diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_atombios.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 812 |
1 files changed, 564 insertions, 248 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index fbdaff55556b..81a0a91921b9 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -23,38 +23,20 @@ * Authors: Dave Airlie * Alex Deucher */ -#include <drm/drmP.h> + +#include <linux/pci.h> + +#include <drm/drm_device.h> +#include <drm/drm_edid.h> #include <drm/radeon_drm.h> + #include "radeon.h" #include "atom.h" #include "atom-bits.h" - -/* from radeon_encoder.c */ -extern uint32_t -radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, - uint8_t dac); -extern void radeon_link_encoder_connector(struct drm_device *dev); -extern void -radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, - uint32_t supported_device, u16 caps); - -/* from radeon_connector.c */ -extern void -radeon_add_atom_connector(struct drm_device *dev, - uint32_t connector_id, - uint32_t supported_device, - int connector_type, - struct radeon_i2c_bus_rec *i2c_bus, - uint32_t igp_lane_info, - uint16_t connector_object_id, - struct radeon_hpd *hpd, - struct radeon_router *router); - -/* from radeon_legacy_encoder.c */ -extern void -radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, - uint32_t supported_device); +#include "radeon_asic.h" +#include "radeon_atombios.h" +#include "radeon_legacy_encoders.h" union atom_supported_devices { struct _ATOM_SUPPORTED_DEVICES_INFO info; @@ -163,8 +145,8 @@ static struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rd num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_I2C_ASSIGMENT); + gpio = &i2c_info->asGPIO_Info[0]; for (i = 0; i < num_indices; i++) { - gpio = &i2c_info->asGPIO_Info[i]; radeon_lookup_i2c_gpio_quirks(rdev, gpio, i); @@ -172,6 +154,8 @@ static struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rd i2c = radeon_get_bus_rec_for_i2c_gpio(gpio); break; } + gpio = (ATOM_GPIO_I2C_ASSIGMENT *) + ((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT)); } } @@ -195,23 +179,24 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_I2C_ASSIGMENT); + gpio = &i2c_info->asGPIO_Info[0]; for (i = 0; i < num_indices; i++) { - gpio = &i2c_info->asGPIO_Info[i]; - radeon_lookup_i2c_gpio_quirks(rdev, gpio, i); i2c = radeon_get_bus_rec_for_i2c_gpio(gpio); if (i2c.valid) { sprintf(stmp, "0x%x", i2c.i2c_id); - rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp); + rdev->i2c_bus[i] = radeon_i2c_create(rdev_to_drm(rdev), &i2c, stmp); } + gpio = (ATOM_GPIO_I2C_ASSIGMENT *) + ((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT)); } } } -static struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev, - u8 id) +struct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev, + u8 id) { struct atom_context *ctx = rdev->mode_info.atom_context; struct radeon_gpio_rec gpio; @@ -230,15 +215,18 @@ static struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev, num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_PIN_ASSIGNMENT); + pin = gpio_info->asGPIO_Pin; 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 = le16_to_cpu(pin->usGpioPin_AIndex) * 4; + gpio.shift = pin->ucGpioPinBitShift; gpio.mask = (1 << pin->ucGpioPinBitShift); gpio.valid = true; break; } + pin = (ATOM_GPIO_PIN_ASSIGNMENT *) + ((u8 *)pin + sizeof(ATOM_GPIO_PIN_ASSIGNMENT)); } } @@ -297,46 +285,47 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, uint16_t *line_mux, struct radeon_hpd *hpd) { + struct pci_dev *pdev = to_pci_dev(dev->dev); /* Asus M2A-VM HDMI board lists the DVI port as HDMI */ - if ((dev->pdev->device == 0x791e) && - (dev->pdev->subsystem_vendor == 0x1043) && - (dev->pdev->subsystem_device == 0x826d)) { + if ((pdev->device == 0x791e) && + (pdev->subsystem_vendor == 0x1043) && + (pdev->subsystem_device == 0x826d)) { if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) && (supported_device == ATOM_DEVICE_DFP3_SUPPORT)) *connector_type = DRM_MODE_CONNECTOR_DVID; } /* Asrock RS600 board lists the DVI port as HDMI */ - if ((dev->pdev->device == 0x7941) && - (dev->pdev->subsystem_vendor == 0x1849) && - (dev->pdev->subsystem_device == 0x7941)) { + if ((pdev->device == 0x7941) && + (pdev->subsystem_vendor == 0x1849) && + (pdev->subsystem_device == 0x7941)) { if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) && (supported_device == ATOM_DEVICE_DFP3_SUPPORT)) *connector_type = DRM_MODE_CONNECTOR_DVID; } /* MSI K9A2GM V2/V3 board has no HDMI or DVI */ - if ((dev->pdev->device == 0x796e) && - (dev->pdev->subsystem_vendor == 0x1462) && - (dev->pdev->subsystem_device == 0x7302)) { + if ((pdev->device == 0x796e) && + (pdev->subsystem_vendor == 0x1462) && + (pdev->subsystem_device == 0x7302)) { if ((supported_device == ATOM_DEVICE_DFP2_SUPPORT) || (supported_device == ATOM_DEVICE_DFP3_SUPPORT)) return false; } /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */ - if ((dev->pdev->device == 0x7941) && - (dev->pdev->subsystem_vendor == 0x147b) && - (dev->pdev->subsystem_device == 0x2412)) { + if ((pdev->device == 0x7941) && + (pdev->subsystem_vendor == 0x147b) && + (pdev->subsystem_device == 0x2412)) { if (*connector_type == DRM_MODE_CONNECTOR_DVII) return false; } /* Falcon NW laptop lists vga ddc line for LVDS */ - if ((dev->pdev->device == 0x5653) && - (dev->pdev->subsystem_vendor == 0x1462) && - (dev->pdev->subsystem_device == 0x0291)) { + if ((pdev->device == 0x5653) && + (pdev->subsystem_vendor == 0x1462) && + (pdev->subsystem_device == 0x0291)) { if (*connector_type == DRM_MODE_CONNECTOR_LVDS) { i2c_bus->valid = false; *line_mux = 53; @@ -344,26 +333,26 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } /* HIS X1300 is DVI+VGA, not DVI+DVI */ - if ((dev->pdev->device == 0x7146) && - (dev->pdev->subsystem_vendor == 0x17af) && - (dev->pdev->subsystem_device == 0x2058)) { + if ((pdev->device == 0x7146) && + (pdev->subsystem_vendor == 0x17af) && + (pdev->subsystem_device == 0x2058)) { if (supported_device == ATOM_DEVICE_DFP1_SUPPORT) return false; } /* Gigabyte X1300 is DVI+VGA, not DVI+DVI */ - if ((dev->pdev->device == 0x7142) && - (dev->pdev->subsystem_vendor == 0x1458) && - (dev->pdev->subsystem_device == 0x2134)) { + if ((pdev->device == 0x7142) && + (pdev->subsystem_vendor == 0x1458) && + (pdev->subsystem_device == 0x2134)) { if (supported_device == ATOM_DEVICE_DFP1_SUPPORT) return false; } /* Funky macbooks */ - if ((dev->pdev->device == 0x71C5) && - (dev->pdev->subsystem_vendor == 0x106b) && - (dev->pdev->subsystem_device == 0x0080)) { + if ((pdev->device == 0x71C5) && + (pdev->subsystem_vendor == 0x106b) && + (pdev->subsystem_device == 0x0080)) { if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) || (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) return false; @@ -379,27 +368,27 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } /* ASUS HD 3600 XT board lists the DVI port as HDMI */ - if ((dev->pdev->device == 0x9598) && - (dev->pdev->subsystem_vendor == 0x1043) && - (dev->pdev->subsystem_device == 0x01da)) { + if ((pdev->device == 0x9598) && + (pdev->subsystem_vendor == 0x1043) && + (pdev->subsystem_device == 0x01da)) { if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) { *connector_type = DRM_MODE_CONNECTOR_DVII; } } /* ASUS HD 3600 board lists the DVI port as HDMI */ - if ((dev->pdev->device == 0x9598) && - (dev->pdev->subsystem_vendor == 0x1043) && - (dev->pdev->subsystem_device == 0x01e4)) { + if ((pdev->device == 0x9598) && + (pdev->subsystem_vendor == 0x1043) && + (pdev->subsystem_device == 0x01e4)) { if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) { *connector_type = DRM_MODE_CONNECTOR_DVII; } } /* ASUS HD 3450 board lists the DVI port as HDMI */ - if ((dev->pdev->device == 0x95C5) && - (dev->pdev->subsystem_vendor == 0x1043) && - (dev->pdev->subsystem_device == 0x01e2)) { + if ((pdev->device == 0x95C5) && + (pdev->subsystem_vendor == 0x1043) && + (pdev->subsystem_device == 0x01e2)) { if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) { *connector_type = DRM_MODE_CONNECTOR_DVII; } @@ -424,9 +413,9 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, * with different crtcs which isn't possible on the hardware * side and leaves no crtcs for LVDS or VGA. */ - if (((dev->pdev->device == 0x95c4) || (dev->pdev->device == 0x9591)) && - (dev->pdev->subsystem_vendor == 0x1025) && - (dev->pdev->subsystem_device == 0x013c)) { + if (((pdev->device == 0x95c4) || (pdev->device == 0x9591)) && + (pdev->subsystem_vendor == 0x1025) && + (pdev->subsystem_device == 0x013c)) { if ((*connector_type == DRM_MODE_CONNECTOR_DVII) && (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) { /* actually it's a DVI-D port not DVI-I */ @@ -438,9 +427,9 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, /* XFX Pine Group device rv730 reports no VGA DDC lines * even though they are wired up to record 0x93 */ - if ((dev->pdev->device == 0x9498) && - (dev->pdev->subsystem_vendor == 0x1682) && - (dev->pdev->subsystem_device == 0x2452) && + if ((pdev->device == 0x9498) && + (pdev->subsystem_vendor == 0x1682) && + (pdev->subsystem_device == 0x2452) && (i2c_bus->valid == false) && !(supported_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))) { struct radeon_device *rdev = dev->dev_private; @@ -448,9 +437,11 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ - if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) && - (dev->pdev->subsystem_vendor == 0x1734) && - (dev->pdev->subsystem_device == 0x11bd)) { + if (((pdev->device == 0x9802) || + (pdev->device == 0x9805) || + (pdev->device == 0x9806)) && + (pdev->subsystem_vendor == 0x1734) && + (pdev->subsystem_device == 0x11bd)) { if (*connector_type == DRM_MODE_CONNECTOR_VGA) { *connector_type = DRM_MODE_CONNECTOR_DVII; *line_mux = 0x3103; @@ -459,11 +450,10 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } - return true; } -const int supported_devices_connector_convert[] = { +static const int supported_devices_connector_convert[] = { DRM_MODE_CONNECTOR_Unknown, DRM_MODE_CONNECTOR_VGA, DRM_MODE_CONNECTOR_DVII, @@ -482,7 +472,7 @@ const int supported_devices_connector_convert[] = { DRM_MODE_CONNECTOR_DisplayPort }; -const uint16_t supported_devices_connector_object_id_convert[] = { +static const uint16_t supported_devices_connector_object_id_convert[] = { CONNECTOR_OBJECT_ID_NONE, CONNECTOR_OBJECT_ID_VGA, CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, /* not all boards support DL */ @@ -499,7 +489,7 @@ const uint16_t supported_devices_connector_object_id_convert[] = { CONNECTOR_OBJECT_ID_SVIDEO }; -const int object_connector_convert[] = { +static const int object_connector_convert[] = { DRM_MODE_CONNECTOR_Unknown, DRM_MODE_CONNECTOR_DVII, DRM_MODE_CONNECTOR_DVII, @@ -575,7 +565,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) path_size += le16_to_cpu(path->usSize); if (device_support & le16_to_cpu(path->usDeviceTag)) { - uint8_t con_obj_id, con_obj_num, con_obj_type; + uint8_t con_obj_id, con_obj_num; con_obj_id = (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) @@ -583,9 +573,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) con_obj_num = (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) >> ENUM_ID_SHIFT; - con_obj_type = - (le16_to_cpu(path->usConnObjectId) & - OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; /* TODO CV support */ if (le16_to_cpu(path->usDeviceTag) == @@ -653,15 +640,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) router.ddc_valid = false; router.cd_valid = false; for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) { - uint8_t grph_obj_id, grph_obj_num, grph_obj_type; - - grph_obj_id = - (le16_to_cpu(path->usGraphicObjIds[j]) & - OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - grph_obj_num = - (le16_to_cpu(path->usGraphicObjIds[j]) & - ENUM_ID_MASK) >> ENUM_ID_SHIFT; - grph_obj_type = + uint8_t grph_obj_type = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; @@ -711,13 +690,16 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) (ctx->bios + data_offset + le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset)); + u8 *num_dst_objs = (u8 *) + ((u8 *)router_src_dst_table + 1 + + (router_src_dst_table->ucNumberOfSrc * 2)); + u16 *dst_objs = (u16 *)(num_dst_objs + 1); int enum_id; router.router_id = router_obj_id; - for (enum_id = 0; enum_id < router_src_dst_table->ucNumberOfDst; - enum_id++) { + for (enum_id = 0; enum_id < (*num_dst_objs); enum_id++) { if (le16_to_cpu(path->usConnObjectId) == - le16_to_cpu(router_src_dst_table->usDstObjectID[enum_id])) + le16_to_cpu(dst_objs[enum_id])) break; } @@ -803,7 +785,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) hpd_record = (ATOM_HPD_INT_RECORD *) record; - gpio = radeon_lookup_gpio(rdev, + gpio = radeon_atombios_lookup_gpio(rdev, hpd_record->ucHPDIntGPIOID); hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio); hpd.plugged_state = hpd_record->ucPlugged_PinState; @@ -845,7 +827,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) } radeon_link_encoder_connector(dev); - return true; } @@ -942,8 +923,12 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct max_device = ATOM_MAX_SUPPORTED_DEVICE_INFO; for (i = 0; i < max_device; i++) { - ATOM_CONNECTOR_INFO_I2C ci = - supported_devices->info.asConnInfo[i]; + ATOM_CONNECTOR_INFO_I2C ci; + + if (frev > 1) + ci = supported_devices->info_2d1.asConnInfo[i]; + else + ci = supported_devices->info.asConnInfo[i]; bios_connectors[i].valid = false; @@ -1112,6 +1097,31 @@ union firmware_info { ATOM_FIRMWARE_INFO_V2_2 info_22; }; +union igp_info { + struct _ATOM_INTEGRATED_SYSTEM_INFO info; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; +}; + +static void radeon_atombios_get_dentist_vco_freq(struct radeon_device *rdev) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); + union igp_info *igp_info; + u8 frev, crev; + u16 data_offset; + + 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); + rdev->clock.vco_freq = + le32_to_cpu(igp_info->info_6.ulDentistVCOFreq); + } +} + bool radeon_atom_get_clock_info(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; @@ -1136,7 +1146,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) le16_to_cpu(firmware_info->info.usReferenceClock); p1pll->reference_div = 0; - if (crev < 2) + if ((frev < 2) && (crev < 2)) p1pll->pll_out_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); else @@ -1145,7 +1155,7 @@ 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) { + if (((frev < 2) && (crev >= 4)) || (frev >= 2)) { p1pll->lcd_pll_out_min = le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100; if (p1pll->lcd_pll_out_min == 0) @@ -1236,11 +1246,19 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) rdev->clock.default_dispclk = le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq); if (rdev->clock.default_dispclk == 0) { - if (ASIC_IS_DCE5(rdev)) + if (ASIC_IS_DCE6(rdev)) + rdev->clock.default_dispclk = 60000; /* 600 Mhz */ + else if (ASIC_IS_DCE5(rdev)) rdev->clock.default_dispclk = 54000; /* 540 Mhz */ else rdev->clock.default_dispclk = 60000; /* 600 Mhz */ } + /* set a reasonable default for DP */ + if (ASIC_IS_DCE6(rdev) && (rdev->clock.default_dispclk < 53900)) { + DRM_INFO("Changing default dispclk from %dMhz to 600Mhz\n", + rdev->clock.default_dispclk / 100); + rdev->clock.default_dispclk = 60000; + } rdev->clock.dp_extclk = le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq); rdev->clock.current_dispclk = rdev->clock.default_dispclk; @@ -1255,20 +1273,25 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) rdev->mode_info.firmware_flags = le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess); + if (ASIC_IS_DCE8(rdev)) + rdev->clock.vco_freq = + le32_to_cpu(firmware_info->info_22.ulGPUPLL_OutputFreq); + else if (ASIC_IS_DCE5(rdev)) + rdev->clock.vco_freq = rdev->clock.current_dispclk; + else if (ASIC_IS_DCE41(rdev)) + radeon_atombios_get_dentist_vco_freq(rdev); + else + rdev->clock.vco_freq = rdev->clock.current_dispclk; + + if (rdev->clock.vco_freq == 0) + rdev->clock.vco_freq = 360000; /* 3.6 GHz */ + return true; } return false; } -union igp_info { - struct _ATOM_INTEGRATED_SYSTEM_INFO info; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; -}; - bool radeon_atombios_sideport_present(struct radeon_device *rdev) { struct radeon_mode_info *mode_info = &rdev->mode_info; @@ -1359,6 +1382,7 @@ bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev, int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info); uint16_t data_offset, size; struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info; + struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT *ss_assign; uint8_t frev, crev; int i, num_indices; @@ -1370,18 +1394,21 @@ bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev, num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT); - + ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT *) + ((u8 *)&ss_info->asSS_Info[0]); for (i = 0; i < num_indices; i++) { - if (ss_info->asSS_Info[i].ucSS_Id == id) { + if (ss_assign->ucSS_Id == id) { ss->percentage = - le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage); - ss->type = ss_info->asSS_Info[i].ucSpreadSpectrumType; - ss->step = ss_info->asSS_Info[i].ucSS_Step; - ss->delay = ss_info->asSS_Info[i].ucSS_Delay; - ss->range = ss_info->asSS_Info[i].ucSS_Range; - ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div; + le16_to_cpu(ss_assign->usSpreadSpectrumPercentage); + ss->type = ss_assign->ucSpreadSpectrumType; + ss->step = ss_assign->ucSS_Step; + ss->delay = ss_assign->ucSS_Delay; + ss->range = ss_assign->ucSS_Range; + ss->refdiv = ss_assign->ucRecommendedRef_Div; return true; } + ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT *) + ((u8 *)ss_assign + sizeof(struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT)); } } return false; @@ -1469,6 +1496,12 @@ union asic_ss_info { struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3; }; +union asic_ss_assignment { + struct _ATOM_ASIC_SS_ASSIGNMENT v1; + struct _ATOM_ASIC_SS_ASSIGNMENT_V2 v2; + struct _ATOM_ASIC_SS_ASSIGNMENT_V3 v3; +}; + bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, struct radeon_atom_ss *ss, int id, u32 clock) @@ -1477,9 +1510,19 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); uint16_t data_offset, size; union asic_ss_info *ss_info; + union asic_ss_assignment *ss_assign; uint8_t frev, crev; int i, num_indices; + if (id == ASIC_INTERNAL_MEMORY_SS) { + if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT)) + return false; + } + if (id == ASIC_INTERNAL_ENGINE_SS) { + if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT)) + return false; + } + memset(ss, 0, sizeof(struct radeon_atom_ss)); if (atom_parse_data_header(mode_info->atom_context, index, &size, &frev, &crev, &data_offset)) { @@ -1492,45 +1535,59 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_ASIC_SS_ASSIGNMENT); + ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info.asSpreadSpectrum[0]); for (i = 0; i < num_indices; i++) { - if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) && - (clock <= le32_to_cpu(ss_info->info.asSpreadSpectrum[i].ulTargetClockRange))) { + if ((ss_assign->v1.ucClockIndication == id) && + (clock <= le32_to_cpu(ss_assign->v1.ulTargetClockRange))) { ss->percentage = - le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage); - ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode; - ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz); + le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage); + ss->type = ss_assign->v1.ucSpreadSpectrumMode; + ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz); + ss->percentage_divider = 100; return true; } + ss_assign = (union asic_ss_assignment *) + ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT)); } break; case 2: num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2); + ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_2.asSpreadSpectrum[0]); for (i = 0; i < num_indices; i++) { - if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) && - (clock <= le32_to_cpu(ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange))) { + if ((ss_assign->v2.ucClockIndication == id) && + (clock <= le32_to_cpu(ss_assign->v2.ulTargetClockRange))) { ss->percentage = - le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage); - ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode; - ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz); + le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage); + ss->type = ss_assign->v2.ucSpreadSpectrumMode; + ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz); + ss->percentage_divider = 100; if ((crev == 2) && ((id == ASIC_INTERNAL_ENGINE_SS) || (id == ASIC_INTERNAL_MEMORY_SS))) ss->rate /= 100; return true; } + ss_assign = (union asic_ss_assignment *) + ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2)); } break; case 3: num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3); + ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_3.asSpreadSpectrum[0]); for (i = 0; i < num_indices; i++) { - if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) && - (clock <= le32_to_cpu(ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange))) { + if ((ss_assign->v3.ucClockIndication == id) && + (clock <= le32_to_cpu(ss_assign->v3.ulTargetClockRange))) { ss->percentage = - le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage); - ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode; - ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz); + le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage); + ss->type = ss_assign->v3.ucSpreadSpectrumMode; + ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz); + if (ss_assign->v3.ucSpreadSpectrumMode & + SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK) + ss->percentage_divider = 1000; + else + ss->percentage_divider = 100; if ((id == ASIC_INTERNAL_ENGINE_SS) || (id == ASIC_INTERNAL_MEMORY_SS)) ss->rate /= 100; @@ -1538,6 +1595,8 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, radeon_atombios_get_igp_ss_overrides(rdev, ss, id); return true; } + ss_assign = (union asic_ss_assignment *) + ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3)); } break; default: @@ -1657,22 +1716,25 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct case LCD_FAKE_EDID_PATCH_RECORD_TYPE: fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; if (fake_edid_record->ucFakeEDIDLength) { - struct edid *edid; - int edid_size = - max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength); - edid = kmalloc(edid_size, GFP_KERNEL); - if (edid) { - memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], - fake_edid_record->ucFakeEDIDLength); - - if (drm_edid_is_valid(edid)) { - rdev->mode_info.bios_hardcoded_edid = edid; - rdev->mode_info.bios_hardcoded_edid_size = edid_size; - } else - kfree(edid); - } + const struct drm_edid *edid; + int edid_size; + + if (fake_edid_record->ucFakeEDIDLength == 128) + edid_size = fake_edid_record->ucFakeEDIDLength; + else + edid_size = fake_edid_record->ucFakeEDIDLength * 128; + edid = drm_edid_alloc(fake_edid_record->ucFakeEDIDString, edid_size); + if (drm_edid_valid(edid)) + rdev->mode_info.bios_hardcoded_edid = edid; + else + drm_edid_free(edid); + record += struct_size(fake_edid_record, + ucFakeEDIDString, + edid_size); + } else { + /* empty fake edid record must be 3 bytes long */ + record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; } - record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD); break; case LCD_PANEL_RESOLUTION_RECORD_TYPE: panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; @@ -1770,7 +1832,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, if (misc & ATOM_DOUBLE_CLOCK_MODE) mode->flags |= DRM_MODE_FLAG_DBLSCAN; - mode->clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10; + mode->crtc_clock = mode->clock = + le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10; if (index == 1) { /* PAL timings appear to have wrong values for totals */ @@ -1813,7 +1876,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, if (misc & ATOM_DOUBLE_CLOCK_MODE) mode->flags |= DRM_MODE_FLAG_DBLSCAN; - mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10; + mode->crtc_clock = mode->clock = + le16_to_cpu(dtd_timings->usPixClk) * 10; break; } return true; @@ -1924,7 +1988,7 @@ static const char *thermal_controller_names[] = { "adm1032", "adm1030", "max6649", - "lm64", + "lm63", /* lm64 */ "f75375", "asc7xxx", }; @@ -1935,7 +1999,7 @@ static const char *pp_lib_thermal_controller_names[] = { "adm1032", "adm1030", "max6649", - "lm64", + "lm63", /* lm64 */ "f75375", "RV6xx", "RV770", @@ -2023,7 +2087,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) struct radeon_i2c_bus_rec i2c_bus; union power_info *power_info; int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); - u16 data_offset; + u16 data_offset; u8 frev, crev; if (!atom_parse_data_header(mode_info->atom_context, index, NULL, @@ -2044,8 +2108,8 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) const char *name = thermal_controller_names[power_info->info. ucOverdriveThermalController]; info.addr = power_info->info.ucOverdriveControllerAddress >> 1; - strlcpy(info.type, name, sizeof(info.type)); - i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); + strscpy(info.type, name, sizeof(info.type)); + i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); } } num_modes = power_info->info.ucNumOfPowerModeEntries; @@ -2053,15 +2117,21 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; if (num_modes == 0) return state_index; - rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL); + rdev->pm.power_state = kcalloc(num_modes, + sizeof(struct radeon_power_state), + GFP_KERNEL); if (!rdev->pm.power_state) return state_index; /* last mode is usually default, array is low to high */ for (i = 0; i < num_modes; i++) { - rdev->pm.power_state[state_index].clock_info = - kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + /* avoid memory leaks from invalid modes or unknown frev. */ + if (!rdev->pm.power_state[state_index].clock_info) { + rdev->pm.power_state[state_index].clock_info = + kzalloc(sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); + } if (!rdev->pm.power_state[state_index].clock_info) - return state_index; + goto out; rdev->pm.power_state[state_index].num_clock_modes = 1; rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; switch (frev) { @@ -2082,7 +2152,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = - radeon_lookup_gpio(rdev, + radeon_atombios_lookup_gpio(rdev, power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = @@ -2118,7 +2188,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = - radeon_lookup_gpio(rdev, + radeon_atombios_lookup_gpio(rdev, power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex); if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = @@ -2154,7 +2224,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = - radeon_lookup_gpio(rdev, + radeon_atombios_lookup_gpio(rdev, power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex); if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = @@ -2180,17 +2250,24 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) break; } } +out: + /* free any unused clock_info allocation. */ + if (state_index && state_index < num_modes) { + kfree(rdev->pm.power_state[state_index].clock_info); + rdev->pm.power_state[state_index].clock_info = NULL; + } + /* last mode is usually default */ - if (rdev->pm.default_power_state_index == -1) { + if (state_index && rdev->pm.default_power_state_index == -1) { rdev->pm.power_state[state_index - 1].type = POWER_STATE_TYPE_DEFAULT; rdev->pm.default_power_state_index = state_index - 1; rdev->pm.power_state[state_index - 1].default_clock_mode = &rdev->pm.power_state[state_index - 1].clock_info[0]; - rdev->pm.power_state[state_index].flags &= + rdev->pm.power_state[state_index - 1].flags &= ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; - rdev->pm.power_state[state_index].misc = 0; - rdev->pm.power_state[state_index].misc2 = 0; + rdev->pm.power_state[state_index - 1].misc = 0; + rdev->pm.power_state[state_index - 1].misc2 = 0; } return state_index; } @@ -2202,6 +2279,14 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r /* add the i2c bus for thermal/fan chip */ if (controller->ucType > 0) { + if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) + rdev->pm.no_fan = true; + rdev->pm.fan_pulses_per_revolution = + controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; + if (rdev->pm.fan_pulses_per_revolution) { + rdev->pm.fan_min_rpm = controller->ucFanMinRPM; + rdev->pm.fan_max_rpm = controller->ucFanMaxRPM; + } if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { DRM_INFO("Internal thermal controller %s fan control\n", (controller->ucFanParameters & @@ -2237,27 +2322,44 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); rdev->pm.int_thermal_type = THERMAL_TYPE_CI; - } else if ((controller->ucType == - ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || - (controller->ucType == - ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) || - (controller->ucType == - ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) { - DRM_INFO("Special thermal controller config\n"); + } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) { + DRM_INFO("Internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_KV; + } else if (controller->ucType == + ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) { + DRM_INFO("External GPIO thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO; + } else if (controller->ucType == + ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) { + DRM_INFO("ADT7473 with internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL; + } else if (controller->ucType == + ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) { + DRM_INFO("EMC2103 with internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL; } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) { DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", pp_lib_thermal_controller_names[controller->ucType], controller->ucI2cAddress >> 1, (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL; i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); if (rdev->pm.i2c_bus) { struct i2c_board_info info = { }; const char *name = pp_lib_thermal_controller_names[controller->ucType]; info.addr = controller->ucI2cAddress >> 1; - strlcpy(info.type, name, sizeof(info.type)); - i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); + strscpy(info.type, name, sizeof(info.type)); + i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); } } else { DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n", @@ -2478,7 +2580,7 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) bool valid; union power_info *power_info; int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); - u16 data_offset; + u16 data_offset; u8 frev, crev; if (!atom_parse_data_header(mode_info->atom_context, index, NULL, @@ -2489,8 +2591,9 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); if (power_info->pplib.ucNumStates == 0) return state_index; - rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * - power_info->pplib.ucNumStates, GFP_KERNEL); + rdev->pm.power_state = kcalloc(power_info->pplib.ucNumStates, + sizeof(struct radeon_power_state), + GFP_KERNEL); if (!rdev->pm.power_state) return state_index; /* first mode is usually default, followed by low to high */ @@ -2505,10 +2608,11 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + (power_state->v1.ucNonClockStateIndex * power_info->pplib.ucNonClockSize)); - rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * - ((power_info->pplib.ucStateEntrySize - 1) ? - (power_info->pplib.ucStateEntrySize - 1) : 1), - GFP_KERNEL); + rdev->pm.power_state[i].clock_info = + kcalloc((power_info->pplib.ucStateEntrySize - 1) ? + (power_info->pplib.ucStateEntrySize - 1) : 1, + sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); if (!rdev->pm.power_state[i].clock_info) return state_index; if (power_info->pplib.ucStateEntrySize - 1) { @@ -2569,7 +2673,7 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) bool valid; union power_info *power_info; int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); - u16 data_offset; + u16 data_offset; u8 frev, crev; u8 *power_state_offset; @@ -2590,8 +2694,9 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); if (state_array->ucNumEntries == 0) return state_index; - rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * - state_array->ucNumEntries, GFP_KERNEL); + rdev->pm.power_state = kcalloc(state_array->ucNumEntries, + sizeof(struct radeon_power_state), + GFP_KERNEL); if (!rdev->pm.power_state) return state_index; power_state_offset = (u8 *)state_array->states; @@ -2601,10 +2706,11 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; - rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * - (power_state->v2.ucNumDPMLevels ? - power_state->v2.ucNumDPMLevels : 1), - GFP_KERNEL); + rdev->pm.power_state[i].clock_info = + kcalloc(power_state->v2.ucNumDPMLevels ? + power_state->v2.ucNumDPMLevels : 1, + sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); if (!rdev->pm.power_state[i].clock_info) return state_index; if (power_state->v2.ucNumDPMLevels) { @@ -2684,7 +2790,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL); if (rdev->pm.power_state) { rdev->pm.power_state[0].clock_info = - kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + kcalloc(1, + sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); if (rdev->pm.power_state[0].clock_info) { /* add the default mode */ rdev->pm.power_state[state_index].type = @@ -2746,7 +2854,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev, args.v1.ucAction = clock_type; args.v1.ulClock = cpu_to_le32(clock); /* 10 khz */ - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); dividers->post_div = args.v1.ucPostDiv; dividers->fb_div = args.v1.ucFbDiv; @@ -2760,7 +2868,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev, args.v2.ucAction = clock_type; args.v2.ulClock = cpu_to_le32(clock); /* 10 khz */ - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); dividers->post_div = args.v2.ucPostDiv; dividers->fb_div = le16_to_cpu(args.v2.usFbDiv); @@ -2775,14 +2883,14 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev, if (clock_type == COMPUTE_ENGINE_PLL_PARAM) { args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); dividers->post_div = args.v3.ucPostDiv; dividers->enable_post_div = (args.v3.ucCntlFlag & ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false; dividers->enable_dithen = (args.v3.ucCntlFlag & ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true; - dividers->fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv); + dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv); dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac); dividers->ref_div = args.v3.ucRefDiv; dividers->vco_mode = (args.v3.ucCntlFlag & @@ -2795,7 +2903,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev, if (strobe_mode) args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); dividers->post_div = args.v5.ucPostDiv; dividers->enable_post_div = (args.v5.ucCntlFlag & @@ -2814,7 +2922,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev, /* fusion */ args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */ - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); dividers->post_divider = dividers->post_div = args.v4.ucPostDiv; dividers->real_clock = le32_to_cpu(args.v4.ulClock); @@ -2825,7 +2933,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev, args.v6_in.ulClock.ulComputeClockFlag = clock_type; args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */ - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv); dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac); @@ -2866,7 +2974,7 @@ int radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev, if (strobe_mode) args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac); mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv); @@ -2874,7 +2982,7 @@ int radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev, mpll_param->dll_speed = args.ucDllSpeed; mpll_param->bwcntl = args.ucBWCntl; mpll_param->vco_mode = - (args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK) ? 1 : 0; + (args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK); mpll_param->yclk_sel = (args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0; mpll_param->qdr = @@ -2899,7 +3007,7 @@ void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) args.ucEnable = enable; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev) @@ -2907,7 +3015,7 @@ uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev) GET_ENGINE_CLOCK_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); return le32_to_cpu(args.ulReturnEngineClock); } @@ -2916,7 +3024,7 @@ uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev) GET_MEMORY_CLOCK_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); return le32_to_cpu(args.ulReturnMemoryClock); } @@ -2928,7 +3036,7 @@ void radeon_atom_set_engine_clock(struct radeon_device *rdev, args.ulTargetEngineClock = cpu_to_le32(eng_clock); /* 10 khz */ - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void radeon_atom_set_memory_clock(struct radeon_device *rdev, @@ -2942,7 +3050,7 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev, args.ulTargetMemoryClock = cpu_to_le32(mem_clock); /* 10 khz */ - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev, @@ -2961,7 +3069,7 @@ void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev, if (mem_clock) args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void radeon_atom_update_memory_dll(struct radeon_device *rdev, @@ -2972,7 +3080,7 @@ void radeon_atom_update_memory_dll(struct radeon_device *rdev, args = cpu_to_le32(mem_clock); /* 10 khz */ - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } void radeon_atom_set_ac_timing(struct radeon_device *rdev, @@ -2984,7 +3092,7 @@ void radeon_atom_set_ac_timing(struct radeon_device *rdev, args.ulTargetMemoryClock = cpu_to_le32(tmp); /* 10 khz */ - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } union set_voltage { @@ -3028,7 +3136,7 @@ void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 v return; } - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); } int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, @@ -3049,7 +3157,7 @@ int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, args.v2.ucVoltageMode = 0; args.v2.usVoltageLevel = 0; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); *voltage = le16_to_cpu(args.v2.usVoltageLevel); break; @@ -3058,7 +3166,7 @@ int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL; args.v3.usVoltageLevel = cpu_to_le16(voltage_id); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); *voltage = le16_to_cpu(args.v3.usVoltageLevel); break; @@ -3077,6 +3185,157 @@ int radeon_atom_get_leakage_vddc_based_on_leakage_idx(struct radeon_device *rdev return radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage); } +int radeon_atom_get_leakage_id_from_vbios(struct radeon_device *rdev, + u16 *leakage_id) +{ + union set_voltage args; + int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); + u8 frev, crev; + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return -EINVAL; + + switch (crev) { + case 3: + case 4: + args.v3.ucVoltageType = 0; + args.v3.ucVoltageMode = ATOM_GET_LEAKAGE_ID; + args.v3.usVoltageLevel = 0; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); + + *leakage_id = le16_to_cpu(args.v3.usVoltageLevel); + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + return -EINVAL; + } + + return 0; +} + +int radeon_atom_get_leakage_vddc_based_on_leakage_params(struct radeon_device *rdev, + u16 *vddc, u16 *vddci, + u16 virtual_voltage_id, + u16 vbios_voltage_id) +{ + int index = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo); + u8 frev, crev; + u16 data_offset, size; + int i, j; + ATOM_ASIC_PROFILING_INFO_V2_1 *profile; + u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf; + + *vddc = 0; + *vddci = 0; + + if (!atom_parse_data_header(rdev->mode_info.atom_context, index, &size, + &frev, &crev, &data_offset)) + return -EINVAL; + + profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *) + (rdev->mode_info.atom_context->bios + data_offset); + + switch (frev) { + case 1: + return -EINVAL; + case 2: + switch (crev) { + case 1: + if (size < sizeof(ATOM_ASIC_PROFILING_INFO_V2_1)) + return -EINVAL; + leakage_bin = (u16 *) + (rdev->mode_info.atom_context->bios + data_offset + + le16_to_cpu(profile->usLeakageBinArrayOffset)); + vddc_id_buf = (u16 *) + (rdev->mode_info.atom_context->bios + data_offset + + le16_to_cpu(profile->usElbVDDC_IdArrayOffset)); + vddc_buf = (u16 *) + (rdev->mode_info.atom_context->bios + data_offset + + le16_to_cpu(profile->usElbVDDC_LevelArrayOffset)); + vddci_id_buf = (u16 *) + (rdev->mode_info.atom_context->bios + data_offset + + le16_to_cpu(profile->usElbVDDCI_IdArrayOffset)); + vddci_buf = (u16 *) + (rdev->mode_info.atom_context->bios + data_offset + + le16_to_cpu(profile->usElbVDDCI_LevelArrayOffset)); + + if (profile->ucElbVDDC_Num > 0) { + for (i = 0; i < profile->ucElbVDDC_Num; i++) { + if (vddc_id_buf[i] == virtual_voltage_id) { + for (j = 0; j < profile->ucLeakageBinNum; j++) { + if (vbios_voltage_id <= leakage_bin[j]) { + *vddc = vddc_buf[j * profile->ucElbVDDC_Num + i]; + break; + } + } + break; + } + } + } + if (profile->ucElbVDDCI_Num > 0) { + for (i = 0; i < profile->ucElbVDDCI_Num; i++) { + if (vddci_id_buf[i] == virtual_voltage_id) { + for (j = 0; j < profile->ucLeakageBinNum; j++) { + if (vbios_voltage_id <= leakage_bin[j]) { + *vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i]; + break; + } + } + break; + } + } + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + return -EINVAL; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + return -EINVAL; + } + + return 0; +} + +union get_voltage_info { + struct _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 in; + struct _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 evv_out; +}; + +int radeon_atom_get_voltage_evv(struct radeon_device *rdev, + u16 virtual_voltage_id, + u16 *voltage) +{ + int index = GetIndexIntoMasterTable(COMMAND, GetVoltageInfo); + u32 entry_id; + u32 count = rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; + union get_voltage_info args; + + for (entry_id = 0; entry_id < count; entry_id++) { + if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].v == + virtual_voltage_id) + break; + } + + if (entry_id >= count) + return -EINVAL; + + args.in.ucVoltageType = VOLTAGE_TYPE_VDDC; + args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE; + args.in.usVoltageLevel = cpu_to_le16(virtual_voltage_id); + args.in.ulSCLKFreq = + cpu_to_le32(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); + + *voltage = le16_to_cpu(args.evv_out.usVoltageLevel); + + return 0; +} + int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type, u32 *gpio_value, u32 *gpio_mask) @@ -3096,7 +3355,7 @@ int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev, args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK; args.v2.usVoltageLevel = cpu_to_le16(voltage_level); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); *gpio_mask = le32_to_cpu(*(u32 *)&args.v2); @@ -3104,7 +3363,7 @@ int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev, args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL; args.v2.usVoltageLevel = cpu_to_le16(voltage_level); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args, sizeof(args)); *gpio_value = le32_to_cpu(*(u32 *)&args.v2); break; @@ -3150,7 +3409,7 @@ static ATOM_VOLTAGE_OBJECT_V2 *atom_lookup_voltage_object_v2(ATOM_VOLTAGE_OBJECT { u32 size = le16_to_cpu(v2->sHeader.usStructureSize); u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V2, asVoltageObj[0]); - u8 *start = (u8*)v2; + u8 *start = (u8 *)v2; while (offset < size) { ATOM_VOLTAGE_OBJECT_V2 *vo = (ATOM_VOLTAGE_OBJECT_V2 *)(start + offset); @@ -3167,7 +3426,7 @@ static ATOM_VOLTAGE_OBJECT_V3 *atom_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT { u32 size = le16_to_cpu(v3->sHeader.usStructureSize); u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]); - u8 *start = (u8*)v3; + u8 *start = (u8 *)v3; while (offset < size) { ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset); @@ -3238,6 +3497,50 @@ radeon_atom_is_voltage_gpio(struct radeon_device *rdev, return false; } +int radeon_atom_get_svi2_info(struct radeon_device *rdev, + u8 voltage_type, + u8 *svd_gpio_id, u8 *svc_gpio_id) +{ + int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); + u8 frev, crev; + u16 data_offset, size; + union voltage_object_info *voltage_info; + union voltage_object *voltage_object = NULL; + + if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, + &frev, &crev, &data_offset)) { + voltage_info = (union voltage_object_info *) + (rdev->mode_info.atom_context->bios + data_offset); + + switch (frev) { + case 3: + switch (crev) { + case 1: + voltage_object = (union voltage_object *) + atom_lookup_voltage_object_v3(&voltage_info->v3, + voltage_type, + VOLTAGE_OBJ_SVID2); + if (voltage_object) { + *svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId; + *svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId; + } else { + return -EINVAL; + } + break; + default: + DRM_ERROR("unknown voltage object table\n"); + return -EINVAL; + } + break; + default: + DRM_ERROR("unknown voltage object table\n"); + return -EINVAL; + } + + } + return 0; +} + int radeon_atom_get_max_voltage(struct radeon_device *rdev, u8 voltage_type, u16 *max_voltage) { @@ -3279,10 +3582,11 @@ int radeon_atom_get_max_voltage(struct radeon_device *rdev, ATOM_VOLTAGE_FORMULA_V2 *formula = &voltage_object->v2.asFormula; if (formula->ucNumOfVoltageEntries) { + VOLTAGE_LUT_ENTRY *lut = (VOLTAGE_LUT_ENTRY *) + ((u8 *)&formula->asVIDAdjustEntries[0] + + (sizeof(VOLTAGE_LUT_ENTRY) * (formula->ucNumOfVoltageEntries - 1))); *max_voltage = - le16_to_cpu(formula->asVIDAdjustEntries[ - formula->ucNumOfVoltageEntries - 1 - ].usVoltageValue); + le16_to_cpu(lut->usVoltageValue); return 0; } } @@ -3442,11 +3746,13 @@ int radeon_atom_get_voltage_table(struct radeon_device *rdev, if (voltage_object) { ATOM_VOLTAGE_FORMULA_V2 *formula = &voltage_object->v2.asFormula; + VOLTAGE_LUT_ENTRY *lut; if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES) return -EINVAL; + lut = &formula->asVIDAdjustEntries[0]; for (i = 0; i < formula->ucNumOfVoltageEntries; i++) { voltage_table->entries[i].value = - le16_to_cpu(formula->asVIDAdjustEntries[i].usVoltageValue); + le16_to_cpu(lut->usVoltageValue); ret = radeon_atom_get_voltage_gpio_settings(rdev, voltage_table->entries[i].value, voltage_type, @@ -3454,6 +3760,8 @@ int radeon_atom_get_voltage_table(struct radeon_device *rdev, &voltage_table->mask_low); if (ret) return ret; + lut = (VOLTAGE_LUT_ENTRY *) + ((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY)); } voltage_table->count = formula->ucNumOfVoltageEntries; return 0; @@ -3473,13 +3781,17 @@ int radeon_atom_get_voltage_table(struct radeon_device *rdev, if (voltage_object) { ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio = &voltage_object->v3.asGpioVoltageObj; + VOLTAGE_LUT_ENTRY_V2 *lut; if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES) return -EINVAL; + lut = &gpio->asVolGpioLut[0]; for (i = 0; i < gpio->ucGpioEntryNum; i++) { voltage_table->entries[i].value = - le16_to_cpu(gpio->asVolGpioLut[i].usVoltageValue); + le16_to_cpu(lut->usVoltageValue); voltage_table->entries[i].smio_low = - le32_to_cpu(gpio->asVolGpioLut[i].ulVoltageId); + le32_to_cpu(lut->ulVoltageId); + lut = (VOLTAGE_LUT_ENTRY_V2 *) + ((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY_V2)); } voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal); voltage_table->count = gpio->ucGpioEntryNum; @@ -3513,7 +3825,6 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, u8 frev, crev, i; u16 data_offset, size; union vram_info *vram_info; - u8 *p; memset(mem_info, 0, sizeof(struct atom_memory_info)); @@ -3529,13 +3840,12 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, if (module_index < vram_info->v1_3.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V3 *vram_module = (ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo; - p = (u8 *)vram_info->v1_3.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V3 *)p; if (le16_to_cpu(vram_module->usSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usSize); + vram_module = (ATOM_VRAM_MODULE_V3 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usSize)); } mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf; mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0; @@ -3547,13 +3857,12 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, if (module_index < vram_info->v1_4.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V4 *vram_module = (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; - p = (u8 *)vram_info->v1_4.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V4 *)p; if (le16_to_cpu(vram_module->usModuleSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usModuleSize); + vram_module = (ATOM_VRAM_MODULE_V4 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); } mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; mem_info->mem_type = vram_module->ucMemoryType & 0xf0; @@ -3572,13 +3881,12 @@ int radeon_atom_get_memory_info(struct radeon_device *rdev, if (module_index < vram_info->v2_1.ucNumOfVRAMModule) { ATOM_VRAM_MODULE_V7 *vram_module = (ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo; - p = (u8 *)vram_info->v2_1.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V7 *)p; if (le16_to_cpu(vram_module->usModuleSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usModuleSize); + vram_module = (ATOM_VRAM_MODULE_V7 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); } mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; mem_info->mem_type = vram_module->ucMemoryType & 0xf0; @@ -3609,7 +3917,6 @@ int radeon_atom_get_mclk_range_table(struct radeon_device *rdev, union vram_info *vram_info; u32 mem_timing_size = gddr5 ? sizeof(ATOM_MEMORY_TIMING_FORMAT_V2) : sizeof(ATOM_MEMORY_TIMING_FORMAT); - u8 *p; memset(mclk_range_table, 0, sizeof(struct atom_memory_clock_range_table)); @@ -3629,22 +3936,21 @@ int radeon_atom_get_mclk_range_table(struct radeon_device *rdev, ATOM_VRAM_MODULE_V4 *vram_module = (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; ATOM_MEMORY_TIMING_FORMAT *format; - p = (u8 *)vram_info->v1_4.aVramInfo; for (i = 0; i < module_index; i++) { - vram_module = (ATOM_VRAM_MODULE_V4 *)p; if (le16_to_cpu(vram_module->usModuleSize) == 0) return -EINVAL; - p += le16_to_cpu(vram_module->usModuleSize); + vram_module = (ATOM_VRAM_MODULE_V4 *) + ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); } mclk_range_table->num_entries = (u8) - ((vram_module->usModuleSize - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) / + ((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) / mem_timing_size); - p = (u8 *)vram_module->asMemTiming; + format = &vram_module->asMemTiming[0]; for (i = 0; i < mclk_range_table->num_entries; i++) { - format = (ATOM_MEMORY_TIMING_FORMAT *)p; mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange); - p += mem_timing_size; + format = (ATOM_MEMORY_TIMING_FORMAT *) + ((u8 *)format + mem_timing_size); } } else return -EINVAL; @@ -3705,29 +4011,35 @@ int radeon_atom_init_mc_reg_table(struct radeon_device *rdev, (ATOM_MEMORY_SETTING_DATA_BLOCK *) ((u8 *)reg_block + (2 * sizeof(u16)) + le16_to_cpu(reg_block->usRegIndexTblSize)); + ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0]; num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) / sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1; if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE) return -EINVAL; - while (!(reg_block->asRegIndexBuf[i].ucPreRegDataLength & ACCESS_PLACEHOLDER) && - (i < num_entries)) { + while (i < num_entries) { + if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER) + break; reg_table->mc_reg_address[i].s1 = - (u16)(le16_to_cpu(reg_block->asRegIndexBuf[i].usRegIndex)); + (u16)(le16_to_cpu(format->usRegIndex)); reg_table->mc_reg_address[i].pre_reg_data = - (u8)(reg_block->asRegIndexBuf[i].ucPreRegDataLength); + (u8)(format->ucPreRegDataLength); i++; + format = (ATOM_INIT_REG_INDEX_FORMAT *) + ((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT)); } reg_table->last = i; - while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) && + while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) && (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) { - t_mem_id = (u8)((*(u32 *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT); + t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK) + >> MEM_ID_SHIFT); if (module_index == t_mem_id) { reg_table->mc_reg_table_entry[num_ranges].mclk_max = - (u32)((*(u32 *)reg_data & CLOCK_RANGE_MASK) >> CLOCK_RANGE_SHIFT); + (u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK) + >> CLOCK_RANGE_SHIFT); for (i = 0, j = 1; i < reg_table->last; i++) { if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) { reg_table->mc_reg_table_entry[num_ranges].mc_data[i] = - (u32)*((u32 *)reg_data + j); + (u32)le32_to_cpu(*((u32 *)reg_data + j)); j++; } else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) { reg_table->mc_reg_table_entry[num_ranges].mc_data[i] = @@ -3739,7 +4051,7 @@ int radeon_atom_init_mc_reg_table(struct radeon_device *rdev, reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *) ((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)); } - if (*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) + if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) return -EINVAL; reg_table->num_entries = num_ranges; } else @@ -3778,6 +4090,10 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) /* tell the bios not to handle mode switching */ bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH; + /* clear the vbios dpms state */ + if (ASIC_IS_DCE4(rdev)) + bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE; + if (rdev->family >= CHIP_R600) { WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); |
