18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 138c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 198c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 208c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 218c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Authors: Dave Airlie 248c2ecf20Sopenharmony_ci * Alex Deucher 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/pci.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <drm/drm_device.h> 308c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "radeon.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "atom.h" 358c2ecf20Sopenharmony_ci#include "atom-bits.h" 368c2ecf20Sopenharmony_ci#include "radeon_asic.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciextern void 398c2ecf20Sopenharmony_ciradeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, 408c2ecf20Sopenharmony_ci uint32_t supported_device, u16 caps); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* from radeon_legacy_encoder.c */ 438c2ecf20Sopenharmony_ciextern void 448c2ecf20Sopenharmony_ciradeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, 458c2ecf20Sopenharmony_ci uint32_t supported_device); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ciunion atom_supported_devices { 488c2ecf20Sopenharmony_ci struct _ATOM_SUPPORTED_DEVICES_INFO info; 498c2ecf20Sopenharmony_ci struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2; 508c2ecf20Sopenharmony_ci struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic void radeon_lookup_i2c_gpio_quirks(struct radeon_device *rdev, 548c2ecf20Sopenharmony_ci ATOM_GPIO_I2C_ASSIGMENT *gpio, 558c2ecf20Sopenharmony_ci u8 index) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci /* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */ 588c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_R420) || 598c2ecf20Sopenharmony_ci (rdev->family == CHIP_R423) || 608c2ecf20Sopenharmony_ci (rdev->family == CHIP_RV410)) { 618c2ecf20Sopenharmony_ci if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) || 628c2ecf20Sopenharmony_ci (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) || 638c2ecf20Sopenharmony_ci (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) { 648c2ecf20Sopenharmony_ci gpio->ucClkMaskShift = 0x19; 658c2ecf20Sopenharmony_ci gpio->ucDataMaskShift = 0x18; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* some evergreen boards have bad data for this entry */ 708c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 718c2ecf20Sopenharmony_ci if ((index == 7) && 728c2ecf20Sopenharmony_ci (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) && 738c2ecf20Sopenharmony_ci (gpio->sucI2cId.ucAccess == 0)) { 748c2ecf20Sopenharmony_ci gpio->sucI2cId.ucAccess = 0x97; 758c2ecf20Sopenharmony_ci gpio->ucDataMaskShift = 8; 768c2ecf20Sopenharmony_ci gpio->ucDataEnShift = 8; 778c2ecf20Sopenharmony_ci gpio->ucDataY_Shift = 8; 788c2ecf20Sopenharmony_ci gpio->ucDataA_Shift = 8; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* some DCE3 boards have bad data for this entry */ 838c2ecf20Sopenharmony_ci if (ASIC_IS_DCE3(rdev)) { 848c2ecf20Sopenharmony_ci if ((index == 4) && 858c2ecf20Sopenharmony_ci (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) && 868c2ecf20Sopenharmony_ci (gpio->sucI2cId.ucAccess == 0x94)) 878c2ecf20Sopenharmony_ci gpio->sucI2cId.ucAccess = 0x14; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic struct radeon_i2c_bus_rec radeon_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct radeon_i2c_bus_rec i2c; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec)); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; 988c2ecf20Sopenharmony_ci i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; 998c2ecf20Sopenharmony_ci i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; 1008c2ecf20Sopenharmony_ci i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4; 1018c2ecf20Sopenharmony_ci i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4; 1028c2ecf20Sopenharmony_ci i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4; 1038c2ecf20Sopenharmony_ci i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4; 1048c2ecf20Sopenharmony_ci i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4; 1058c2ecf20Sopenharmony_ci i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift); 1068c2ecf20Sopenharmony_ci i2c.mask_data_mask = (1 << gpio->ucDataMaskShift); 1078c2ecf20Sopenharmony_ci i2c.en_clk_mask = (1 << gpio->ucClkEnShift); 1088c2ecf20Sopenharmony_ci i2c.en_data_mask = (1 << gpio->ucDataEnShift); 1098c2ecf20Sopenharmony_ci i2c.y_clk_mask = (1 << gpio->ucClkY_Shift); 1108c2ecf20Sopenharmony_ci i2c.y_data_mask = (1 << gpio->ucDataY_Shift); 1118c2ecf20Sopenharmony_ci i2c.a_clk_mask = (1 << gpio->ucClkA_Shift); 1128c2ecf20Sopenharmony_ci i2c.a_data_mask = (1 << gpio->ucDataA_Shift); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (gpio->sucI2cId.sbfAccess.bfHW_Capable) 1158c2ecf20Sopenharmony_ci i2c.hw_capable = true; 1168c2ecf20Sopenharmony_ci else 1178c2ecf20Sopenharmony_ci i2c.hw_capable = false; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (gpio->sucI2cId.ucAccess == 0xa0) 1208c2ecf20Sopenharmony_ci i2c.mm_i2c = true; 1218c2ecf20Sopenharmony_ci else 1228c2ecf20Sopenharmony_ci i2c.mm_i2c = false; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci i2c.i2c_id = gpio->sucI2cId.ucAccess; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (i2c.mask_clk_reg) 1278c2ecf20Sopenharmony_ci i2c.valid = true; 1288c2ecf20Sopenharmony_ci else 1298c2ecf20Sopenharmony_ci i2c.valid = false; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return i2c; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rdev, 1358c2ecf20Sopenharmony_ci uint8_t id) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct atom_context *ctx = rdev->mode_info.atom_context; 1388c2ecf20Sopenharmony_ci ATOM_GPIO_I2C_ASSIGMENT *gpio; 1398c2ecf20Sopenharmony_ci struct radeon_i2c_bus_rec i2c; 1408c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info); 1418c2ecf20Sopenharmony_ci struct _ATOM_GPIO_I2C_INFO *i2c_info; 1428c2ecf20Sopenharmony_ci uint16_t data_offset, size; 1438c2ecf20Sopenharmony_ci int i, num_indices; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec)); 1468c2ecf20Sopenharmony_ci i2c.valid = false; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { 1498c2ecf20Sopenharmony_ci i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 1528c2ecf20Sopenharmony_ci sizeof(ATOM_GPIO_I2C_ASSIGMENT); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci gpio = &i2c_info->asGPIO_Info[0]; 1558c2ecf20Sopenharmony_ci for (i = 0; i < num_indices; i++) { 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci radeon_lookup_i2c_gpio_quirks(rdev, gpio, i); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (gpio->sucI2cId.ucAccess == id) { 1608c2ecf20Sopenharmony_ci i2c = radeon_get_bus_rec_for_i2c_gpio(gpio); 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci gpio = (ATOM_GPIO_I2C_ASSIGMENT *) 1648c2ecf20Sopenharmony_ci ((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT)); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return i2c; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_civoid radeon_atombios_i2c_init(struct radeon_device *rdev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct atom_context *ctx = rdev->mode_info.atom_context; 1748c2ecf20Sopenharmony_ci ATOM_GPIO_I2C_ASSIGMENT *gpio; 1758c2ecf20Sopenharmony_ci struct radeon_i2c_bus_rec i2c; 1768c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info); 1778c2ecf20Sopenharmony_ci struct _ATOM_GPIO_I2C_INFO *i2c_info; 1788c2ecf20Sopenharmony_ci uint16_t data_offset, size; 1798c2ecf20Sopenharmony_ci int i, num_indices; 1808c2ecf20Sopenharmony_ci char stmp[32]; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { 1838c2ecf20Sopenharmony_ci i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 1868c2ecf20Sopenharmony_ci sizeof(ATOM_GPIO_I2C_ASSIGMENT); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci gpio = &i2c_info->asGPIO_Info[0]; 1898c2ecf20Sopenharmony_ci for (i = 0; i < num_indices; i++) { 1908c2ecf20Sopenharmony_ci radeon_lookup_i2c_gpio_quirks(rdev, gpio, i); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci i2c = radeon_get_bus_rec_for_i2c_gpio(gpio); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (i2c.valid) { 1958c2ecf20Sopenharmony_ci sprintf(stmp, "0x%x", i2c.i2c_id); 1968c2ecf20Sopenharmony_ci rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci gpio = (ATOM_GPIO_I2C_ASSIGMENT *) 1998c2ecf20Sopenharmony_ci ((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT)); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistruct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev, 2058c2ecf20Sopenharmony_ci u8 id) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct atom_context *ctx = rdev->mode_info.atom_context; 2088c2ecf20Sopenharmony_ci struct radeon_gpio_rec gpio; 2098c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT); 2108c2ecf20Sopenharmony_ci struct _ATOM_GPIO_PIN_LUT *gpio_info; 2118c2ecf20Sopenharmony_ci ATOM_GPIO_PIN_ASSIGNMENT *pin; 2128c2ecf20Sopenharmony_ci u16 data_offset, size; 2138c2ecf20Sopenharmony_ci int i, num_indices; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci memset(&gpio, 0, sizeof(struct radeon_gpio_rec)); 2168c2ecf20Sopenharmony_ci gpio.valid = false; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { 2198c2ecf20Sopenharmony_ci gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 2228c2ecf20Sopenharmony_ci sizeof(ATOM_GPIO_PIN_ASSIGNMENT); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci pin = gpio_info->asGPIO_Pin; 2258c2ecf20Sopenharmony_ci for (i = 0; i < num_indices; i++) { 2268c2ecf20Sopenharmony_ci if (id == pin->ucGPIO_ID) { 2278c2ecf20Sopenharmony_ci gpio.id = pin->ucGPIO_ID; 2288c2ecf20Sopenharmony_ci gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4; 2298c2ecf20Sopenharmony_ci gpio.shift = pin->ucGpioPinBitShift; 2308c2ecf20Sopenharmony_ci gpio.mask = (1 << pin->ucGpioPinBitShift); 2318c2ecf20Sopenharmony_ci gpio.valid = true; 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci pin = (ATOM_GPIO_PIN_ASSIGNMENT *) 2358c2ecf20Sopenharmony_ci ((u8 *)pin + sizeof(ATOM_GPIO_PIN_ASSIGNMENT)); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return gpio; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device *rdev, 2438c2ecf20Sopenharmony_ci struct radeon_gpio_rec *gpio) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct radeon_hpd hpd; 2468c2ecf20Sopenharmony_ci u32 reg; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci memset(&hpd, 0, sizeof(struct radeon_hpd)); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (ASIC_IS_DCE6(rdev)) 2518c2ecf20Sopenharmony_ci reg = SI_DC_GPIO_HPD_A; 2528c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE4(rdev)) 2538c2ecf20Sopenharmony_ci reg = EVERGREEN_DC_GPIO_HPD_A; 2548c2ecf20Sopenharmony_ci else 2558c2ecf20Sopenharmony_ci reg = AVIVO_DC_GPIO_HPD_A; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci hpd.gpio = *gpio; 2588c2ecf20Sopenharmony_ci if (gpio->reg == reg) { 2598c2ecf20Sopenharmony_ci switch(gpio->mask) { 2608c2ecf20Sopenharmony_ci case (1 << 0): 2618c2ecf20Sopenharmony_ci hpd.hpd = RADEON_HPD_1; 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci case (1 << 8): 2648c2ecf20Sopenharmony_ci hpd.hpd = RADEON_HPD_2; 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci case (1 << 16): 2678c2ecf20Sopenharmony_ci hpd.hpd = RADEON_HPD_3; 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci case (1 << 24): 2708c2ecf20Sopenharmony_ci hpd.hpd = RADEON_HPD_4; 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci case (1 << 26): 2738c2ecf20Sopenharmony_ci hpd.hpd = RADEON_HPD_5; 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci case (1 << 28): 2768c2ecf20Sopenharmony_ci hpd.hpd = RADEON_HPD_6; 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci default: 2798c2ecf20Sopenharmony_ci hpd.hpd = RADEON_HPD_NONE; 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci } else 2838c2ecf20Sopenharmony_ci hpd.hpd = RADEON_HPD_NONE; 2848c2ecf20Sopenharmony_ci return hpd; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic bool radeon_atom_apply_quirks(struct drm_device *dev, 2888c2ecf20Sopenharmony_ci uint32_t supported_device, 2898c2ecf20Sopenharmony_ci int *connector_type, 2908c2ecf20Sopenharmony_ci struct radeon_i2c_bus_rec *i2c_bus, 2918c2ecf20Sopenharmony_ci uint16_t *line_mux, 2928c2ecf20Sopenharmony_ci struct radeon_hpd *hpd) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Asus M2A-VM HDMI board lists the DVI port as HDMI */ 2968c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x791e) && 2978c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1043) && 2988c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x826d)) { 2998c2ecf20Sopenharmony_ci if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) && 3008c2ecf20Sopenharmony_ci (supported_device == ATOM_DEVICE_DFP3_SUPPORT)) 3018c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_DVID; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* Asrock RS600 board lists the DVI port as HDMI */ 3058c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x7941) && 3068c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1849) && 3078c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x7941)) { 3088c2ecf20Sopenharmony_ci if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) && 3098c2ecf20Sopenharmony_ci (supported_device == ATOM_DEVICE_DFP3_SUPPORT)) 3108c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_DVID; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* MSI K9A2GM V2/V3 board has no HDMI or DVI */ 3148c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x796e) && 3158c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1462) && 3168c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x7302)) { 3178c2ecf20Sopenharmony_ci if ((supported_device == ATOM_DEVICE_DFP2_SUPPORT) || 3188c2ecf20Sopenharmony_ci (supported_device == ATOM_DEVICE_DFP3_SUPPORT)) 3198c2ecf20Sopenharmony_ci return false; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */ 3238c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x7941) && 3248c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x147b) && 3258c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x2412)) { 3268c2ecf20Sopenharmony_ci if (*connector_type == DRM_MODE_CONNECTOR_DVII) 3278c2ecf20Sopenharmony_ci return false; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Falcon NW laptop lists vga ddc line for LVDS */ 3318c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x5653) && 3328c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1462) && 3338c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x0291)) { 3348c2ecf20Sopenharmony_ci if (*connector_type == DRM_MODE_CONNECTOR_LVDS) { 3358c2ecf20Sopenharmony_ci i2c_bus->valid = false; 3368c2ecf20Sopenharmony_ci *line_mux = 53; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* HIS X1300 is DVI+VGA, not DVI+DVI */ 3418c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x7146) && 3428c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x17af) && 3438c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x2058)) { 3448c2ecf20Sopenharmony_ci if (supported_device == ATOM_DEVICE_DFP1_SUPPORT) 3458c2ecf20Sopenharmony_ci return false; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Gigabyte X1300 is DVI+VGA, not DVI+DVI */ 3498c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x7142) && 3508c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1458) && 3518c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x2134)) { 3528c2ecf20Sopenharmony_ci if (supported_device == ATOM_DEVICE_DFP1_SUPPORT) 3538c2ecf20Sopenharmony_ci return false; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Funky macbooks */ 3588c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x71C5) && 3598c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x106b) && 3608c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x0080)) { 3618c2ecf20Sopenharmony_ci if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) || 3628c2ecf20Sopenharmony_ci (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) 3638c2ecf20Sopenharmony_ci return false; 3648c2ecf20Sopenharmony_ci if (supported_device == ATOM_DEVICE_CRT2_SUPPORT) 3658c2ecf20Sopenharmony_ci *line_mux = 0x90; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* mac rv630, rv730, others */ 3698c2ecf20Sopenharmony_ci if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) && 3708c2ecf20Sopenharmony_ci (*connector_type == DRM_MODE_CONNECTOR_DVII)) { 3718c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_9PinDIN; 3728c2ecf20Sopenharmony_ci *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* ASUS HD 3600 XT board lists the DVI port as HDMI */ 3768c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x9598) && 3778c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1043) && 3788c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x01da)) { 3798c2ecf20Sopenharmony_ci if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) { 3808c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_DVII; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* ASUS HD 3600 board lists the DVI port as HDMI */ 3858c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x9598) && 3868c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1043) && 3878c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x01e4)) { 3888c2ecf20Sopenharmony_ci if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) { 3898c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_DVII; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* ASUS HD 3450 board lists the DVI port as HDMI */ 3948c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x95C5) && 3958c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1043) && 3968c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x01e2)) { 3978c2ecf20Sopenharmony_ci if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) { 3988c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_DVII; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* some BIOSes seem to report DAC on HDMI - usually this is a board with 4038c2ecf20Sopenharmony_ci * HDMI + VGA reporting as HDMI 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ci if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) { 4068c2ecf20Sopenharmony_ci if (supported_device & (ATOM_DEVICE_CRT_SUPPORT)) { 4078c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_VGA; 4088c2ecf20Sopenharmony_ci *line_mux = 0; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Acer laptop (Acer TravelMate 5730/5730G) has an HDMI port 4138c2ecf20Sopenharmony_ci * on the laptop and a DVI port on the docking station and 4148c2ecf20Sopenharmony_ci * both share the same encoder, hpd pin, and ddc line. 4158c2ecf20Sopenharmony_ci * So while the bios table is technically correct, 4168c2ecf20Sopenharmony_ci * we drop the DVI port here since xrandr has no concept of 4178c2ecf20Sopenharmony_ci * encoders and will try and drive both connectors 4188c2ecf20Sopenharmony_ci * with different crtcs which isn't possible on the hardware 4198c2ecf20Sopenharmony_ci * side and leaves no crtcs for LVDS or VGA. 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci if (((dev->pdev->device == 0x95c4) || (dev->pdev->device == 0x9591)) && 4228c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1025) && 4238c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x013c)) { 4248c2ecf20Sopenharmony_ci if ((*connector_type == DRM_MODE_CONNECTOR_DVII) && 4258c2ecf20Sopenharmony_ci (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) { 4268c2ecf20Sopenharmony_ci /* actually it's a DVI-D port not DVI-I */ 4278c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_DVID; 4288c2ecf20Sopenharmony_ci return false; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* XFX Pine Group device rv730 reports no VGA DDC lines 4338c2ecf20Sopenharmony_ci * even though they are wired up to record 0x93 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_ci if ((dev->pdev->device == 0x9498) && 4368c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1682) && 4378c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x2452) && 4388c2ecf20Sopenharmony_ci (i2c_bus->valid == false) && 4398c2ecf20Sopenharmony_ci !(supported_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))) { 4408c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 4418c2ecf20Sopenharmony_ci *i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ 4458c2ecf20Sopenharmony_ci if (((dev->pdev->device == 0x9802) || 4468c2ecf20Sopenharmony_ci (dev->pdev->device == 0x9805) || 4478c2ecf20Sopenharmony_ci (dev->pdev->device == 0x9806)) && 4488c2ecf20Sopenharmony_ci (dev->pdev->subsystem_vendor == 0x1734) && 4498c2ecf20Sopenharmony_ci (dev->pdev->subsystem_device == 0x11bd)) { 4508c2ecf20Sopenharmony_ci if (*connector_type == DRM_MODE_CONNECTOR_VGA) { 4518c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_DVII; 4528c2ecf20Sopenharmony_ci *line_mux = 0x3103; 4538c2ecf20Sopenharmony_ci } else if (*connector_type == DRM_MODE_CONNECTOR_DVID) { 4548c2ecf20Sopenharmony_ci *connector_type = DRM_MODE_CONNECTOR_DVII; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return true; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic const int supported_devices_connector_convert[] = { 4628c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 4638c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_VGA, 4648c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DVII, 4658c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DVID, 4668c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DVIA, 4678c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_SVIDEO, 4688c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Composite, 4698c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_LVDS, 4708c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 4718c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 4728c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_HDMIA, 4738c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_HDMIB, 4748c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 4758c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 4768c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_9PinDIN, 4778c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DisplayPort 4788c2ecf20Sopenharmony_ci}; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic const uint16_t supported_devices_connector_object_id_convert[] = { 4818c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_NONE, 4828c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_VGA, 4838c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, /* not all boards support DL */ 4848c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D, /* not all boards support DL */ 4858c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_VGA, /* technically DVI-A */ 4868c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_COMPOSITE, 4878c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_SVIDEO, 4888c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_LVDS, 4898c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_9PIN_DIN, 4908c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_9PIN_DIN, 4918c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_DISPLAYPORT, 4928c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_HDMI_TYPE_A, 4938c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_HDMI_TYPE_B, 4948c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_SVIDEO 4958c2ecf20Sopenharmony_ci}; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic const int object_connector_convert[] = { 4988c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 4998c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DVII, 5008c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DVII, 5018c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DVID, 5028c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DVID, 5038c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_VGA, 5048c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Composite, 5058c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_SVIDEO, 5068c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 5078c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 5088c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_9PinDIN, 5098c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 5108c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_HDMIA, 5118c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_HDMIB, 5128c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_LVDS, 5138c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_9PinDIN, 5148c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 5158c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 5168c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown, 5178c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DisplayPort, 5188c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_eDP, 5198c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown 5208c2ecf20Sopenharmony_ci}; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cibool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 5258c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 5268c2ecf20Sopenharmony_ci struct atom_context *ctx = mode_info->atom_context; 5278c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, Object_Header); 5288c2ecf20Sopenharmony_ci u16 size, data_offset; 5298c2ecf20Sopenharmony_ci u8 frev, crev; 5308c2ecf20Sopenharmony_ci ATOM_CONNECTOR_OBJECT_TABLE *con_obj; 5318c2ecf20Sopenharmony_ci ATOM_ENCODER_OBJECT_TABLE *enc_obj; 5328c2ecf20Sopenharmony_ci ATOM_OBJECT_TABLE *router_obj; 5338c2ecf20Sopenharmony_ci ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj; 5348c2ecf20Sopenharmony_ci ATOM_OBJECT_HEADER *obj_header; 5358c2ecf20Sopenharmony_ci int i, j, k, path_size, device_support; 5368c2ecf20Sopenharmony_ci int connector_type; 5378c2ecf20Sopenharmony_ci u16 igp_lane_info, conn_id, connector_object_id; 5388c2ecf20Sopenharmony_ci struct radeon_i2c_bus_rec ddc_bus; 5398c2ecf20Sopenharmony_ci struct radeon_router router; 5408c2ecf20Sopenharmony_ci struct radeon_gpio_rec gpio; 5418c2ecf20Sopenharmony_ci struct radeon_hpd hpd; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) 5448c2ecf20Sopenharmony_ci return false; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (crev < 2) 5478c2ecf20Sopenharmony_ci return false; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset); 5508c2ecf20Sopenharmony_ci path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *) 5518c2ecf20Sopenharmony_ci (ctx->bios + data_offset + 5528c2ecf20Sopenharmony_ci le16_to_cpu(obj_header->usDisplayPathTableOffset)); 5538c2ecf20Sopenharmony_ci con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *) 5548c2ecf20Sopenharmony_ci (ctx->bios + data_offset + 5558c2ecf20Sopenharmony_ci le16_to_cpu(obj_header->usConnectorObjectTableOffset)); 5568c2ecf20Sopenharmony_ci enc_obj = (ATOM_ENCODER_OBJECT_TABLE *) 5578c2ecf20Sopenharmony_ci (ctx->bios + data_offset + 5588c2ecf20Sopenharmony_ci le16_to_cpu(obj_header->usEncoderObjectTableOffset)); 5598c2ecf20Sopenharmony_ci router_obj = (ATOM_OBJECT_TABLE *) 5608c2ecf20Sopenharmony_ci (ctx->bios + data_offset + 5618c2ecf20Sopenharmony_ci le16_to_cpu(obj_header->usRouterObjectTableOffset)); 5628c2ecf20Sopenharmony_ci device_support = le16_to_cpu(obj_header->usDeviceSupport); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci path_size = 0; 5658c2ecf20Sopenharmony_ci for (i = 0; i < path_obj->ucNumOfDispPath; i++) { 5668c2ecf20Sopenharmony_ci uint8_t *addr = (uint8_t *) path_obj->asDispPath; 5678c2ecf20Sopenharmony_ci ATOM_DISPLAY_OBJECT_PATH *path; 5688c2ecf20Sopenharmony_ci addr += path_size; 5698c2ecf20Sopenharmony_ci path = (ATOM_DISPLAY_OBJECT_PATH *) addr; 5708c2ecf20Sopenharmony_ci path_size += le16_to_cpu(path->usSize); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (device_support & le16_to_cpu(path->usDeviceTag)) { 5738c2ecf20Sopenharmony_ci uint8_t con_obj_id, con_obj_num; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci con_obj_id = 5768c2ecf20Sopenharmony_ci (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) 5778c2ecf20Sopenharmony_ci >> OBJECT_ID_SHIFT; 5788c2ecf20Sopenharmony_ci con_obj_num = 5798c2ecf20Sopenharmony_ci (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) 5808c2ecf20Sopenharmony_ci >> ENUM_ID_SHIFT; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* TODO CV support */ 5838c2ecf20Sopenharmony_ci if (le16_to_cpu(path->usDeviceTag) == 5848c2ecf20Sopenharmony_ci ATOM_DEVICE_CV_SUPPORT) 5858c2ecf20Sopenharmony_ci continue; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* IGP chips */ 5888c2ecf20Sopenharmony_ci if ((rdev->flags & RADEON_IS_IGP) && 5898c2ecf20Sopenharmony_ci (con_obj_id == 5908c2ecf20Sopenharmony_ci CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) { 5918c2ecf20Sopenharmony_ci uint16_t igp_offset = 0; 5928c2ecf20Sopenharmony_ci ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci index = 5958c2ecf20Sopenharmony_ci GetIndexIntoMasterTable(DATA, 5968c2ecf20Sopenharmony_ci IntegratedSystemInfo); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (atom_parse_data_header(ctx, index, &size, &frev, 5998c2ecf20Sopenharmony_ci &crev, &igp_offset)) { 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (crev >= 2) { 6028c2ecf20Sopenharmony_ci igp_obj = 6038c2ecf20Sopenharmony_ci (ATOM_INTEGRATED_SYSTEM_INFO_V2 6048c2ecf20Sopenharmony_ci *) (ctx->bios + igp_offset); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (igp_obj) { 6078c2ecf20Sopenharmony_ci uint32_t slot_config, ct; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (con_obj_num == 1) 6108c2ecf20Sopenharmony_ci slot_config = 6118c2ecf20Sopenharmony_ci igp_obj-> 6128c2ecf20Sopenharmony_ci ulDDISlot1Config; 6138c2ecf20Sopenharmony_ci else 6148c2ecf20Sopenharmony_ci slot_config = 6158c2ecf20Sopenharmony_ci igp_obj-> 6168c2ecf20Sopenharmony_ci ulDDISlot2Config; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci ct = (slot_config >> 16) & 0xff; 6198c2ecf20Sopenharmony_ci connector_type = 6208c2ecf20Sopenharmony_ci object_connector_convert 6218c2ecf20Sopenharmony_ci [ct]; 6228c2ecf20Sopenharmony_ci connector_object_id = ct; 6238c2ecf20Sopenharmony_ci igp_lane_info = 6248c2ecf20Sopenharmony_ci slot_config & 0xffff; 6258c2ecf20Sopenharmony_ci } else 6268c2ecf20Sopenharmony_ci continue; 6278c2ecf20Sopenharmony_ci } else 6288c2ecf20Sopenharmony_ci continue; 6298c2ecf20Sopenharmony_ci } else { 6308c2ecf20Sopenharmony_ci igp_lane_info = 0; 6318c2ecf20Sopenharmony_ci connector_type = 6328c2ecf20Sopenharmony_ci object_connector_convert[con_obj_id]; 6338c2ecf20Sopenharmony_ci connector_object_id = con_obj_id; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci } else { 6368c2ecf20Sopenharmony_ci igp_lane_info = 0; 6378c2ecf20Sopenharmony_ci connector_type = 6388c2ecf20Sopenharmony_ci object_connector_convert[con_obj_id]; 6398c2ecf20Sopenharmony_ci connector_object_id = con_obj_id; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (connector_type == DRM_MODE_CONNECTOR_Unknown) 6438c2ecf20Sopenharmony_ci continue; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci router.ddc_valid = false; 6468c2ecf20Sopenharmony_ci router.cd_valid = false; 6478c2ecf20Sopenharmony_ci for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) { 6488c2ecf20Sopenharmony_ci uint8_t grph_obj_type = 6498c2ecf20Sopenharmony_ci (le16_to_cpu(path->usGraphicObjIds[j]) & 6508c2ecf20Sopenharmony_ci OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) { 6538c2ecf20Sopenharmony_ci for (k = 0; k < enc_obj->ucNumberOfObjects; k++) { 6548c2ecf20Sopenharmony_ci u16 encoder_obj = le16_to_cpu(enc_obj->asObjects[k].usObjectID); 6558c2ecf20Sopenharmony_ci if (le16_to_cpu(path->usGraphicObjIds[j]) == encoder_obj) { 6568c2ecf20Sopenharmony_ci ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *) 6578c2ecf20Sopenharmony_ci (ctx->bios + data_offset + 6588c2ecf20Sopenharmony_ci le16_to_cpu(enc_obj->asObjects[k].usRecordOffset)); 6598c2ecf20Sopenharmony_ci ATOM_ENCODER_CAP_RECORD *cap_record; 6608c2ecf20Sopenharmony_ci u16 caps = 0; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci while (record->ucRecordSize > 0 && 6638c2ecf20Sopenharmony_ci record->ucRecordType > 0 && 6648c2ecf20Sopenharmony_ci record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 6658c2ecf20Sopenharmony_ci switch (record->ucRecordType) { 6668c2ecf20Sopenharmony_ci case ATOM_ENCODER_CAP_RECORD_TYPE: 6678c2ecf20Sopenharmony_ci cap_record =(ATOM_ENCODER_CAP_RECORD *) 6688c2ecf20Sopenharmony_ci record; 6698c2ecf20Sopenharmony_ci caps = le16_to_cpu(cap_record->usEncoderCap); 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci record = (ATOM_COMMON_RECORD_HEADER *) 6738c2ecf20Sopenharmony_ci ((char *)record + record->ucRecordSize); 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci radeon_add_atom_encoder(dev, 6768c2ecf20Sopenharmony_ci encoder_obj, 6778c2ecf20Sopenharmony_ci le16_to_cpu 6788c2ecf20Sopenharmony_ci (path-> 6798c2ecf20Sopenharmony_ci usDeviceTag), 6808c2ecf20Sopenharmony_ci caps); 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci } else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) { 6848c2ecf20Sopenharmony_ci for (k = 0; k < router_obj->ucNumberOfObjects; k++) { 6858c2ecf20Sopenharmony_ci u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID); 6868c2ecf20Sopenharmony_ci if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) { 6878c2ecf20Sopenharmony_ci ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *) 6888c2ecf20Sopenharmony_ci (ctx->bios + data_offset + 6898c2ecf20Sopenharmony_ci le16_to_cpu(router_obj->asObjects[k].usRecordOffset)); 6908c2ecf20Sopenharmony_ci ATOM_I2C_RECORD *i2c_record; 6918c2ecf20Sopenharmony_ci ATOM_I2C_ID_CONFIG_ACCESS *i2c_config; 6928c2ecf20Sopenharmony_ci ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path; 6938c2ecf20Sopenharmony_ci ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path; 6948c2ecf20Sopenharmony_ci ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table = 6958c2ecf20Sopenharmony_ci (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) 6968c2ecf20Sopenharmony_ci (ctx->bios + data_offset + 6978c2ecf20Sopenharmony_ci le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset)); 6988c2ecf20Sopenharmony_ci u8 *num_dst_objs = (u8 *) 6998c2ecf20Sopenharmony_ci ((u8 *)router_src_dst_table + 1 + 7008c2ecf20Sopenharmony_ci (router_src_dst_table->ucNumberOfSrc * 2)); 7018c2ecf20Sopenharmony_ci u16 *dst_objs = (u16 *)(num_dst_objs + 1); 7028c2ecf20Sopenharmony_ci int enum_id; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci router.router_id = router_obj_id; 7058c2ecf20Sopenharmony_ci for (enum_id = 0; enum_id < (*num_dst_objs); enum_id++) { 7068c2ecf20Sopenharmony_ci if (le16_to_cpu(path->usConnObjectId) == 7078c2ecf20Sopenharmony_ci le16_to_cpu(dst_objs[enum_id])) 7088c2ecf20Sopenharmony_ci break; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci while (record->ucRecordSize > 0 && 7128c2ecf20Sopenharmony_ci record->ucRecordType > 0 && 7138c2ecf20Sopenharmony_ci record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 7148c2ecf20Sopenharmony_ci switch (record->ucRecordType) { 7158c2ecf20Sopenharmony_ci case ATOM_I2C_RECORD_TYPE: 7168c2ecf20Sopenharmony_ci i2c_record = 7178c2ecf20Sopenharmony_ci (ATOM_I2C_RECORD *) 7188c2ecf20Sopenharmony_ci record; 7198c2ecf20Sopenharmony_ci i2c_config = 7208c2ecf20Sopenharmony_ci (ATOM_I2C_ID_CONFIG_ACCESS *) 7218c2ecf20Sopenharmony_ci &i2c_record->sucI2cId; 7228c2ecf20Sopenharmony_ci router.i2c_info = 7238c2ecf20Sopenharmony_ci radeon_lookup_i2c_gpio(rdev, 7248c2ecf20Sopenharmony_ci i2c_config-> 7258c2ecf20Sopenharmony_ci ucAccess); 7268c2ecf20Sopenharmony_ci router.i2c_addr = i2c_record->ucI2CAddr >> 1; 7278c2ecf20Sopenharmony_ci break; 7288c2ecf20Sopenharmony_ci case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE: 7298c2ecf20Sopenharmony_ci ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *) 7308c2ecf20Sopenharmony_ci record; 7318c2ecf20Sopenharmony_ci router.ddc_valid = true; 7328c2ecf20Sopenharmony_ci router.ddc_mux_type = ddc_path->ucMuxType; 7338c2ecf20Sopenharmony_ci router.ddc_mux_control_pin = ddc_path->ucMuxControlPin; 7348c2ecf20Sopenharmony_ci router.ddc_mux_state = ddc_path->ucMuxState[enum_id]; 7358c2ecf20Sopenharmony_ci break; 7368c2ecf20Sopenharmony_ci case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE: 7378c2ecf20Sopenharmony_ci cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *) 7388c2ecf20Sopenharmony_ci record; 7398c2ecf20Sopenharmony_ci router.cd_valid = true; 7408c2ecf20Sopenharmony_ci router.cd_mux_type = cd_path->ucMuxType; 7418c2ecf20Sopenharmony_ci router.cd_mux_control_pin = cd_path->ucMuxControlPin; 7428c2ecf20Sopenharmony_ci router.cd_mux_state = cd_path->ucMuxState[enum_id]; 7438c2ecf20Sopenharmony_ci break; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci record = (ATOM_COMMON_RECORD_HEADER *) 7468c2ecf20Sopenharmony_ci ((char *)record + record->ucRecordSize); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* look up gpio for ddc, hpd */ 7548c2ecf20Sopenharmony_ci ddc_bus.valid = false; 7558c2ecf20Sopenharmony_ci hpd.hpd = RADEON_HPD_NONE; 7568c2ecf20Sopenharmony_ci if ((le16_to_cpu(path->usDeviceTag) & 7578c2ecf20Sopenharmony_ci (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) { 7588c2ecf20Sopenharmony_ci for (j = 0; j < con_obj->ucNumberOfObjects; j++) { 7598c2ecf20Sopenharmony_ci if (le16_to_cpu(path->usConnObjectId) == 7608c2ecf20Sopenharmony_ci le16_to_cpu(con_obj->asObjects[j]. 7618c2ecf20Sopenharmony_ci usObjectID)) { 7628c2ecf20Sopenharmony_ci ATOM_COMMON_RECORD_HEADER 7638c2ecf20Sopenharmony_ci *record = 7648c2ecf20Sopenharmony_ci (ATOM_COMMON_RECORD_HEADER 7658c2ecf20Sopenharmony_ci *) 7668c2ecf20Sopenharmony_ci (ctx->bios + data_offset + 7678c2ecf20Sopenharmony_ci le16_to_cpu(con_obj-> 7688c2ecf20Sopenharmony_ci asObjects[j]. 7698c2ecf20Sopenharmony_ci usRecordOffset)); 7708c2ecf20Sopenharmony_ci ATOM_I2C_RECORD *i2c_record; 7718c2ecf20Sopenharmony_ci ATOM_HPD_INT_RECORD *hpd_record; 7728c2ecf20Sopenharmony_ci ATOM_I2C_ID_CONFIG_ACCESS *i2c_config; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci while (record->ucRecordSize > 0 && 7758c2ecf20Sopenharmony_ci record->ucRecordType > 0 && 7768c2ecf20Sopenharmony_ci record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 7778c2ecf20Sopenharmony_ci switch (record->ucRecordType) { 7788c2ecf20Sopenharmony_ci case ATOM_I2C_RECORD_TYPE: 7798c2ecf20Sopenharmony_ci i2c_record = 7808c2ecf20Sopenharmony_ci (ATOM_I2C_RECORD *) 7818c2ecf20Sopenharmony_ci record; 7828c2ecf20Sopenharmony_ci i2c_config = 7838c2ecf20Sopenharmony_ci (ATOM_I2C_ID_CONFIG_ACCESS *) 7848c2ecf20Sopenharmony_ci &i2c_record->sucI2cId; 7858c2ecf20Sopenharmony_ci ddc_bus = radeon_lookup_i2c_gpio(rdev, 7868c2ecf20Sopenharmony_ci i2c_config-> 7878c2ecf20Sopenharmony_ci ucAccess); 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci case ATOM_HPD_INT_RECORD_TYPE: 7908c2ecf20Sopenharmony_ci hpd_record = 7918c2ecf20Sopenharmony_ci (ATOM_HPD_INT_RECORD *) 7928c2ecf20Sopenharmony_ci record; 7938c2ecf20Sopenharmony_ci gpio = radeon_atombios_lookup_gpio(rdev, 7948c2ecf20Sopenharmony_ci hpd_record->ucHPDIntGPIOID); 7958c2ecf20Sopenharmony_ci hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio); 7968c2ecf20Sopenharmony_ci hpd.plugged_state = hpd_record->ucPlugged_PinState; 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci record = 8008c2ecf20Sopenharmony_ci (ATOM_COMMON_RECORD_HEADER 8018c2ecf20Sopenharmony_ci *) ((char *)record 8028c2ecf20Sopenharmony_ci + 8038c2ecf20Sopenharmony_ci record-> 8048c2ecf20Sopenharmony_ci ucRecordSize); 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* needed for aux chan transactions */ 8128c2ecf20Sopenharmony_ci ddc_bus.hpd = hpd.hpd; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci conn_id = le16_to_cpu(path->usConnObjectId); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (!radeon_atom_apply_quirks 8178c2ecf20Sopenharmony_ci (dev, le16_to_cpu(path->usDeviceTag), &connector_type, 8188c2ecf20Sopenharmony_ci &ddc_bus, &conn_id, &hpd)) 8198c2ecf20Sopenharmony_ci continue; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci radeon_add_atom_connector(dev, 8228c2ecf20Sopenharmony_ci conn_id, 8238c2ecf20Sopenharmony_ci le16_to_cpu(path-> 8248c2ecf20Sopenharmony_ci usDeviceTag), 8258c2ecf20Sopenharmony_ci connector_type, &ddc_bus, 8268c2ecf20Sopenharmony_ci igp_lane_info, 8278c2ecf20Sopenharmony_ci connector_object_id, 8288c2ecf20Sopenharmony_ci &hpd, 8298c2ecf20Sopenharmony_ci &router); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci radeon_link_encoder_connector(dev); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci radeon_setup_mst_connector(dev); 8378c2ecf20Sopenharmony_ci return true; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic uint16_t atombios_get_connector_object_id(struct drm_device *dev, 8418c2ecf20Sopenharmony_ci int connector_type, 8428c2ecf20Sopenharmony_ci uint16_t devices) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) { 8478c2ecf20Sopenharmony_ci return supported_devices_connector_object_id_convert 8488c2ecf20Sopenharmony_ci [connector_type]; 8498c2ecf20Sopenharmony_ci } else if (((connector_type == DRM_MODE_CONNECTOR_DVII) || 8508c2ecf20Sopenharmony_ci (connector_type == DRM_MODE_CONNECTOR_DVID)) && 8518c2ecf20Sopenharmony_ci (devices & ATOM_DEVICE_DFP2_SUPPORT)) { 8528c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 8538c2ecf20Sopenharmony_ci struct atom_context *ctx = mode_info->atom_context; 8548c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, XTMDS_Info); 8558c2ecf20Sopenharmony_ci uint16_t size, data_offset; 8568c2ecf20Sopenharmony_ci uint8_t frev, crev; 8578c2ecf20Sopenharmony_ci ATOM_XTMDS_INFO *xtmds; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) { 8608c2ecf20Sopenharmony_ci xtmds = (ATOM_XTMDS_INFO *)(ctx->bios + data_offset); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (xtmds->ucSupportedLink & ATOM_XTMDS_SUPPORTED_DUALLINK) { 8638c2ecf20Sopenharmony_ci if (connector_type == DRM_MODE_CONNECTOR_DVII) 8648c2ecf20Sopenharmony_ci return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I; 8658c2ecf20Sopenharmony_ci else 8668c2ecf20Sopenharmony_ci return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D; 8678c2ecf20Sopenharmony_ci } else { 8688c2ecf20Sopenharmony_ci if (connector_type == DRM_MODE_CONNECTOR_DVII) 8698c2ecf20Sopenharmony_ci return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I; 8708c2ecf20Sopenharmony_ci else 8718c2ecf20Sopenharmony_ci return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci } else 8748c2ecf20Sopenharmony_ci return supported_devices_connector_object_id_convert 8758c2ecf20Sopenharmony_ci [connector_type]; 8768c2ecf20Sopenharmony_ci } else { 8778c2ecf20Sopenharmony_ci return supported_devices_connector_object_id_convert 8788c2ecf20Sopenharmony_ci [connector_type]; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistruct bios_connector { 8838c2ecf20Sopenharmony_ci bool valid; 8848c2ecf20Sopenharmony_ci uint16_t line_mux; 8858c2ecf20Sopenharmony_ci uint16_t devices; 8868c2ecf20Sopenharmony_ci int connector_type; 8878c2ecf20Sopenharmony_ci struct radeon_i2c_bus_rec ddc_bus; 8888c2ecf20Sopenharmony_ci struct radeon_hpd hpd; 8898c2ecf20Sopenharmony_ci}; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cibool radeon_get_atom_connector_info_from_supported_devices_table(struct 8928c2ecf20Sopenharmony_ci drm_device 8938c2ecf20Sopenharmony_ci *dev) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 8968c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 8978c2ecf20Sopenharmony_ci struct atom_context *ctx = mode_info->atom_context; 8988c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo); 8998c2ecf20Sopenharmony_ci uint16_t size, data_offset; 9008c2ecf20Sopenharmony_ci uint8_t frev, crev; 9018c2ecf20Sopenharmony_ci uint16_t device_support; 9028c2ecf20Sopenharmony_ci uint8_t dac; 9038c2ecf20Sopenharmony_ci union atom_supported_devices *supported_devices; 9048c2ecf20Sopenharmony_ci int i, j, max_device; 9058c2ecf20Sopenharmony_ci struct bios_connector *bios_connectors; 9068c2ecf20Sopenharmony_ci size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE; 9078c2ecf20Sopenharmony_ci struct radeon_router router; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci router.ddc_valid = false; 9108c2ecf20Sopenharmony_ci router.cd_valid = false; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci bios_connectors = kzalloc(bc_size, GFP_KERNEL); 9138c2ecf20Sopenharmony_ci if (!bios_connectors) 9148c2ecf20Sopenharmony_ci return false; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, 9178c2ecf20Sopenharmony_ci &data_offset)) { 9188c2ecf20Sopenharmony_ci kfree(bios_connectors); 9198c2ecf20Sopenharmony_ci return false; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci supported_devices = 9238c2ecf20Sopenharmony_ci (union atom_supported_devices *)(ctx->bios + data_offset); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci device_support = le16_to_cpu(supported_devices->info.usDeviceSupport); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (frev > 1) 9288c2ecf20Sopenharmony_ci max_device = ATOM_MAX_SUPPORTED_DEVICE; 9298c2ecf20Sopenharmony_ci else 9308c2ecf20Sopenharmony_ci max_device = ATOM_MAX_SUPPORTED_DEVICE_INFO; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci for (i = 0; i < max_device; i++) { 9338c2ecf20Sopenharmony_ci ATOM_CONNECTOR_INFO_I2C ci = 9348c2ecf20Sopenharmony_ci supported_devices->info.asConnInfo[i]; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci bios_connectors[i].valid = false; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (!(device_support & (1 << i))) { 9398c2ecf20Sopenharmony_ci continue; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (i == ATOM_DEVICE_CV_INDEX) { 9438c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Skipping Component Video\n"); 9448c2ecf20Sopenharmony_ci continue; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci bios_connectors[i].connector_type = 9488c2ecf20Sopenharmony_ci supported_devices_connector_convert[ci.sucConnectorInfo. 9498c2ecf20Sopenharmony_ci sbfAccess. 9508c2ecf20Sopenharmony_ci bfConnectorType]; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (bios_connectors[i].connector_type == 9538c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_Unknown) 9548c2ecf20Sopenharmony_ci continue; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci bios_connectors[i].line_mux = 9598c2ecf20Sopenharmony_ci ci.sucI2cId.ucAccess; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* give tv unique connector ids */ 9628c2ecf20Sopenharmony_ci if (i == ATOM_DEVICE_TV1_INDEX) { 9638c2ecf20Sopenharmony_ci bios_connectors[i].ddc_bus.valid = false; 9648c2ecf20Sopenharmony_ci bios_connectors[i].line_mux = 50; 9658c2ecf20Sopenharmony_ci } else if (i == ATOM_DEVICE_TV2_INDEX) { 9668c2ecf20Sopenharmony_ci bios_connectors[i].ddc_bus.valid = false; 9678c2ecf20Sopenharmony_ci bios_connectors[i].line_mux = 51; 9688c2ecf20Sopenharmony_ci } else if (i == ATOM_DEVICE_CV_INDEX) { 9698c2ecf20Sopenharmony_ci bios_connectors[i].ddc_bus.valid = false; 9708c2ecf20Sopenharmony_ci bios_connectors[i].line_mux = 52; 9718c2ecf20Sopenharmony_ci } else 9728c2ecf20Sopenharmony_ci bios_connectors[i].ddc_bus = 9738c2ecf20Sopenharmony_ci radeon_lookup_i2c_gpio(rdev, 9748c2ecf20Sopenharmony_ci bios_connectors[i].line_mux); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if ((crev > 1) && (frev > 1)) { 9778c2ecf20Sopenharmony_ci u8 isb = supported_devices->info_2d1.asIntSrcInfo[i].ucIntSrcBitmap; 9788c2ecf20Sopenharmony_ci switch (isb) { 9798c2ecf20Sopenharmony_ci case 0x4: 9808c2ecf20Sopenharmony_ci bios_connectors[i].hpd.hpd = RADEON_HPD_1; 9818c2ecf20Sopenharmony_ci break; 9828c2ecf20Sopenharmony_ci case 0xa: 9838c2ecf20Sopenharmony_ci bios_connectors[i].hpd.hpd = RADEON_HPD_2; 9848c2ecf20Sopenharmony_ci break; 9858c2ecf20Sopenharmony_ci default: 9868c2ecf20Sopenharmony_ci bios_connectors[i].hpd.hpd = RADEON_HPD_NONE; 9878c2ecf20Sopenharmony_ci break; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci } else { 9908c2ecf20Sopenharmony_ci if (i == ATOM_DEVICE_DFP1_INDEX) 9918c2ecf20Sopenharmony_ci bios_connectors[i].hpd.hpd = RADEON_HPD_1; 9928c2ecf20Sopenharmony_ci else if (i == ATOM_DEVICE_DFP2_INDEX) 9938c2ecf20Sopenharmony_ci bios_connectors[i].hpd.hpd = RADEON_HPD_2; 9948c2ecf20Sopenharmony_ci else 9958c2ecf20Sopenharmony_ci bios_connectors[i].hpd.hpd = RADEON_HPD_NONE; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* Always set the connector type to VGA for CRT1/CRT2. if they are 9998c2ecf20Sopenharmony_ci * shared with a DVI port, we'll pick up the DVI connector when we 10008c2ecf20Sopenharmony_ci * merge the outputs. Some bioses incorrectly list VGA ports as DVI. 10018c2ecf20Sopenharmony_ci */ 10028c2ecf20Sopenharmony_ci if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) 10038c2ecf20Sopenharmony_ci bios_connectors[i].connector_type = 10048c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_VGA; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (!radeon_atom_apply_quirks 10078c2ecf20Sopenharmony_ci (dev, (1 << i), &bios_connectors[i].connector_type, 10088c2ecf20Sopenharmony_ci &bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux, 10098c2ecf20Sopenharmony_ci &bios_connectors[i].hpd)) 10108c2ecf20Sopenharmony_ci continue; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci bios_connectors[i].valid = true; 10138c2ecf20Sopenharmony_ci bios_connectors[i].devices = (1 << i); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) 10168c2ecf20Sopenharmony_ci radeon_add_atom_encoder(dev, 10178c2ecf20Sopenharmony_ci radeon_get_encoder_enum(dev, 10188c2ecf20Sopenharmony_ci (1 << i), 10198c2ecf20Sopenharmony_ci dac), 10208c2ecf20Sopenharmony_ci (1 << i), 10218c2ecf20Sopenharmony_ci 0); 10228c2ecf20Sopenharmony_ci else 10238c2ecf20Sopenharmony_ci radeon_add_legacy_encoder(dev, 10248c2ecf20Sopenharmony_ci radeon_get_encoder_enum(dev, 10258c2ecf20Sopenharmony_ci (1 << i), 10268c2ecf20Sopenharmony_ci dac), 10278c2ecf20Sopenharmony_ci (1 << i)); 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* combine shared connectors */ 10318c2ecf20Sopenharmony_ci for (i = 0; i < max_device; i++) { 10328c2ecf20Sopenharmony_ci if (bios_connectors[i].valid) { 10338c2ecf20Sopenharmony_ci for (j = 0; j < max_device; j++) { 10348c2ecf20Sopenharmony_ci if (bios_connectors[j].valid && (i != j)) { 10358c2ecf20Sopenharmony_ci if (bios_connectors[i].line_mux == 10368c2ecf20Sopenharmony_ci bios_connectors[j].line_mux) { 10378c2ecf20Sopenharmony_ci /* make sure not to combine LVDS */ 10388c2ecf20Sopenharmony_ci if (bios_connectors[i].devices & (ATOM_DEVICE_LCD_SUPPORT)) { 10398c2ecf20Sopenharmony_ci bios_connectors[i].line_mux = 53; 10408c2ecf20Sopenharmony_ci bios_connectors[i].ddc_bus.valid = false; 10418c2ecf20Sopenharmony_ci continue; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci if (bios_connectors[j].devices & (ATOM_DEVICE_LCD_SUPPORT)) { 10448c2ecf20Sopenharmony_ci bios_connectors[j].line_mux = 53; 10458c2ecf20Sopenharmony_ci bios_connectors[j].ddc_bus.valid = false; 10468c2ecf20Sopenharmony_ci continue; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci /* combine analog and digital for DVI-I */ 10498c2ecf20Sopenharmony_ci if (((bios_connectors[i].devices & (ATOM_DEVICE_DFP_SUPPORT)) && 10508c2ecf20Sopenharmony_ci (bios_connectors[j].devices & (ATOM_DEVICE_CRT_SUPPORT))) || 10518c2ecf20Sopenharmony_ci ((bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT)) && 10528c2ecf20Sopenharmony_ci (bios_connectors[i].devices & (ATOM_DEVICE_CRT_SUPPORT)))) { 10538c2ecf20Sopenharmony_ci bios_connectors[i].devices |= 10548c2ecf20Sopenharmony_ci bios_connectors[j].devices; 10558c2ecf20Sopenharmony_ci bios_connectors[i].connector_type = 10568c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_DVII; 10578c2ecf20Sopenharmony_ci if (bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT)) 10588c2ecf20Sopenharmony_ci bios_connectors[i].hpd = 10598c2ecf20Sopenharmony_ci bios_connectors[j].hpd; 10608c2ecf20Sopenharmony_ci bios_connectors[j].valid = false; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* add the connectors */ 10698c2ecf20Sopenharmony_ci for (i = 0; i < max_device; i++) { 10708c2ecf20Sopenharmony_ci if (bios_connectors[i].valid) { 10718c2ecf20Sopenharmony_ci uint16_t connector_object_id = 10728c2ecf20Sopenharmony_ci atombios_get_connector_object_id(dev, 10738c2ecf20Sopenharmony_ci bios_connectors[i].connector_type, 10748c2ecf20Sopenharmony_ci bios_connectors[i].devices); 10758c2ecf20Sopenharmony_ci radeon_add_atom_connector(dev, 10768c2ecf20Sopenharmony_ci bios_connectors[i].line_mux, 10778c2ecf20Sopenharmony_ci bios_connectors[i].devices, 10788c2ecf20Sopenharmony_ci bios_connectors[i]. 10798c2ecf20Sopenharmony_ci connector_type, 10808c2ecf20Sopenharmony_ci &bios_connectors[i].ddc_bus, 10818c2ecf20Sopenharmony_ci 0, 10828c2ecf20Sopenharmony_ci connector_object_id, 10838c2ecf20Sopenharmony_ci &bios_connectors[i].hpd, 10848c2ecf20Sopenharmony_ci &router); 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci radeon_link_encoder_connector(dev); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci kfree(bios_connectors); 10918c2ecf20Sopenharmony_ci return true; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ciunion firmware_info { 10958c2ecf20Sopenharmony_ci ATOM_FIRMWARE_INFO info; 10968c2ecf20Sopenharmony_ci ATOM_FIRMWARE_INFO_V1_2 info_12; 10978c2ecf20Sopenharmony_ci ATOM_FIRMWARE_INFO_V1_3 info_13; 10988c2ecf20Sopenharmony_ci ATOM_FIRMWARE_INFO_V1_4 info_14; 10998c2ecf20Sopenharmony_ci ATOM_FIRMWARE_INFO_V2_1 info_21; 11008c2ecf20Sopenharmony_ci ATOM_FIRMWARE_INFO_V2_2 info_22; 11018c2ecf20Sopenharmony_ci}; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ciunion igp_info { 11048c2ecf20Sopenharmony_ci struct _ATOM_INTEGRATED_SYSTEM_INFO info; 11058c2ecf20Sopenharmony_ci struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; 11068c2ecf20Sopenharmony_ci struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; 11078c2ecf20Sopenharmony_ci struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; 11088c2ecf20Sopenharmony_ci struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; 11098c2ecf20Sopenharmony_ci}; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic void radeon_atombios_get_dentist_vco_freq(struct radeon_device *rdev) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 11148c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 11158c2ecf20Sopenharmony_ci union igp_info *igp_info; 11168c2ecf20Sopenharmony_ci u8 frev, crev; 11178c2ecf20Sopenharmony_ci u16 data_offset; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 11208c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 11218c2ecf20Sopenharmony_ci igp_info = (union igp_info *)(mode_info->atom_context->bios + 11228c2ecf20Sopenharmony_ci data_offset); 11238c2ecf20Sopenharmony_ci rdev->clock.vco_freq = 11248c2ecf20Sopenharmony_ci le32_to_cpu(igp_info->info_6.ulDentistVCOFreq); 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cibool radeon_atom_get_clock_info(struct drm_device *dev) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 11318c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 11328c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); 11338c2ecf20Sopenharmony_ci union firmware_info *firmware_info; 11348c2ecf20Sopenharmony_ci uint8_t frev, crev; 11358c2ecf20Sopenharmony_ci struct radeon_pll *p1pll = &rdev->clock.p1pll; 11368c2ecf20Sopenharmony_ci struct radeon_pll *p2pll = &rdev->clock.p2pll; 11378c2ecf20Sopenharmony_ci struct radeon_pll *dcpll = &rdev->clock.dcpll; 11388c2ecf20Sopenharmony_ci struct radeon_pll *spll = &rdev->clock.spll; 11398c2ecf20Sopenharmony_ci struct radeon_pll *mpll = &rdev->clock.mpll; 11408c2ecf20Sopenharmony_ci uint16_t data_offset; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 11438c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 11448c2ecf20Sopenharmony_ci firmware_info = 11458c2ecf20Sopenharmony_ci (union firmware_info *)(mode_info->atom_context->bios + 11468c2ecf20Sopenharmony_ci data_offset); 11478c2ecf20Sopenharmony_ci /* pixel clocks */ 11488c2ecf20Sopenharmony_ci p1pll->reference_freq = 11498c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usReferenceClock); 11508c2ecf20Sopenharmony_ci p1pll->reference_div = 0; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if ((frev < 2) && (crev < 2)) 11538c2ecf20Sopenharmony_ci p1pll->pll_out_min = 11548c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); 11558c2ecf20Sopenharmony_ci else 11568c2ecf20Sopenharmony_ci p1pll->pll_out_min = 11578c2ecf20Sopenharmony_ci le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output); 11588c2ecf20Sopenharmony_ci p1pll->pll_out_max = 11598c2ecf20Sopenharmony_ci le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (((frev < 2) && (crev >= 4)) || (frev >= 2)) { 11628c2ecf20Sopenharmony_ci p1pll->lcd_pll_out_min = 11638c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100; 11648c2ecf20Sopenharmony_ci if (p1pll->lcd_pll_out_min == 0) 11658c2ecf20Sopenharmony_ci p1pll->lcd_pll_out_min = p1pll->pll_out_min; 11668c2ecf20Sopenharmony_ci p1pll->lcd_pll_out_max = 11678c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100; 11688c2ecf20Sopenharmony_ci if (p1pll->lcd_pll_out_max == 0) 11698c2ecf20Sopenharmony_ci p1pll->lcd_pll_out_max = p1pll->pll_out_max; 11708c2ecf20Sopenharmony_ci } else { 11718c2ecf20Sopenharmony_ci p1pll->lcd_pll_out_min = p1pll->pll_out_min; 11728c2ecf20Sopenharmony_ci p1pll->lcd_pll_out_max = p1pll->pll_out_max; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci if (p1pll->pll_out_min == 0) { 11768c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) 11778c2ecf20Sopenharmony_ci p1pll->pll_out_min = 64800; 11788c2ecf20Sopenharmony_ci else 11798c2ecf20Sopenharmony_ci p1pll->pll_out_min = 20000; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci p1pll->pll_in_min = 11838c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input); 11848c2ecf20Sopenharmony_ci p1pll->pll_in_max = 11858c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci *p2pll = *p1pll; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* system clock */ 11908c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 11918c2ecf20Sopenharmony_ci spll->reference_freq = 11928c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info_21.usCoreReferenceClock); 11938c2ecf20Sopenharmony_ci else 11948c2ecf20Sopenharmony_ci spll->reference_freq = 11958c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usReferenceClock); 11968c2ecf20Sopenharmony_ci spll->reference_div = 0; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci spll->pll_out_min = 11998c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output); 12008c2ecf20Sopenharmony_ci spll->pll_out_max = 12018c2ecf20Sopenharmony_ci le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci /* ??? */ 12048c2ecf20Sopenharmony_ci if (spll->pll_out_min == 0) { 12058c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) 12068c2ecf20Sopenharmony_ci spll->pll_out_min = 64800; 12078c2ecf20Sopenharmony_ci else 12088c2ecf20Sopenharmony_ci spll->pll_out_min = 20000; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci spll->pll_in_min = 12128c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input); 12138c2ecf20Sopenharmony_ci spll->pll_in_max = 12148c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci /* memory clock */ 12178c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 12188c2ecf20Sopenharmony_ci mpll->reference_freq = 12198c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock); 12208c2ecf20Sopenharmony_ci else 12218c2ecf20Sopenharmony_ci mpll->reference_freq = 12228c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usReferenceClock); 12238c2ecf20Sopenharmony_ci mpll->reference_div = 0; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci mpll->pll_out_min = 12268c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output); 12278c2ecf20Sopenharmony_ci mpll->pll_out_max = 12288c2ecf20Sopenharmony_ci le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* ??? */ 12318c2ecf20Sopenharmony_ci if (mpll->pll_out_min == 0) { 12328c2ecf20Sopenharmony_ci if (ASIC_IS_AVIVO(rdev)) 12338c2ecf20Sopenharmony_ci mpll->pll_out_min = 64800; 12348c2ecf20Sopenharmony_ci else 12358c2ecf20Sopenharmony_ci mpll->pll_out_min = 20000; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci mpll->pll_in_min = 12398c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input); 12408c2ecf20Sopenharmony_ci mpll->pll_in_max = 12418c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci rdev->clock.default_sclk = 12448c2ecf20Sopenharmony_ci le32_to_cpu(firmware_info->info.ulDefaultEngineClock); 12458c2ecf20Sopenharmony_ci rdev->clock.default_mclk = 12468c2ecf20Sopenharmony_ci le32_to_cpu(firmware_info->info.ulDefaultMemoryClock); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) { 12498c2ecf20Sopenharmony_ci rdev->clock.default_dispclk = 12508c2ecf20Sopenharmony_ci le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq); 12518c2ecf20Sopenharmony_ci if (rdev->clock.default_dispclk == 0) { 12528c2ecf20Sopenharmony_ci if (ASIC_IS_DCE6(rdev)) 12538c2ecf20Sopenharmony_ci rdev->clock.default_dispclk = 60000; /* 600 Mhz */ 12548c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE5(rdev)) 12558c2ecf20Sopenharmony_ci rdev->clock.default_dispclk = 54000; /* 540 Mhz */ 12568c2ecf20Sopenharmony_ci else 12578c2ecf20Sopenharmony_ci rdev->clock.default_dispclk = 60000; /* 600 Mhz */ 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci /* set a reasonable default for DP */ 12608c2ecf20Sopenharmony_ci if (ASIC_IS_DCE6(rdev) && (rdev->clock.default_dispclk < 53900)) { 12618c2ecf20Sopenharmony_ci DRM_INFO("Changing default dispclk from %dMhz to 600Mhz\n", 12628c2ecf20Sopenharmony_ci rdev->clock.default_dispclk / 100); 12638c2ecf20Sopenharmony_ci rdev->clock.default_dispclk = 60000; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci rdev->clock.dp_extclk = 12668c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq); 12678c2ecf20Sopenharmony_ci rdev->clock.current_dispclk = rdev->clock.default_dispclk; 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci *dcpll = *p1pll; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci rdev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock); 12728c2ecf20Sopenharmony_ci if (rdev->clock.max_pixel_clock == 0) 12738c2ecf20Sopenharmony_ci rdev->clock.max_pixel_clock = 40000; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* not technically a clock, but... */ 12768c2ecf20Sopenharmony_ci rdev->mode_info.firmware_flags = 12778c2ecf20Sopenharmony_ci le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (ASIC_IS_DCE8(rdev)) 12808c2ecf20Sopenharmony_ci rdev->clock.vco_freq = 12818c2ecf20Sopenharmony_ci le32_to_cpu(firmware_info->info_22.ulGPUPLL_OutputFreq); 12828c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE5(rdev)) 12838c2ecf20Sopenharmony_ci rdev->clock.vco_freq = rdev->clock.current_dispclk; 12848c2ecf20Sopenharmony_ci else if (ASIC_IS_DCE41(rdev)) 12858c2ecf20Sopenharmony_ci radeon_atombios_get_dentist_vco_freq(rdev); 12868c2ecf20Sopenharmony_ci else 12878c2ecf20Sopenharmony_ci rdev->clock.vco_freq = rdev->clock.current_dispclk; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (rdev->clock.vco_freq == 0) 12908c2ecf20Sopenharmony_ci rdev->clock.vco_freq = 360000; /* 3.6 GHz */ 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci return true; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci return false; 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cibool radeon_atombios_sideport_present(struct radeon_device *rdev) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 13018c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 13028c2ecf20Sopenharmony_ci union igp_info *igp_info; 13038c2ecf20Sopenharmony_ci u8 frev, crev; 13048c2ecf20Sopenharmony_ci u16 data_offset; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* sideport is AMD only */ 13078c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RS600) 13088c2ecf20Sopenharmony_ci return false; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 13118c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 13128c2ecf20Sopenharmony_ci igp_info = (union igp_info *)(mode_info->atom_context->bios + 13138c2ecf20Sopenharmony_ci data_offset); 13148c2ecf20Sopenharmony_ci switch (crev) { 13158c2ecf20Sopenharmony_ci case 1: 13168c2ecf20Sopenharmony_ci if (le32_to_cpu(igp_info->info.ulBootUpMemoryClock)) 13178c2ecf20Sopenharmony_ci return true; 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci case 2: 13208c2ecf20Sopenharmony_ci if (le32_to_cpu(igp_info->info_2.ulBootUpSidePortClock)) 13218c2ecf20Sopenharmony_ci return true; 13228c2ecf20Sopenharmony_ci break; 13238c2ecf20Sopenharmony_ci default: 13248c2ecf20Sopenharmony_ci DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); 13258c2ecf20Sopenharmony_ci break; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci return false; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cibool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder, 13328c2ecf20Sopenharmony_ci struct radeon_encoder_int_tmds *tmds) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->base.dev; 13358c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 13368c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 13378c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, TMDS_Info); 13388c2ecf20Sopenharmony_ci uint16_t data_offset; 13398c2ecf20Sopenharmony_ci struct _ATOM_TMDS_INFO *tmds_info; 13408c2ecf20Sopenharmony_ci uint8_t frev, crev; 13418c2ecf20Sopenharmony_ci uint16_t maxfreq; 13428c2ecf20Sopenharmony_ci int i; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 13458c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 13468c2ecf20Sopenharmony_ci tmds_info = 13478c2ecf20Sopenharmony_ci (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios + 13488c2ecf20Sopenharmony_ci data_offset); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci maxfreq = le16_to_cpu(tmds_info->usMaxFrequency); 13518c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 13528c2ecf20Sopenharmony_ci tmds->tmds_pll[i].freq = 13538c2ecf20Sopenharmony_ci le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency); 13548c2ecf20Sopenharmony_ci tmds->tmds_pll[i].value = 13558c2ecf20Sopenharmony_ci tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f; 13568c2ecf20Sopenharmony_ci tmds->tmds_pll[i].value |= 13578c2ecf20Sopenharmony_ci (tmds_info->asMiscInfo[i]. 13588c2ecf20Sopenharmony_ci ucPLL_VCO_Gain & 0x3f) << 6; 13598c2ecf20Sopenharmony_ci tmds->tmds_pll[i].value |= 13608c2ecf20Sopenharmony_ci (tmds_info->asMiscInfo[i]. 13618c2ecf20Sopenharmony_ci ucPLL_DutyCycle & 0xf) << 12; 13628c2ecf20Sopenharmony_ci tmds->tmds_pll[i].value |= 13638c2ecf20Sopenharmony_ci (tmds_info->asMiscInfo[i]. 13648c2ecf20Sopenharmony_ci ucPLL_VoltageSwing & 0xf) << 16; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("TMDS PLL From ATOMBIOS %u %x\n", 13678c2ecf20Sopenharmony_ci tmds->tmds_pll[i].freq, 13688c2ecf20Sopenharmony_ci tmds->tmds_pll[i].value); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (maxfreq == tmds->tmds_pll[i].freq) { 13718c2ecf20Sopenharmony_ci tmds->tmds_pll[i].freq = 0xffffffff; 13728c2ecf20Sopenharmony_ci break; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci return true; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci return false; 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cibool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev, 13818c2ecf20Sopenharmony_ci struct radeon_atom_ss *ss, 13828c2ecf20Sopenharmony_ci int id) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 13858c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info); 13868c2ecf20Sopenharmony_ci uint16_t data_offset, size; 13878c2ecf20Sopenharmony_ci struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info; 13888c2ecf20Sopenharmony_ci struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT *ss_assign; 13898c2ecf20Sopenharmony_ci uint8_t frev, crev; 13908c2ecf20Sopenharmony_ci int i, num_indices; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci memset(ss, 0, sizeof(struct radeon_atom_ss)); 13938c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, &size, 13948c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 13958c2ecf20Sopenharmony_ci ss_info = 13968c2ecf20Sopenharmony_ci (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 13998c2ecf20Sopenharmony_ci sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT); 14008c2ecf20Sopenharmony_ci ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT*) 14018c2ecf20Sopenharmony_ci ((u8 *)&ss_info->asSS_Info[0]); 14028c2ecf20Sopenharmony_ci for (i = 0; i < num_indices; i++) { 14038c2ecf20Sopenharmony_ci if (ss_assign->ucSS_Id == id) { 14048c2ecf20Sopenharmony_ci ss->percentage = 14058c2ecf20Sopenharmony_ci le16_to_cpu(ss_assign->usSpreadSpectrumPercentage); 14068c2ecf20Sopenharmony_ci ss->type = ss_assign->ucSpreadSpectrumType; 14078c2ecf20Sopenharmony_ci ss->step = ss_assign->ucSS_Step; 14088c2ecf20Sopenharmony_ci ss->delay = ss_assign->ucSS_Delay; 14098c2ecf20Sopenharmony_ci ss->range = ss_assign->ucSS_Range; 14108c2ecf20Sopenharmony_ci ss->refdiv = ss_assign->ucRecommendedRef_Div; 14118c2ecf20Sopenharmony_ci return true; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT*) 14148c2ecf20Sopenharmony_ci ((u8 *)ss_assign + sizeof(struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT)); 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci return false; 14188c2ecf20Sopenharmony_ci} 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev, 14218c2ecf20Sopenharmony_ci struct radeon_atom_ss *ss, 14228c2ecf20Sopenharmony_ci int id) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 14258c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 14268c2ecf20Sopenharmony_ci u16 data_offset, size; 14278c2ecf20Sopenharmony_ci union igp_info *igp_info; 14288c2ecf20Sopenharmony_ci u8 frev, crev; 14298c2ecf20Sopenharmony_ci u16 percentage = 0, rate = 0; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* get any igp specific overrides */ 14328c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, &size, 14338c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 14348c2ecf20Sopenharmony_ci igp_info = (union igp_info *) 14358c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset); 14368c2ecf20Sopenharmony_ci switch (crev) { 14378c2ecf20Sopenharmony_ci case 6: 14388c2ecf20Sopenharmony_ci switch (id) { 14398c2ecf20Sopenharmony_ci case ASIC_INTERNAL_SS_ON_TMDS: 14408c2ecf20Sopenharmony_ci percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage); 14418c2ecf20Sopenharmony_ci rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz); 14428c2ecf20Sopenharmony_ci break; 14438c2ecf20Sopenharmony_ci case ASIC_INTERNAL_SS_ON_HDMI: 14448c2ecf20Sopenharmony_ci percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage); 14458c2ecf20Sopenharmony_ci rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz); 14468c2ecf20Sopenharmony_ci break; 14478c2ecf20Sopenharmony_ci case ASIC_INTERNAL_SS_ON_LVDS: 14488c2ecf20Sopenharmony_ci percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage); 14498c2ecf20Sopenharmony_ci rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz); 14508c2ecf20Sopenharmony_ci break; 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci break; 14538c2ecf20Sopenharmony_ci case 7: 14548c2ecf20Sopenharmony_ci switch (id) { 14558c2ecf20Sopenharmony_ci case ASIC_INTERNAL_SS_ON_TMDS: 14568c2ecf20Sopenharmony_ci percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage); 14578c2ecf20Sopenharmony_ci rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz); 14588c2ecf20Sopenharmony_ci break; 14598c2ecf20Sopenharmony_ci case ASIC_INTERNAL_SS_ON_HDMI: 14608c2ecf20Sopenharmony_ci percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage); 14618c2ecf20Sopenharmony_ci rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz); 14628c2ecf20Sopenharmony_ci break; 14638c2ecf20Sopenharmony_ci case ASIC_INTERNAL_SS_ON_LVDS: 14648c2ecf20Sopenharmony_ci percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage); 14658c2ecf20Sopenharmony_ci rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz); 14668c2ecf20Sopenharmony_ci break; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci break; 14698c2ecf20Sopenharmony_ci case 8: 14708c2ecf20Sopenharmony_ci switch (id) { 14718c2ecf20Sopenharmony_ci case ASIC_INTERNAL_SS_ON_TMDS: 14728c2ecf20Sopenharmony_ci percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage); 14738c2ecf20Sopenharmony_ci rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz); 14748c2ecf20Sopenharmony_ci break; 14758c2ecf20Sopenharmony_ci case ASIC_INTERNAL_SS_ON_HDMI: 14768c2ecf20Sopenharmony_ci percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage); 14778c2ecf20Sopenharmony_ci rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz); 14788c2ecf20Sopenharmony_ci break; 14798c2ecf20Sopenharmony_ci case ASIC_INTERNAL_SS_ON_LVDS: 14808c2ecf20Sopenharmony_ci percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage); 14818c2ecf20Sopenharmony_ci rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz); 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci break; 14858c2ecf20Sopenharmony_ci default: 14868c2ecf20Sopenharmony_ci DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); 14878c2ecf20Sopenharmony_ci break; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci if (percentage) 14908c2ecf20Sopenharmony_ci ss->percentage = percentage; 14918c2ecf20Sopenharmony_ci if (rate) 14928c2ecf20Sopenharmony_ci ss->rate = rate; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ciunion asic_ss_info { 14978c2ecf20Sopenharmony_ci struct _ATOM_ASIC_INTERNAL_SS_INFO info; 14988c2ecf20Sopenharmony_ci struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2; 14998c2ecf20Sopenharmony_ci struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3; 15008c2ecf20Sopenharmony_ci}; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ciunion asic_ss_assignment { 15038c2ecf20Sopenharmony_ci struct _ATOM_ASIC_SS_ASSIGNMENT v1; 15048c2ecf20Sopenharmony_ci struct _ATOM_ASIC_SS_ASSIGNMENT_V2 v2; 15058c2ecf20Sopenharmony_ci struct _ATOM_ASIC_SS_ASSIGNMENT_V3 v3; 15068c2ecf20Sopenharmony_ci}; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_cibool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev, 15098c2ecf20Sopenharmony_ci struct radeon_atom_ss *ss, 15108c2ecf20Sopenharmony_ci int id, u32 clock) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 15138c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); 15148c2ecf20Sopenharmony_ci uint16_t data_offset, size; 15158c2ecf20Sopenharmony_ci union asic_ss_info *ss_info; 15168c2ecf20Sopenharmony_ci union asic_ss_assignment *ss_assign; 15178c2ecf20Sopenharmony_ci uint8_t frev, crev; 15188c2ecf20Sopenharmony_ci int i, num_indices; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci if (id == ASIC_INTERNAL_MEMORY_SS) { 15218c2ecf20Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT)) 15228c2ecf20Sopenharmony_ci return false; 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci if (id == ASIC_INTERNAL_ENGINE_SS) { 15258c2ecf20Sopenharmony_ci if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT)) 15268c2ecf20Sopenharmony_ci return false; 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci memset(ss, 0, sizeof(struct radeon_atom_ss)); 15308c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, &size, 15318c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci ss_info = 15348c2ecf20Sopenharmony_ci (union asic_ss_info *)(mode_info->atom_context->bios + data_offset); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci switch (frev) { 15378c2ecf20Sopenharmony_ci case 1: 15388c2ecf20Sopenharmony_ci num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 15398c2ecf20Sopenharmony_ci sizeof(ATOM_ASIC_SS_ASSIGNMENT); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info.asSpreadSpectrum[0]); 15428c2ecf20Sopenharmony_ci for (i = 0; i < num_indices; i++) { 15438c2ecf20Sopenharmony_ci if ((ss_assign->v1.ucClockIndication == id) && 15448c2ecf20Sopenharmony_ci (clock <= le32_to_cpu(ss_assign->v1.ulTargetClockRange))) { 15458c2ecf20Sopenharmony_ci ss->percentage = 15468c2ecf20Sopenharmony_ci le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage); 15478c2ecf20Sopenharmony_ci ss->type = ss_assign->v1.ucSpreadSpectrumMode; 15488c2ecf20Sopenharmony_ci ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz); 15498c2ecf20Sopenharmony_ci ss->percentage_divider = 100; 15508c2ecf20Sopenharmony_ci return true; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci ss_assign = (union asic_ss_assignment *) 15538c2ecf20Sopenharmony_ci ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT)); 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci break; 15568c2ecf20Sopenharmony_ci case 2: 15578c2ecf20Sopenharmony_ci num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 15588c2ecf20Sopenharmony_ci sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2); 15598c2ecf20Sopenharmony_ci ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_2.asSpreadSpectrum[0]); 15608c2ecf20Sopenharmony_ci for (i = 0; i < num_indices; i++) { 15618c2ecf20Sopenharmony_ci if ((ss_assign->v2.ucClockIndication == id) && 15628c2ecf20Sopenharmony_ci (clock <= le32_to_cpu(ss_assign->v2.ulTargetClockRange))) { 15638c2ecf20Sopenharmony_ci ss->percentage = 15648c2ecf20Sopenharmony_ci le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage); 15658c2ecf20Sopenharmony_ci ss->type = ss_assign->v2.ucSpreadSpectrumMode; 15668c2ecf20Sopenharmony_ci ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz); 15678c2ecf20Sopenharmony_ci ss->percentage_divider = 100; 15688c2ecf20Sopenharmony_ci if ((crev == 2) && 15698c2ecf20Sopenharmony_ci ((id == ASIC_INTERNAL_ENGINE_SS) || 15708c2ecf20Sopenharmony_ci (id == ASIC_INTERNAL_MEMORY_SS))) 15718c2ecf20Sopenharmony_ci ss->rate /= 100; 15728c2ecf20Sopenharmony_ci return true; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci ss_assign = (union asic_ss_assignment *) 15758c2ecf20Sopenharmony_ci ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2)); 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci break; 15788c2ecf20Sopenharmony_ci case 3: 15798c2ecf20Sopenharmony_ci num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 15808c2ecf20Sopenharmony_ci sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3); 15818c2ecf20Sopenharmony_ci ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_3.asSpreadSpectrum[0]); 15828c2ecf20Sopenharmony_ci for (i = 0; i < num_indices; i++) { 15838c2ecf20Sopenharmony_ci if ((ss_assign->v3.ucClockIndication == id) && 15848c2ecf20Sopenharmony_ci (clock <= le32_to_cpu(ss_assign->v3.ulTargetClockRange))) { 15858c2ecf20Sopenharmony_ci ss->percentage = 15868c2ecf20Sopenharmony_ci le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage); 15878c2ecf20Sopenharmony_ci ss->type = ss_assign->v3.ucSpreadSpectrumMode; 15888c2ecf20Sopenharmony_ci ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz); 15898c2ecf20Sopenharmony_ci if (ss_assign->v3.ucSpreadSpectrumMode & 15908c2ecf20Sopenharmony_ci SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK) 15918c2ecf20Sopenharmony_ci ss->percentage_divider = 1000; 15928c2ecf20Sopenharmony_ci else 15938c2ecf20Sopenharmony_ci ss->percentage_divider = 100; 15948c2ecf20Sopenharmony_ci if ((id == ASIC_INTERNAL_ENGINE_SS) || 15958c2ecf20Sopenharmony_ci (id == ASIC_INTERNAL_MEMORY_SS)) 15968c2ecf20Sopenharmony_ci ss->rate /= 100; 15978c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) 15988c2ecf20Sopenharmony_ci radeon_atombios_get_igp_ss_overrides(rdev, ss, id); 15998c2ecf20Sopenharmony_ci return true; 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci ss_assign = (union asic_ss_assignment *) 16028c2ecf20Sopenharmony_ci ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3)); 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci break; 16058c2ecf20Sopenharmony_ci default: 16068c2ecf20Sopenharmony_ci DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev); 16078c2ecf20Sopenharmony_ci break; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci return false; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ciunion lvds_info { 16158c2ecf20Sopenharmony_ci struct _ATOM_LVDS_INFO info; 16168c2ecf20Sopenharmony_ci struct _ATOM_LVDS_INFO_V12 info_12; 16178c2ecf20Sopenharmony_ci}; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cistruct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct 16208c2ecf20Sopenharmony_ci radeon_encoder 16218c2ecf20Sopenharmony_ci *encoder) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->base.dev; 16248c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 16258c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 16268c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, LVDS_Info); 16278c2ecf20Sopenharmony_ci uint16_t data_offset, misc; 16288c2ecf20Sopenharmony_ci union lvds_info *lvds_info; 16298c2ecf20Sopenharmony_ci uint8_t frev, crev; 16308c2ecf20Sopenharmony_ci struct radeon_encoder_atom_dig *lvds = NULL; 16318c2ecf20Sopenharmony_ci int encoder_enum = (encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 16348c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 16358c2ecf20Sopenharmony_ci lvds_info = 16368c2ecf20Sopenharmony_ci (union lvds_info *)(mode_info->atom_context->bios + data_offset); 16378c2ecf20Sopenharmony_ci lvds = 16388c2ecf20Sopenharmony_ci kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci if (!lvds) 16418c2ecf20Sopenharmony_ci return NULL; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci lvds->native_mode.clock = 16448c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10; 16458c2ecf20Sopenharmony_ci lvds->native_mode.hdisplay = 16468c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.sLCDTiming.usHActive); 16478c2ecf20Sopenharmony_ci lvds->native_mode.vdisplay = 16488c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.sLCDTiming.usVActive); 16498c2ecf20Sopenharmony_ci lvds->native_mode.htotal = lvds->native_mode.hdisplay + 16508c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time); 16518c2ecf20Sopenharmony_ci lvds->native_mode.hsync_start = lvds->native_mode.hdisplay + 16528c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset); 16538c2ecf20Sopenharmony_ci lvds->native_mode.hsync_end = lvds->native_mode.hsync_start + 16548c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth); 16558c2ecf20Sopenharmony_ci lvds->native_mode.vtotal = lvds->native_mode.vdisplay + 16568c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); 16578c2ecf20Sopenharmony_ci lvds->native_mode.vsync_start = lvds->native_mode.vdisplay + 16588c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); 16598c2ecf20Sopenharmony_ci lvds->native_mode.vsync_end = lvds->native_mode.vsync_start + 16608c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); 16618c2ecf20Sopenharmony_ci lvds->panel_pwr_delay = 16628c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.usOffDelayInMs); 16638c2ecf20Sopenharmony_ci lvds->lcd_misc = lvds_info->info.ucLVDS_Misc; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess); 16668c2ecf20Sopenharmony_ci if (misc & ATOM_VSYNC_POLARITY) 16678c2ecf20Sopenharmony_ci lvds->native_mode.flags |= DRM_MODE_FLAG_NVSYNC; 16688c2ecf20Sopenharmony_ci if (misc & ATOM_HSYNC_POLARITY) 16698c2ecf20Sopenharmony_ci lvds->native_mode.flags |= DRM_MODE_FLAG_NHSYNC; 16708c2ecf20Sopenharmony_ci if (misc & ATOM_COMPOSITESYNC) 16718c2ecf20Sopenharmony_ci lvds->native_mode.flags |= DRM_MODE_FLAG_CSYNC; 16728c2ecf20Sopenharmony_ci if (misc & ATOM_INTERLACE) 16738c2ecf20Sopenharmony_ci lvds->native_mode.flags |= DRM_MODE_FLAG_INTERLACE; 16748c2ecf20Sopenharmony_ci if (misc & ATOM_DOUBLE_CLOCK_MODE) 16758c2ecf20Sopenharmony_ci lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize); 16788c2ecf20Sopenharmony_ci lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci /* set crtc values */ 16818c2ecf20Sopenharmony_ci drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci lvds->lcd_ss_id = lvds_info->info.ucSS_Id; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci encoder->native_mode = lvds->native_mode; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci if (encoder_enum == 2) 16888c2ecf20Sopenharmony_ci lvds->linkb = true; 16898c2ecf20Sopenharmony_ci else 16908c2ecf20Sopenharmony_ci lvds->linkb = false; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci /* parse the lcd record table */ 16938c2ecf20Sopenharmony_ci if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) { 16948c2ecf20Sopenharmony_ci ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; 16958c2ecf20Sopenharmony_ci ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; 16968c2ecf20Sopenharmony_ci bool bad_record = false; 16978c2ecf20Sopenharmony_ci u8 *record; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci if ((frev == 1) && (crev < 2)) 17008c2ecf20Sopenharmony_ci /* absolute */ 17018c2ecf20Sopenharmony_ci record = (u8 *)(mode_info->atom_context->bios + 17028c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.usModePatchTableOffset)); 17038c2ecf20Sopenharmony_ci else 17048c2ecf20Sopenharmony_ci /* relative */ 17058c2ecf20Sopenharmony_ci record = (u8 *)(mode_info->atom_context->bios + 17068c2ecf20Sopenharmony_ci data_offset + 17078c2ecf20Sopenharmony_ci le16_to_cpu(lvds_info->info.usModePatchTableOffset)); 17088c2ecf20Sopenharmony_ci while (*record != ATOM_RECORD_END_TYPE) { 17098c2ecf20Sopenharmony_ci switch (*record) { 17108c2ecf20Sopenharmony_ci case LCD_MODE_PATCH_RECORD_MODE_TYPE: 17118c2ecf20Sopenharmony_ci record += sizeof(ATOM_PATCH_RECORD_MODE); 17128c2ecf20Sopenharmony_ci break; 17138c2ecf20Sopenharmony_ci case LCD_RTS_RECORD_TYPE: 17148c2ecf20Sopenharmony_ci record += sizeof(ATOM_LCD_RTS_RECORD); 17158c2ecf20Sopenharmony_ci break; 17168c2ecf20Sopenharmony_ci case LCD_CAP_RECORD_TYPE: 17178c2ecf20Sopenharmony_ci record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); 17188c2ecf20Sopenharmony_ci break; 17198c2ecf20Sopenharmony_ci case LCD_FAKE_EDID_PATCH_RECORD_TYPE: 17208c2ecf20Sopenharmony_ci fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; 17218c2ecf20Sopenharmony_ci if (fake_edid_record->ucFakeEDIDLength) { 17228c2ecf20Sopenharmony_ci struct edid *edid; 17238c2ecf20Sopenharmony_ci int edid_size = 17248c2ecf20Sopenharmony_ci max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength); 17258c2ecf20Sopenharmony_ci edid = kmalloc(edid_size, GFP_KERNEL); 17268c2ecf20Sopenharmony_ci if (edid) { 17278c2ecf20Sopenharmony_ci memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], 17288c2ecf20Sopenharmony_ci fake_edid_record->ucFakeEDIDLength); 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (drm_edid_is_valid(edid)) { 17318c2ecf20Sopenharmony_ci rdev->mode_info.bios_hardcoded_edid = edid; 17328c2ecf20Sopenharmony_ci rdev->mode_info.bios_hardcoded_edid_size = edid_size; 17338c2ecf20Sopenharmony_ci } else 17348c2ecf20Sopenharmony_ci kfree(edid); 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci record += fake_edid_record->ucFakeEDIDLength ? 17388c2ecf20Sopenharmony_ci fake_edid_record->ucFakeEDIDLength + 2 : 17398c2ecf20Sopenharmony_ci sizeof(ATOM_FAKE_EDID_PATCH_RECORD); 17408c2ecf20Sopenharmony_ci break; 17418c2ecf20Sopenharmony_ci case LCD_PANEL_RESOLUTION_RECORD_TYPE: 17428c2ecf20Sopenharmony_ci panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; 17438c2ecf20Sopenharmony_ci lvds->native_mode.width_mm = panel_res_record->usHSize; 17448c2ecf20Sopenharmony_ci lvds->native_mode.height_mm = panel_res_record->usVSize; 17458c2ecf20Sopenharmony_ci record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); 17468c2ecf20Sopenharmony_ci break; 17478c2ecf20Sopenharmony_ci default: 17488c2ecf20Sopenharmony_ci DRM_ERROR("Bad LCD record %d\n", *record); 17498c2ecf20Sopenharmony_ci bad_record = true; 17508c2ecf20Sopenharmony_ci break; 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci if (bad_record) 17538c2ecf20Sopenharmony_ci break; 17548c2ecf20Sopenharmony_ci } 17558c2ecf20Sopenharmony_ci } 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci return lvds; 17588c2ecf20Sopenharmony_ci} 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_cistruct radeon_encoder_primary_dac * 17618c2ecf20Sopenharmony_ciradeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->base.dev; 17648c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 17658c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 17668c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, CompassionateData); 17678c2ecf20Sopenharmony_ci uint16_t data_offset; 17688c2ecf20Sopenharmony_ci struct _COMPASSIONATE_DATA *dac_info; 17698c2ecf20Sopenharmony_ci uint8_t frev, crev; 17708c2ecf20Sopenharmony_ci uint8_t bg, dac; 17718c2ecf20Sopenharmony_ci struct radeon_encoder_primary_dac *p_dac = NULL; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 17748c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 17758c2ecf20Sopenharmony_ci dac_info = (struct _COMPASSIONATE_DATA *) 17768c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset); 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), GFP_KERNEL); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci if (!p_dac) 17818c2ecf20Sopenharmony_ci return NULL; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci bg = dac_info->ucDAC1_BG_Adjustment; 17848c2ecf20Sopenharmony_ci dac = dac_info->ucDAC1_DAC_Adjustment; 17858c2ecf20Sopenharmony_ci p_dac->ps2_pdac_adj = (bg << 8) | (dac); 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci return p_dac; 17898c2ecf20Sopenharmony_ci} 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_cibool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, 17928c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 17938c2ecf20Sopenharmony_ci{ 17948c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 17958c2ecf20Sopenharmony_ci ATOM_ANALOG_TV_INFO *tv_info; 17968c2ecf20Sopenharmony_ci ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2; 17978c2ecf20Sopenharmony_ci ATOM_DTD_FORMAT *dtd_timings; 17988c2ecf20Sopenharmony_ci int data_index = GetIndexIntoMasterTable(DATA, AnalogTV_Info); 17998c2ecf20Sopenharmony_ci u8 frev, crev; 18008c2ecf20Sopenharmony_ci u16 data_offset, misc; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci if (!atom_parse_data_header(mode_info->atom_context, data_index, NULL, 18038c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) 18048c2ecf20Sopenharmony_ci return false; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci switch (crev) { 18078c2ecf20Sopenharmony_ci case 1: 18088c2ecf20Sopenharmony_ci tv_info = (ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset); 18098c2ecf20Sopenharmony_ci if (index >= MAX_SUPPORTED_TV_TIMING) 18108c2ecf20Sopenharmony_ci return false; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci mode->crtc_htotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total); 18138c2ecf20Sopenharmony_ci mode->crtc_hdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp); 18148c2ecf20Sopenharmony_ci mode->crtc_hsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart); 18158c2ecf20Sopenharmony_ci mode->crtc_hsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) + 18168c2ecf20Sopenharmony_ci le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci mode->crtc_vtotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total); 18198c2ecf20Sopenharmony_ci mode->crtc_vdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp); 18208c2ecf20Sopenharmony_ci mode->crtc_vsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart); 18218c2ecf20Sopenharmony_ci mode->crtc_vsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) + 18228c2ecf20Sopenharmony_ci le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth); 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci mode->flags = 0; 18258c2ecf20Sopenharmony_ci misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess); 18268c2ecf20Sopenharmony_ci if (misc & ATOM_VSYNC_POLARITY) 18278c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_NVSYNC; 18288c2ecf20Sopenharmony_ci if (misc & ATOM_HSYNC_POLARITY) 18298c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_NHSYNC; 18308c2ecf20Sopenharmony_ci if (misc & ATOM_COMPOSITESYNC) 18318c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_CSYNC; 18328c2ecf20Sopenharmony_ci if (misc & ATOM_INTERLACE) 18338c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_INTERLACE; 18348c2ecf20Sopenharmony_ci if (misc & ATOM_DOUBLE_CLOCK_MODE) 18358c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_DBLSCAN; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci mode->crtc_clock = mode->clock = 18388c2ecf20Sopenharmony_ci le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (index == 1) { 18418c2ecf20Sopenharmony_ci /* PAL timings appear to have wrong values for totals */ 18428c2ecf20Sopenharmony_ci mode->crtc_htotal -= 1; 18438c2ecf20Sopenharmony_ci mode->crtc_vtotal -= 1; 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci break; 18468c2ecf20Sopenharmony_ci case 2: 18478c2ecf20Sopenharmony_ci tv_info_v1_2 = (ATOM_ANALOG_TV_INFO_V1_2 *)(mode_info->atom_context->bios + data_offset); 18488c2ecf20Sopenharmony_ci if (index >= MAX_SUPPORTED_TV_TIMING_V1_2) 18498c2ecf20Sopenharmony_ci return false; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci dtd_timings = &tv_info_v1_2->aModeTimings[index]; 18528c2ecf20Sopenharmony_ci mode->crtc_htotal = le16_to_cpu(dtd_timings->usHActive) + 18538c2ecf20Sopenharmony_ci le16_to_cpu(dtd_timings->usHBlanking_Time); 18548c2ecf20Sopenharmony_ci mode->crtc_hdisplay = le16_to_cpu(dtd_timings->usHActive); 18558c2ecf20Sopenharmony_ci mode->crtc_hsync_start = le16_to_cpu(dtd_timings->usHActive) + 18568c2ecf20Sopenharmony_ci le16_to_cpu(dtd_timings->usHSyncOffset); 18578c2ecf20Sopenharmony_ci mode->crtc_hsync_end = mode->crtc_hsync_start + 18588c2ecf20Sopenharmony_ci le16_to_cpu(dtd_timings->usHSyncWidth); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci mode->crtc_vtotal = le16_to_cpu(dtd_timings->usVActive) + 18618c2ecf20Sopenharmony_ci le16_to_cpu(dtd_timings->usVBlanking_Time); 18628c2ecf20Sopenharmony_ci mode->crtc_vdisplay = le16_to_cpu(dtd_timings->usVActive); 18638c2ecf20Sopenharmony_ci mode->crtc_vsync_start = le16_to_cpu(dtd_timings->usVActive) + 18648c2ecf20Sopenharmony_ci le16_to_cpu(dtd_timings->usVSyncOffset); 18658c2ecf20Sopenharmony_ci mode->crtc_vsync_end = mode->crtc_vsync_start + 18668c2ecf20Sopenharmony_ci le16_to_cpu(dtd_timings->usVSyncWidth); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci mode->flags = 0; 18698c2ecf20Sopenharmony_ci misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess); 18708c2ecf20Sopenharmony_ci if (misc & ATOM_VSYNC_POLARITY) 18718c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_NVSYNC; 18728c2ecf20Sopenharmony_ci if (misc & ATOM_HSYNC_POLARITY) 18738c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_NHSYNC; 18748c2ecf20Sopenharmony_ci if (misc & ATOM_COMPOSITESYNC) 18758c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_CSYNC; 18768c2ecf20Sopenharmony_ci if (misc & ATOM_INTERLACE) 18778c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_INTERLACE; 18788c2ecf20Sopenharmony_ci if (misc & ATOM_DOUBLE_CLOCK_MODE) 18798c2ecf20Sopenharmony_ci mode->flags |= DRM_MODE_FLAG_DBLSCAN; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci mode->crtc_clock = mode->clock = 18828c2ecf20Sopenharmony_ci le16_to_cpu(dtd_timings->usPixClk) * 10; 18838c2ecf20Sopenharmony_ci break; 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci return true; 18868c2ecf20Sopenharmony_ci} 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_cienum radeon_tv_std 18898c2ecf20Sopenharmony_ciradeon_atombios_get_tv_info(struct radeon_device *rdev) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 18928c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, AnalogTV_Info); 18938c2ecf20Sopenharmony_ci uint16_t data_offset; 18948c2ecf20Sopenharmony_ci uint8_t frev, crev; 18958c2ecf20Sopenharmony_ci struct _ATOM_ANALOG_TV_INFO *tv_info; 18968c2ecf20Sopenharmony_ci enum radeon_tv_std tv_std = TV_STD_NTSC; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 18998c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci tv_info = (struct _ATOM_ANALOG_TV_INFO *) 19028c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci switch (tv_info->ucTV_BootUpDefaultStandard) { 19058c2ecf20Sopenharmony_ci case ATOM_TV_NTSC: 19068c2ecf20Sopenharmony_ci tv_std = TV_STD_NTSC; 19078c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Default TV standard: NTSC\n"); 19088c2ecf20Sopenharmony_ci break; 19098c2ecf20Sopenharmony_ci case ATOM_TV_NTSCJ: 19108c2ecf20Sopenharmony_ci tv_std = TV_STD_NTSC_J; 19118c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Default TV standard: NTSC-J\n"); 19128c2ecf20Sopenharmony_ci break; 19138c2ecf20Sopenharmony_ci case ATOM_TV_PAL: 19148c2ecf20Sopenharmony_ci tv_std = TV_STD_PAL; 19158c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Default TV standard: PAL\n"); 19168c2ecf20Sopenharmony_ci break; 19178c2ecf20Sopenharmony_ci case ATOM_TV_PALM: 19188c2ecf20Sopenharmony_ci tv_std = TV_STD_PAL_M; 19198c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Default TV standard: PAL-M\n"); 19208c2ecf20Sopenharmony_ci break; 19218c2ecf20Sopenharmony_ci case ATOM_TV_PALN: 19228c2ecf20Sopenharmony_ci tv_std = TV_STD_PAL_N; 19238c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Default TV standard: PAL-N\n"); 19248c2ecf20Sopenharmony_ci break; 19258c2ecf20Sopenharmony_ci case ATOM_TV_PALCN: 19268c2ecf20Sopenharmony_ci tv_std = TV_STD_PAL_CN; 19278c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Default TV standard: PAL-CN\n"); 19288c2ecf20Sopenharmony_ci break; 19298c2ecf20Sopenharmony_ci case ATOM_TV_PAL60: 19308c2ecf20Sopenharmony_ci tv_std = TV_STD_PAL_60; 19318c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Default TV standard: PAL-60\n"); 19328c2ecf20Sopenharmony_ci break; 19338c2ecf20Sopenharmony_ci case ATOM_TV_SECAM: 19348c2ecf20Sopenharmony_ci tv_std = TV_STD_SECAM; 19358c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Default TV standard: SECAM\n"); 19368c2ecf20Sopenharmony_ci break; 19378c2ecf20Sopenharmony_ci default: 19388c2ecf20Sopenharmony_ci tv_std = TV_STD_NTSC; 19398c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("Unknown TV standard; defaulting to NTSC\n"); 19408c2ecf20Sopenharmony_ci break; 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci return tv_std; 19448c2ecf20Sopenharmony_ci} 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_cistruct radeon_encoder_tv_dac * 19478c2ecf20Sopenharmony_ciradeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) 19488c2ecf20Sopenharmony_ci{ 19498c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->base.dev; 19508c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 19518c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 19528c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, CompassionateData); 19538c2ecf20Sopenharmony_ci uint16_t data_offset; 19548c2ecf20Sopenharmony_ci struct _COMPASSIONATE_DATA *dac_info; 19558c2ecf20Sopenharmony_ci uint8_t frev, crev; 19568c2ecf20Sopenharmony_ci uint8_t bg, dac; 19578c2ecf20Sopenharmony_ci struct radeon_encoder_tv_dac *tv_dac = NULL; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 19608c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci dac_info = (struct _COMPASSIONATE_DATA *) 19638c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci if (!tv_dac) 19688c2ecf20Sopenharmony_ci return NULL; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci bg = dac_info->ucDAC2_CRT2_BG_Adjustment; 19718c2ecf20Sopenharmony_ci dac = dac_info->ucDAC2_CRT2_DAC_Adjustment; 19728c2ecf20Sopenharmony_ci tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20); 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci bg = dac_info->ucDAC2_PAL_BG_Adjustment; 19758c2ecf20Sopenharmony_ci dac = dac_info->ucDAC2_PAL_DAC_Adjustment; 19768c2ecf20Sopenharmony_ci tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20); 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci bg = dac_info->ucDAC2_NTSC_BG_Adjustment; 19798c2ecf20Sopenharmony_ci dac = dac_info->ucDAC2_NTSC_DAC_Adjustment; 19808c2ecf20Sopenharmony_ci tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci tv_dac->tv_std = radeon_atombios_get_tv_info(rdev); 19838c2ecf20Sopenharmony_ci } 19848c2ecf20Sopenharmony_ci return tv_dac; 19858c2ecf20Sopenharmony_ci} 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_cistatic const char *thermal_controller_names[] = { 19888c2ecf20Sopenharmony_ci "NONE", 19898c2ecf20Sopenharmony_ci "lm63", 19908c2ecf20Sopenharmony_ci "adm1032", 19918c2ecf20Sopenharmony_ci "adm1030", 19928c2ecf20Sopenharmony_ci "max6649", 19938c2ecf20Sopenharmony_ci "lm63", /* lm64 */ 19948c2ecf20Sopenharmony_ci "f75375", 19958c2ecf20Sopenharmony_ci "asc7xxx", 19968c2ecf20Sopenharmony_ci}; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_cistatic const char *pp_lib_thermal_controller_names[] = { 19998c2ecf20Sopenharmony_ci "NONE", 20008c2ecf20Sopenharmony_ci "lm63", 20018c2ecf20Sopenharmony_ci "adm1032", 20028c2ecf20Sopenharmony_ci "adm1030", 20038c2ecf20Sopenharmony_ci "max6649", 20048c2ecf20Sopenharmony_ci "lm63", /* lm64 */ 20058c2ecf20Sopenharmony_ci "f75375", 20068c2ecf20Sopenharmony_ci "RV6xx", 20078c2ecf20Sopenharmony_ci "RV770", 20088c2ecf20Sopenharmony_ci "adt7473", 20098c2ecf20Sopenharmony_ci "NONE", 20108c2ecf20Sopenharmony_ci "External GPIO", 20118c2ecf20Sopenharmony_ci "Evergreen", 20128c2ecf20Sopenharmony_ci "emc2103", 20138c2ecf20Sopenharmony_ci "Sumo", 20148c2ecf20Sopenharmony_ci "Northern Islands", 20158c2ecf20Sopenharmony_ci "Southern Islands", 20168c2ecf20Sopenharmony_ci "lm96163", 20178c2ecf20Sopenharmony_ci "Sea Islands", 20188c2ecf20Sopenharmony_ci}; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ciunion power_info { 20218c2ecf20Sopenharmony_ci struct _ATOM_POWERPLAY_INFO info; 20228c2ecf20Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V2 info_2; 20238c2ecf20Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V3 info_3; 20248c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE pplib; 20258c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; 20268c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; 20278c2ecf20Sopenharmony_ci}; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ciunion pplib_clock_info { 20308c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_R600_CLOCK_INFO r600; 20318c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; 20328c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; 20338c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; 20348c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_SI_CLOCK_INFO si; 20358c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_CI_CLOCK_INFO ci; 20368c2ecf20Sopenharmony_ci}; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ciunion pplib_power_state { 20398c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_STATE v1; 20408c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_STATE_V2 v2; 20418c2ecf20Sopenharmony_ci}; 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_cistatic void radeon_atombios_parse_misc_flags_1_3(struct radeon_device *rdev, 20448c2ecf20Sopenharmony_ci int state_index, 20458c2ecf20Sopenharmony_ci u32 misc, u32 misc2) 20468c2ecf20Sopenharmony_ci{ 20478c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].misc = misc; 20488c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].misc2 = misc2; 20498c2ecf20Sopenharmony_ci /* order matters! */ 20508c2ecf20Sopenharmony_ci if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) 20518c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 20528c2ecf20Sopenharmony_ci POWER_STATE_TYPE_POWERSAVE; 20538c2ecf20Sopenharmony_ci if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE) 20548c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 20558c2ecf20Sopenharmony_ci POWER_STATE_TYPE_BATTERY; 20568c2ecf20Sopenharmony_ci if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE) 20578c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 20588c2ecf20Sopenharmony_ci POWER_STATE_TYPE_BATTERY; 20598c2ecf20Sopenharmony_ci if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) 20608c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 20618c2ecf20Sopenharmony_ci POWER_STATE_TYPE_BALANCED; 20628c2ecf20Sopenharmony_ci if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { 20638c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 20648c2ecf20Sopenharmony_ci POWER_STATE_TYPE_PERFORMANCE; 20658c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].flags &= 20668c2ecf20Sopenharmony_ci ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) 20698c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 20708c2ecf20Sopenharmony_ci POWER_STATE_TYPE_BALANCED; 20718c2ecf20Sopenharmony_ci if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { 20728c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 20738c2ecf20Sopenharmony_ci POWER_STATE_TYPE_DEFAULT; 20748c2ecf20Sopenharmony_ci rdev->pm.default_power_state_index = state_index; 20758c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].default_clock_mode = 20768c2ecf20Sopenharmony_ci &rdev->pm.power_state[state_index].clock_info[0]; 20778c2ecf20Sopenharmony_ci } else if (state_index == 0) { 20788c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].flags |= 20798c2ecf20Sopenharmony_ci RADEON_PM_MODE_NO_DISPLAY; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci} 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_cistatic int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) 20848c2ecf20Sopenharmony_ci{ 20858c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 20868c2ecf20Sopenharmony_ci u32 misc, misc2 = 0; 20878c2ecf20Sopenharmony_ci int num_modes = 0, i; 20888c2ecf20Sopenharmony_ci int state_index = 0; 20898c2ecf20Sopenharmony_ci struct radeon_i2c_bus_rec i2c_bus; 20908c2ecf20Sopenharmony_ci union power_info *power_info; 20918c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 20928c2ecf20Sopenharmony_ci u16 data_offset; 20938c2ecf20Sopenharmony_ci u8 frev, crev; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 20968c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) 20978c2ecf20Sopenharmony_ci return state_index; 20988c2ecf20Sopenharmony_ci power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci /* add the i2c bus for thermal/fan chip */ 21018c2ecf20Sopenharmony_ci if ((power_info->info.ucOverdriveThermalController > 0) && 21028c2ecf20Sopenharmony_ci (power_info->info.ucOverdriveThermalController < ARRAY_SIZE(thermal_controller_names))) { 21038c2ecf20Sopenharmony_ci DRM_INFO("Possible %s thermal controller at 0x%02x\n", 21048c2ecf20Sopenharmony_ci thermal_controller_names[power_info->info.ucOverdriveThermalController], 21058c2ecf20Sopenharmony_ci power_info->info.ucOverdriveControllerAddress >> 1); 21068c2ecf20Sopenharmony_ci i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); 21078c2ecf20Sopenharmony_ci rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); 21088c2ecf20Sopenharmony_ci if (rdev->pm.i2c_bus) { 21098c2ecf20Sopenharmony_ci struct i2c_board_info info = { }; 21108c2ecf20Sopenharmony_ci const char *name = thermal_controller_names[power_info->info. 21118c2ecf20Sopenharmony_ci ucOverdriveThermalController]; 21128c2ecf20Sopenharmony_ci info.addr = power_info->info.ucOverdriveControllerAddress >> 1; 21138c2ecf20Sopenharmony_ci strlcpy(info.type, name, sizeof(info.type)); 21148c2ecf20Sopenharmony_ci i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); 21158c2ecf20Sopenharmony_ci } 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci num_modes = power_info->info.ucNumOfPowerModeEntries; 21188c2ecf20Sopenharmony_ci if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) 21198c2ecf20Sopenharmony_ci num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; 21208c2ecf20Sopenharmony_ci if (num_modes == 0) 21218c2ecf20Sopenharmony_ci return state_index; 21228c2ecf20Sopenharmony_ci rdev->pm.power_state = kcalloc(num_modes, 21238c2ecf20Sopenharmony_ci sizeof(struct radeon_power_state), 21248c2ecf20Sopenharmony_ci GFP_KERNEL); 21258c2ecf20Sopenharmony_ci if (!rdev->pm.power_state) 21268c2ecf20Sopenharmony_ci return state_index; 21278c2ecf20Sopenharmony_ci /* last mode is usually default, array is low to high */ 21288c2ecf20Sopenharmony_ci for (i = 0; i < num_modes; i++) { 21298c2ecf20Sopenharmony_ci /* avoid memory leaks from invalid modes or unknown frev. */ 21308c2ecf20Sopenharmony_ci if (!rdev->pm.power_state[state_index].clock_info) { 21318c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info = 21328c2ecf20Sopenharmony_ci kzalloc(sizeof(struct radeon_pm_clock_info), 21338c2ecf20Sopenharmony_ci GFP_KERNEL); 21348c2ecf20Sopenharmony_ci } 21358c2ecf20Sopenharmony_ci if (!rdev->pm.power_state[state_index].clock_info) 21368c2ecf20Sopenharmony_ci goto out; 21378c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].num_clock_modes = 1; 21388c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; 21398c2ecf20Sopenharmony_ci switch (frev) { 21408c2ecf20Sopenharmony_ci case 1: 21418c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].mclk = 21428c2ecf20Sopenharmony_ci le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock); 21438c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].sclk = 21448c2ecf20Sopenharmony_ci le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock); 21458c2ecf20Sopenharmony_ci /* skip invalid modes */ 21468c2ecf20Sopenharmony_ci if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || 21478c2ecf20Sopenharmony_ci (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) 21488c2ecf20Sopenharmony_ci continue; 21498c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].pcie_lanes = 21508c2ecf20Sopenharmony_ci power_info->info.asPowerPlayInfo[i].ucNumPciELanes; 21518c2ecf20Sopenharmony_ci misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); 21528c2ecf20Sopenharmony_ci if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || 21538c2ecf20Sopenharmony_ci (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { 21548c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.type = 21558c2ecf20Sopenharmony_ci VOLTAGE_GPIO; 21568c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = 21578c2ecf20Sopenharmony_ci radeon_atombios_lookup_gpio(rdev, 21588c2ecf20Sopenharmony_ci power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); 21598c2ecf20Sopenharmony_ci if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) 21608c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = 21618c2ecf20Sopenharmony_ci true; 21628c2ecf20Sopenharmony_ci else 21638c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = 21648c2ecf20Sopenharmony_ci false; 21658c2ecf20Sopenharmony_ci } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { 21668c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.type = 21678c2ecf20Sopenharmony_ci VOLTAGE_VDDC; 21688c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = 21698c2ecf20Sopenharmony_ci power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; 21708c2ecf20Sopenharmony_ci } 21718c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; 21728c2ecf20Sopenharmony_ci radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0); 21738c2ecf20Sopenharmony_ci state_index++; 21748c2ecf20Sopenharmony_ci break; 21758c2ecf20Sopenharmony_ci case 2: 21768c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].mclk = 21778c2ecf20Sopenharmony_ci le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock); 21788c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].sclk = 21798c2ecf20Sopenharmony_ci le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock); 21808c2ecf20Sopenharmony_ci /* skip invalid modes */ 21818c2ecf20Sopenharmony_ci if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || 21828c2ecf20Sopenharmony_ci (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) 21838c2ecf20Sopenharmony_ci continue; 21848c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].pcie_lanes = 21858c2ecf20Sopenharmony_ci power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; 21868c2ecf20Sopenharmony_ci misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); 21878c2ecf20Sopenharmony_ci misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); 21888c2ecf20Sopenharmony_ci if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || 21898c2ecf20Sopenharmony_ci (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { 21908c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.type = 21918c2ecf20Sopenharmony_ci VOLTAGE_GPIO; 21928c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = 21938c2ecf20Sopenharmony_ci radeon_atombios_lookup_gpio(rdev, 21948c2ecf20Sopenharmony_ci power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex); 21958c2ecf20Sopenharmony_ci if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) 21968c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = 21978c2ecf20Sopenharmony_ci true; 21988c2ecf20Sopenharmony_ci else 21998c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = 22008c2ecf20Sopenharmony_ci false; 22018c2ecf20Sopenharmony_ci } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { 22028c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.type = 22038c2ecf20Sopenharmony_ci VOLTAGE_VDDC; 22048c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = 22058c2ecf20Sopenharmony_ci power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; 22088c2ecf20Sopenharmony_ci radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); 22098c2ecf20Sopenharmony_ci state_index++; 22108c2ecf20Sopenharmony_ci break; 22118c2ecf20Sopenharmony_ci case 3: 22128c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].mclk = 22138c2ecf20Sopenharmony_ci le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock); 22148c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].sclk = 22158c2ecf20Sopenharmony_ci le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock); 22168c2ecf20Sopenharmony_ci /* skip invalid modes */ 22178c2ecf20Sopenharmony_ci if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || 22188c2ecf20Sopenharmony_ci (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) 22198c2ecf20Sopenharmony_ci continue; 22208c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].pcie_lanes = 22218c2ecf20Sopenharmony_ci power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; 22228c2ecf20Sopenharmony_ci misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); 22238c2ecf20Sopenharmony_ci misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); 22248c2ecf20Sopenharmony_ci if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || 22258c2ecf20Sopenharmony_ci (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { 22268c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.type = 22278c2ecf20Sopenharmony_ci VOLTAGE_GPIO; 22288c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = 22298c2ecf20Sopenharmony_ci radeon_atombios_lookup_gpio(rdev, 22308c2ecf20Sopenharmony_ci power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex); 22318c2ecf20Sopenharmony_ci if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) 22328c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = 22338c2ecf20Sopenharmony_ci true; 22348c2ecf20Sopenharmony_ci else 22358c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = 22368c2ecf20Sopenharmony_ci false; 22378c2ecf20Sopenharmony_ci } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { 22388c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.type = 22398c2ecf20Sopenharmony_ci VOLTAGE_VDDC; 22408c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = 22418c2ecf20Sopenharmony_ci power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex; 22428c2ecf20Sopenharmony_ci if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) { 22438c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled = 22448c2ecf20Sopenharmony_ci true; 22458c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id = 22468c2ecf20Sopenharmony_ci power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; 22508c2ecf20Sopenharmony_ci radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); 22518c2ecf20Sopenharmony_ci state_index++; 22528c2ecf20Sopenharmony_ci break; 22538c2ecf20Sopenharmony_ci } 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ciout: 22568c2ecf20Sopenharmony_ci /* free any unused clock_info allocation. */ 22578c2ecf20Sopenharmony_ci if (state_index && state_index < num_modes) { 22588c2ecf20Sopenharmony_ci kfree(rdev->pm.power_state[state_index].clock_info); 22598c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info = NULL; 22608c2ecf20Sopenharmony_ci } 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci /* last mode is usually default */ 22638c2ecf20Sopenharmony_ci if (state_index && rdev->pm.default_power_state_index == -1) { 22648c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index - 1].type = 22658c2ecf20Sopenharmony_ci POWER_STATE_TYPE_DEFAULT; 22668c2ecf20Sopenharmony_ci rdev->pm.default_power_state_index = state_index - 1; 22678c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index - 1].default_clock_mode = 22688c2ecf20Sopenharmony_ci &rdev->pm.power_state[state_index - 1].clock_info[0]; 22698c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index - 1].flags &= 22708c2ecf20Sopenharmony_ci ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; 22718c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index - 1].misc = 0; 22728c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index - 1].misc2 = 0; 22738c2ecf20Sopenharmony_ci } 22748c2ecf20Sopenharmony_ci return state_index; 22758c2ecf20Sopenharmony_ci} 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_cistatic void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *rdev, 22788c2ecf20Sopenharmony_ci ATOM_PPLIB_THERMALCONTROLLER *controller) 22798c2ecf20Sopenharmony_ci{ 22808c2ecf20Sopenharmony_ci struct radeon_i2c_bus_rec i2c_bus; 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci /* add the i2c bus for thermal/fan chip */ 22838c2ecf20Sopenharmony_ci if (controller->ucType > 0) { 22848c2ecf20Sopenharmony_ci if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) 22858c2ecf20Sopenharmony_ci rdev->pm.no_fan = true; 22868c2ecf20Sopenharmony_ci rdev->pm.fan_pulses_per_revolution = 22878c2ecf20Sopenharmony_ci controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; 22888c2ecf20Sopenharmony_ci if (rdev->pm.fan_pulses_per_revolution) { 22898c2ecf20Sopenharmony_ci rdev->pm.fan_min_rpm = controller->ucFanMinRPM; 22908c2ecf20Sopenharmony_ci rdev->pm.fan_max_rpm = controller->ucFanMaxRPM; 22918c2ecf20Sopenharmony_ci } 22928c2ecf20Sopenharmony_ci if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { 22938c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 22948c2ecf20Sopenharmony_ci (controller->ucFanParameters & 22958c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 22968c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; 22978c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { 22988c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 22998c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23008c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23018c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_RV770; 23028c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) { 23038c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 23048c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23058c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23068c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; 23078c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) { 23088c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 23098c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23108c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23118c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_SUMO; 23128c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) { 23138c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 23148c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23158c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23168c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_NI; 23178c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) { 23188c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 23198c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23208c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23218c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_SI; 23228c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) { 23238c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 23248c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23258c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23268c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_CI; 23278c2ecf20Sopenharmony_ci } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) { 23288c2ecf20Sopenharmony_ci DRM_INFO("Internal thermal controller %s fan control\n", 23298c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23308c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23318c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_KV; 23328c2ecf20Sopenharmony_ci } else if (controller->ucType == 23338c2ecf20Sopenharmony_ci ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) { 23348c2ecf20Sopenharmony_ci DRM_INFO("External GPIO thermal controller %s fan control\n", 23358c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23368c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23378c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO; 23388c2ecf20Sopenharmony_ci } else if (controller->ucType == 23398c2ecf20Sopenharmony_ci ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) { 23408c2ecf20Sopenharmony_ci DRM_INFO("ADT7473 with internal thermal controller %s fan control\n", 23418c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23428c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23438c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL; 23448c2ecf20Sopenharmony_ci } else if (controller->ucType == 23458c2ecf20Sopenharmony_ci ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) { 23468c2ecf20Sopenharmony_ci DRM_INFO("EMC2103 with internal thermal controller %s fan control\n", 23478c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23488c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23498c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL; 23508c2ecf20Sopenharmony_ci } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) { 23518c2ecf20Sopenharmony_ci DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", 23528c2ecf20Sopenharmony_ci pp_lib_thermal_controller_names[controller->ucType], 23538c2ecf20Sopenharmony_ci controller->ucI2cAddress >> 1, 23548c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23558c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23568c2ecf20Sopenharmony_ci rdev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL; 23578c2ecf20Sopenharmony_ci i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); 23588c2ecf20Sopenharmony_ci rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); 23598c2ecf20Sopenharmony_ci if (rdev->pm.i2c_bus) { 23608c2ecf20Sopenharmony_ci struct i2c_board_info info = { }; 23618c2ecf20Sopenharmony_ci const char *name = pp_lib_thermal_controller_names[controller->ucType]; 23628c2ecf20Sopenharmony_ci info.addr = controller->ucI2cAddress >> 1; 23638c2ecf20Sopenharmony_ci strlcpy(info.type, name, sizeof(info.type)); 23648c2ecf20Sopenharmony_ci i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info); 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci } else { 23678c2ecf20Sopenharmony_ci DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n", 23688c2ecf20Sopenharmony_ci controller->ucType, 23698c2ecf20Sopenharmony_ci controller->ucI2cAddress >> 1, 23708c2ecf20Sopenharmony_ci (controller->ucFanParameters & 23718c2ecf20Sopenharmony_ci ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci } 23748c2ecf20Sopenharmony_ci} 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_civoid radeon_atombios_get_default_voltages(struct radeon_device *rdev, 23778c2ecf20Sopenharmony_ci u16 *vddc, u16 *vddci, u16 *mvdd) 23788c2ecf20Sopenharmony_ci{ 23798c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 23808c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); 23818c2ecf20Sopenharmony_ci u8 frev, crev; 23828c2ecf20Sopenharmony_ci u16 data_offset; 23838c2ecf20Sopenharmony_ci union firmware_info *firmware_info; 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci *vddc = 0; 23868c2ecf20Sopenharmony_ci *vddci = 0; 23878c2ecf20Sopenharmony_ci *mvdd = 0; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 23908c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 23918c2ecf20Sopenharmony_ci firmware_info = 23928c2ecf20Sopenharmony_ci (union firmware_info *)(mode_info->atom_context->bios + 23938c2ecf20Sopenharmony_ci data_offset); 23948c2ecf20Sopenharmony_ci *vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage); 23958c2ecf20Sopenharmony_ci if ((frev == 2) && (crev >= 2)) { 23968c2ecf20Sopenharmony_ci *vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage); 23978c2ecf20Sopenharmony_ci *mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage); 23988c2ecf20Sopenharmony_ci } 23998c2ecf20Sopenharmony_ci } 24008c2ecf20Sopenharmony_ci} 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_cistatic void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev, 24038c2ecf20Sopenharmony_ci int state_index, int mode_index, 24048c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info) 24058c2ecf20Sopenharmony_ci{ 24068c2ecf20Sopenharmony_ci int j; 24078c2ecf20Sopenharmony_ci u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); 24088c2ecf20Sopenharmony_ci u32 misc2 = le16_to_cpu(non_clock_info->usClassification); 24098c2ecf20Sopenharmony_ci u16 vddc, vddci, mvdd; 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd); 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].misc = misc; 24148c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].misc2 = misc2; 24158c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].pcie_lanes = 24168c2ecf20Sopenharmony_ci ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> 24178c2ecf20Sopenharmony_ci ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; 24188c2ecf20Sopenharmony_ci switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { 24198c2ecf20Sopenharmony_ci case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY: 24208c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 24218c2ecf20Sopenharmony_ci POWER_STATE_TYPE_BATTERY; 24228c2ecf20Sopenharmony_ci break; 24238c2ecf20Sopenharmony_ci case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED: 24248c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 24258c2ecf20Sopenharmony_ci POWER_STATE_TYPE_BALANCED; 24268c2ecf20Sopenharmony_ci break; 24278c2ecf20Sopenharmony_ci case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE: 24288c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 24298c2ecf20Sopenharmony_ci POWER_STATE_TYPE_PERFORMANCE; 24308c2ecf20Sopenharmony_ci break; 24318c2ecf20Sopenharmony_ci case ATOM_PPLIB_CLASSIFICATION_UI_NONE: 24328c2ecf20Sopenharmony_ci if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) 24338c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 24348c2ecf20Sopenharmony_ci POWER_STATE_TYPE_PERFORMANCE; 24358c2ecf20Sopenharmony_ci break; 24368c2ecf20Sopenharmony_ci } 24378c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].flags = 0; 24388c2ecf20Sopenharmony_ci if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) 24398c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].flags |= 24408c2ecf20Sopenharmony_ci RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; 24418c2ecf20Sopenharmony_ci if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { 24428c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 24438c2ecf20Sopenharmony_ci POWER_STATE_TYPE_DEFAULT; 24448c2ecf20Sopenharmony_ci rdev->pm.default_power_state_index = state_index; 24458c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].default_clock_mode = 24468c2ecf20Sopenharmony_ci &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; 24478c2ecf20Sopenharmony_ci if ((rdev->family >= CHIP_BARTS) && !(rdev->flags & RADEON_IS_IGP)) { 24488c2ecf20Sopenharmony_ci /* NI chips post without MC ucode, so default clocks are strobe mode only */ 24498c2ecf20Sopenharmony_ci rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk; 24508c2ecf20Sopenharmony_ci rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk; 24518c2ecf20Sopenharmony_ci rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage; 24528c2ecf20Sopenharmony_ci rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci; 24538c2ecf20Sopenharmony_ci } else { 24548c2ecf20Sopenharmony_ci u16 max_vddci = 0; 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 24578c2ecf20Sopenharmony_ci radeon_atom_get_max_voltage(rdev, 24588c2ecf20Sopenharmony_ci SET_VOLTAGE_TYPE_ASIC_VDDCI, 24598c2ecf20Sopenharmony_ci &max_vddci); 24608c2ecf20Sopenharmony_ci /* patch the table values with the default sclk/mclk from firmware info */ 24618c2ecf20Sopenharmony_ci for (j = 0; j < mode_index; j++) { 24628c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[j].mclk = 24638c2ecf20Sopenharmony_ci rdev->clock.default_mclk; 24648c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[j].sclk = 24658c2ecf20Sopenharmony_ci rdev->clock.default_sclk; 24668c2ecf20Sopenharmony_ci if (vddc) 24678c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = 24688c2ecf20Sopenharmony_ci vddc; 24698c2ecf20Sopenharmony_ci if (max_vddci) 24708c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[j].voltage.vddci = 24718c2ecf20Sopenharmony_ci max_vddci; 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci } 24748c2ecf20Sopenharmony_ci } 24758c2ecf20Sopenharmony_ci} 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_cistatic bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, 24788c2ecf20Sopenharmony_ci int state_index, int mode_index, 24798c2ecf20Sopenharmony_ci union pplib_clock_info *clock_info) 24808c2ecf20Sopenharmony_ci{ 24818c2ecf20Sopenharmony_ci u32 sclk, mclk; 24828c2ecf20Sopenharmony_ci u16 vddc; 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) { 24858c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_PALM) { 24868c2ecf20Sopenharmony_ci sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); 24878c2ecf20Sopenharmony_ci sclk |= clock_info->sumo.ucEngineClockHigh << 16; 24888c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; 24898c2ecf20Sopenharmony_ci } else { 24908c2ecf20Sopenharmony_ci sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); 24918c2ecf20Sopenharmony_ci sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; 24928c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; 24938c2ecf20Sopenharmony_ci } 24948c2ecf20Sopenharmony_ci } else if (rdev->family >= CHIP_BONAIRE) { 24958c2ecf20Sopenharmony_ci sclk = le16_to_cpu(clock_info->ci.usEngineClockLow); 24968c2ecf20Sopenharmony_ci sclk |= clock_info->ci.ucEngineClockHigh << 16; 24978c2ecf20Sopenharmony_ci mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow); 24988c2ecf20Sopenharmony_ci mclk |= clock_info->ci.ucMemoryClockHigh << 16; 24998c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; 25008c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; 25018c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = 25028c2ecf20Sopenharmony_ci VOLTAGE_NONE; 25038c2ecf20Sopenharmony_ci } else if (rdev->family >= CHIP_TAHITI) { 25048c2ecf20Sopenharmony_ci sclk = le16_to_cpu(clock_info->si.usEngineClockLow); 25058c2ecf20Sopenharmony_ci sclk |= clock_info->si.ucEngineClockHigh << 16; 25068c2ecf20Sopenharmony_ci mclk = le16_to_cpu(clock_info->si.usMemoryClockLow); 25078c2ecf20Sopenharmony_ci mclk |= clock_info->si.ucMemoryClockHigh << 16; 25088c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; 25098c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; 25108c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = 25118c2ecf20Sopenharmony_ci VOLTAGE_SW; 25128c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = 25138c2ecf20Sopenharmony_ci le16_to_cpu(clock_info->si.usVDDC); 25148c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci = 25158c2ecf20Sopenharmony_ci le16_to_cpu(clock_info->si.usVDDCI); 25168c2ecf20Sopenharmony_ci } else if (rdev->family >= CHIP_CEDAR) { 25178c2ecf20Sopenharmony_ci sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); 25188c2ecf20Sopenharmony_ci sclk |= clock_info->evergreen.ucEngineClockHigh << 16; 25198c2ecf20Sopenharmony_ci mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow); 25208c2ecf20Sopenharmony_ci mclk |= clock_info->evergreen.ucMemoryClockHigh << 16; 25218c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; 25228c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; 25238c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = 25248c2ecf20Sopenharmony_ci VOLTAGE_SW; 25258c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = 25268c2ecf20Sopenharmony_ci le16_to_cpu(clock_info->evergreen.usVDDC); 25278c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci = 25288c2ecf20Sopenharmony_ci le16_to_cpu(clock_info->evergreen.usVDDCI); 25298c2ecf20Sopenharmony_ci } else { 25308c2ecf20Sopenharmony_ci sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); 25318c2ecf20Sopenharmony_ci sclk |= clock_info->r600.ucEngineClockHigh << 16; 25328c2ecf20Sopenharmony_ci mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); 25338c2ecf20Sopenharmony_ci mclk |= clock_info->r600.ucMemoryClockHigh << 16; 25348c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; 25358c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; 25368c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = 25378c2ecf20Sopenharmony_ci VOLTAGE_SW; 25388c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = 25398c2ecf20Sopenharmony_ci le16_to_cpu(clock_info->r600.usVDDC); 25408c2ecf20Sopenharmony_ci } 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci /* patch up vddc if necessary */ 25438c2ecf20Sopenharmony_ci switch (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage) { 25448c2ecf20Sopenharmony_ci case ATOM_VIRTUAL_VOLTAGE_ID0: 25458c2ecf20Sopenharmony_ci case ATOM_VIRTUAL_VOLTAGE_ID1: 25468c2ecf20Sopenharmony_ci case ATOM_VIRTUAL_VOLTAGE_ID2: 25478c2ecf20Sopenharmony_ci case ATOM_VIRTUAL_VOLTAGE_ID3: 25488c2ecf20Sopenharmony_ci case ATOM_VIRTUAL_VOLTAGE_ID4: 25498c2ecf20Sopenharmony_ci case ATOM_VIRTUAL_VOLTAGE_ID5: 25508c2ecf20Sopenharmony_ci case ATOM_VIRTUAL_VOLTAGE_ID6: 25518c2ecf20Sopenharmony_ci case ATOM_VIRTUAL_VOLTAGE_ID7: 25528c2ecf20Sopenharmony_ci if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, 25538c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage, 25548c2ecf20Sopenharmony_ci &vddc) == 0) 25558c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = vddc; 25568c2ecf20Sopenharmony_ci break; 25578c2ecf20Sopenharmony_ci default: 25588c2ecf20Sopenharmony_ci break; 25598c2ecf20Sopenharmony_ci } 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) { 25628c2ecf20Sopenharmony_ci /* skip invalid modes */ 25638c2ecf20Sopenharmony_ci if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) 25648c2ecf20Sopenharmony_ci return false; 25658c2ecf20Sopenharmony_ci } else { 25668c2ecf20Sopenharmony_ci /* skip invalid modes */ 25678c2ecf20Sopenharmony_ci if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || 25688c2ecf20Sopenharmony_ci (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) 25698c2ecf20Sopenharmony_ci return false; 25708c2ecf20Sopenharmony_ci } 25718c2ecf20Sopenharmony_ci return true; 25728c2ecf20Sopenharmony_ci} 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_cistatic int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) 25758c2ecf20Sopenharmony_ci{ 25768c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 25778c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; 25788c2ecf20Sopenharmony_ci union pplib_power_state *power_state; 25798c2ecf20Sopenharmony_ci int i, j; 25808c2ecf20Sopenharmony_ci int state_index = 0, mode_index = 0; 25818c2ecf20Sopenharmony_ci union pplib_clock_info *clock_info; 25828c2ecf20Sopenharmony_ci bool valid; 25838c2ecf20Sopenharmony_ci union power_info *power_info; 25848c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 25858c2ecf20Sopenharmony_ci u16 data_offset; 25868c2ecf20Sopenharmony_ci u8 frev, crev; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 25898c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) 25908c2ecf20Sopenharmony_ci return state_index; 25918c2ecf20Sopenharmony_ci power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); 25948c2ecf20Sopenharmony_ci if (power_info->pplib.ucNumStates == 0) 25958c2ecf20Sopenharmony_ci return state_index; 25968c2ecf20Sopenharmony_ci rdev->pm.power_state = kcalloc(power_info->pplib.ucNumStates, 25978c2ecf20Sopenharmony_ci sizeof(struct radeon_power_state), 25988c2ecf20Sopenharmony_ci GFP_KERNEL); 25998c2ecf20Sopenharmony_ci if (!rdev->pm.power_state) 26008c2ecf20Sopenharmony_ci return state_index; 26018c2ecf20Sopenharmony_ci /* first mode is usually default, followed by low to high */ 26028c2ecf20Sopenharmony_ci for (i = 0; i < power_info->pplib.ucNumStates; i++) { 26038c2ecf20Sopenharmony_ci mode_index = 0; 26048c2ecf20Sopenharmony_ci power_state = (union pplib_power_state *) 26058c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 26068c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib.usStateArrayOffset) + 26078c2ecf20Sopenharmony_ci i * power_info->pplib.ucStateEntrySize); 26088c2ecf20Sopenharmony_ci non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) 26098c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 26108c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + 26118c2ecf20Sopenharmony_ci (power_state->v1.ucNonClockStateIndex * 26128c2ecf20Sopenharmony_ci power_info->pplib.ucNonClockSize)); 26138c2ecf20Sopenharmony_ci rdev->pm.power_state[i].clock_info = 26148c2ecf20Sopenharmony_ci kcalloc((power_info->pplib.ucStateEntrySize - 1) ? 26158c2ecf20Sopenharmony_ci (power_info->pplib.ucStateEntrySize - 1) : 1, 26168c2ecf20Sopenharmony_ci sizeof(struct radeon_pm_clock_info), 26178c2ecf20Sopenharmony_ci GFP_KERNEL); 26188c2ecf20Sopenharmony_ci if (!rdev->pm.power_state[i].clock_info) 26198c2ecf20Sopenharmony_ci return state_index; 26208c2ecf20Sopenharmony_ci if (power_info->pplib.ucStateEntrySize - 1) { 26218c2ecf20Sopenharmony_ci for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { 26228c2ecf20Sopenharmony_ci clock_info = (union pplib_clock_info *) 26238c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 26248c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + 26258c2ecf20Sopenharmony_ci (power_state->v1.ucClockStateIndices[j] * 26268c2ecf20Sopenharmony_ci power_info->pplib.ucClockInfoSize)); 26278c2ecf20Sopenharmony_ci valid = radeon_atombios_parse_pplib_clock_info(rdev, 26288c2ecf20Sopenharmony_ci state_index, mode_index, 26298c2ecf20Sopenharmony_ci clock_info); 26308c2ecf20Sopenharmony_ci if (valid) 26318c2ecf20Sopenharmony_ci mode_index++; 26328c2ecf20Sopenharmony_ci } 26338c2ecf20Sopenharmony_ci } else { 26348c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].mclk = 26358c2ecf20Sopenharmony_ci rdev->clock.default_mclk; 26368c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].sclk = 26378c2ecf20Sopenharmony_ci rdev->clock.default_sclk; 26388c2ecf20Sopenharmony_ci mode_index++; 26398c2ecf20Sopenharmony_ci } 26408c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].num_clock_modes = mode_index; 26418c2ecf20Sopenharmony_ci if (mode_index) { 26428c2ecf20Sopenharmony_ci radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index, 26438c2ecf20Sopenharmony_ci non_clock_info); 26448c2ecf20Sopenharmony_ci state_index++; 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci /* if multiple clock modes, mark the lowest as no display */ 26488c2ecf20Sopenharmony_ci for (i = 0; i < state_index; i++) { 26498c2ecf20Sopenharmony_ci if (rdev->pm.power_state[i].num_clock_modes > 1) 26508c2ecf20Sopenharmony_ci rdev->pm.power_state[i].clock_info[0].flags |= 26518c2ecf20Sopenharmony_ci RADEON_PM_MODE_NO_DISPLAY; 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci /* first mode is usually default */ 26548c2ecf20Sopenharmony_ci if (rdev->pm.default_power_state_index == -1) { 26558c2ecf20Sopenharmony_ci rdev->pm.power_state[0].type = 26568c2ecf20Sopenharmony_ci POWER_STATE_TYPE_DEFAULT; 26578c2ecf20Sopenharmony_ci rdev->pm.default_power_state_index = 0; 26588c2ecf20Sopenharmony_ci rdev->pm.power_state[0].default_clock_mode = 26598c2ecf20Sopenharmony_ci &rdev->pm.power_state[0].clock_info[0]; 26608c2ecf20Sopenharmony_ci } 26618c2ecf20Sopenharmony_ci return state_index; 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_cistatic int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 26678c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; 26688c2ecf20Sopenharmony_ci union pplib_power_state *power_state; 26698c2ecf20Sopenharmony_ci int i, j, non_clock_array_index, clock_array_index; 26708c2ecf20Sopenharmony_ci int state_index = 0, mode_index = 0; 26718c2ecf20Sopenharmony_ci union pplib_clock_info *clock_info; 26728c2ecf20Sopenharmony_ci struct _StateArray *state_array; 26738c2ecf20Sopenharmony_ci struct _ClockInfoArray *clock_info_array; 26748c2ecf20Sopenharmony_ci struct _NonClockInfoArray *non_clock_info_array; 26758c2ecf20Sopenharmony_ci bool valid; 26768c2ecf20Sopenharmony_ci union power_info *power_info; 26778c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 26788c2ecf20Sopenharmony_ci u16 data_offset; 26798c2ecf20Sopenharmony_ci u8 frev, crev; 26808c2ecf20Sopenharmony_ci u8 *power_state_offset; 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 26838c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) 26848c2ecf20Sopenharmony_ci return state_index; 26858c2ecf20Sopenharmony_ci power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); 26888c2ecf20Sopenharmony_ci state_array = (struct _StateArray *) 26898c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 26908c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib.usStateArrayOffset)); 26918c2ecf20Sopenharmony_ci clock_info_array = (struct _ClockInfoArray *) 26928c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 26938c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); 26948c2ecf20Sopenharmony_ci non_clock_info_array = (struct _NonClockInfoArray *) 26958c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 26968c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); 26978c2ecf20Sopenharmony_ci if (state_array->ucNumEntries == 0) 26988c2ecf20Sopenharmony_ci return state_index; 26998c2ecf20Sopenharmony_ci rdev->pm.power_state = kcalloc(state_array->ucNumEntries, 27008c2ecf20Sopenharmony_ci sizeof(struct radeon_power_state), 27018c2ecf20Sopenharmony_ci GFP_KERNEL); 27028c2ecf20Sopenharmony_ci if (!rdev->pm.power_state) 27038c2ecf20Sopenharmony_ci return state_index; 27048c2ecf20Sopenharmony_ci power_state_offset = (u8 *)state_array->states; 27058c2ecf20Sopenharmony_ci for (i = 0; i < state_array->ucNumEntries; i++) { 27068c2ecf20Sopenharmony_ci mode_index = 0; 27078c2ecf20Sopenharmony_ci power_state = (union pplib_power_state *)power_state_offset; 27088c2ecf20Sopenharmony_ci non_clock_array_index = power_state->v2.nonClockInfoIndex; 27098c2ecf20Sopenharmony_ci non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) 27108c2ecf20Sopenharmony_ci &non_clock_info_array->nonClockInfo[non_clock_array_index]; 27118c2ecf20Sopenharmony_ci rdev->pm.power_state[i].clock_info = 27128c2ecf20Sopenharmony_ci kcalloc(power_state->v2.ucNumDPMLevels ? 27138c2ecf20Sopenharmony_ci power_state->v2.ucNumDPMLevels : 1, 27148c2ecf20Sopenharmony_ci sizeof(struct radeon_pm_clock_info), 27158c2ecf20Sopenharmony_ci GFP_KERNEL); 27168c2ecf20Sopenharmony_ci if (!rdev->pm.power_state[i].clock_info) 27178c2ecf20Sopenharmony_ci return state_index; 27188c2ecf20Sopenharmony_ci if (power_state->v2.ucNumDPMLevels) { 27198c2ecf20Sopenharmony_ci for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { 27208c2ecf20Sopenharmony_ci clock_array_index = power_state->v2.clockInfoIndex[j]; 27218c2ecf20Sopenharmony_ci clock_info = (union pplib_clock_info *) 27228c2ecf20Sopenharmony_ci &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; 27238c2ecf20Sopenharmony_ci valid = radeon_atombios_parse_pplib_clock_info(rdev, 27248c2ecf20Sopenharmony_ci state_index, mode_index, 27258c2ecf20Sopenharmony_ci clock_info); 27268c2ecf20Sopenharmony_ci if (valid) 27278c2ecf20Sopenharmony_ci mode_index++; 27288c2ecf20Sopenharmony_ci } 27298c2ecf20Sopenharmony_ci } else { 27308c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].mclk = 27318c2ecf20Sopenharmony_ci rdev->clock.default_mclk; 27328c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].sclk = 27338c2ecf20Sopenharmony_ci rdev->clock.default_sclk; 27348c2ecf20Sopenharmony_ci mode_index++; 27358c2ecf20Sopenharmony_ci } 27368c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].num_clock_modes = mode_index; 27378c2ecf20Sopenharmony_ci if (mode_index) { 27388c2ecf20Sopenharmony_ci radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index, 27398c2ecf20Sopenharmony_ci non_clock_info); 27408c2ecf20Sopenharmony_ci state_index++; 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci power_state_offset += 2 + power_state->v2.ucNumDPMLevels; 27438c2ecf20Sopenharmony_ci } 27448c2ecf20Sopenharmony_ci /* if multiple clock modes, mark the lowest as no display */ 27458c2ecf20Sopenharmony_ci for (i = 0; i < state_index; i++) { 27468c2ecf20Sopenharmony_ci if (rdev->pm.power_state[i].num_clock_modes > 1) 27478c2ecf20Sopenharmony_ci rdev->pm.power_state[i].clock_info[0].flags |= 27488c2ecf20Sopenharmony_ci RADEON_PM_MODE_NO_DISPLAY; 27498c2ecf20Sopenharmony_ci } 27508c2ecf20Sopenharmony_ci /* first mode is usually default */ 27518c2ecf20Sopenharmony_ci if (rdev->pm.default_power_state_index == -1) { 27528c2ecf20Sopenharmony_ci rdev->pm.power_state[0].type = 27538c2ecf20Sopenharmony_ci POWER_STATE_TYPE_DEFAULT; 27548c2ecf20Sopenharmony_ci rdev->pm.default_power_state_index = 0; 27558c2ecf20Sopenharmony_ci rdev->pm.power_state[0].default_clock_mode = 27568c2ecf20Sopenharmony_ci &rdev->pm.power_state[0].clock_info[0]; 27578c2ecf20Sopenharmony_ci } 27588c2ecf20Sopenharmony_ci return state_index; 27598c2ecf20Sopenharmony_ci} 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_civoid radeon_atombios_get_power_modes(struct radeon_device *rdev) 27628c2ecf20Sopenharmony_ci{ 27638c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 27648c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 27658c2ecf20Sopenharmony_ci u16 data_offset; 27668c2ecf20Sopenharmony_ci u8 frev, crev; 27678c2ecf20Sopenharmony_ci int state_index = 0; 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci rdev->pm.default_power_state_index = -1; 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 27728c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 27738c2ecf20Sopenharmony_ci switch (frev) { 27748c2ecf20Sopenharmony_ci case 1: 27758c2ecf20Sopenharmony_ci case 2: 27768c2ecf20Sopenharmony_ci case 3: 27778c2ecf20Sopenharmony_ci state_index = radeon_atombios_parse_power_table_1_3(rdev); 27788c2ecf20Sopenharmony_ci break; 27798c2ecf20Sopenharmony_ci case 4: 27808c2ecf20Sopenharmony_ci case 5: 27818c2ecf20Sopenharmony_ci state_index = radeon_atombios_parse_power_table_4_5(rdev); 27828c2ecf20Sopenharmony_ci break; 27838c2ecf20Sopenharmony_ci case 6: 27848c2ecf20Sopenharmony_ci state_index = radeon_atombios_parse_power_table_6(rdev); 27858c2ecf20Sopenharmony_ci break; 27868c2ecf20Sopenharmony_ci default: 27878c2ecf20Sopenharmony_ci break; 27888c2ecf20Sopenharmony_ci } 27898c2ecf20Sopenharmony_ci } 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci if (state_index == 0) { 27928c2ecf20Sopenharmony_ci rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL); 27938c2ecf20Sopenharmony_ci if (rdev->pm.power_state) { 27948c2ecf20Sopenharmony_ci rdev->pm.power_state[0].clock_info = 27958c2ecf20Sopenharmony_ci kcalloc(1, 27968c2ecf20Sopenharmony_ci sizeof(struct radeon_pm_clock_info), 27978c2ecf20Sopenharmony_ci GFP_KERNEL); 27988c2ecf20Sopenharmony_ci if (rdev->pm.power_state[0].clock_info) { 27998c2ecf20Sopenharmony_ci /* add the default mode */ 28008c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].type = 28018c2ecf20Sopenharmony_ci POWER_STATE_TYPE_DEFAULT; 28028c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].num_clock_modes = 1; 28038c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; 28048c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; 28058c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].default_clock_mode = 28068c2ecf20Sopenharmony_ci &rdev->pm.power_state[state_index].clock_info[0]; 28078c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; 28088c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].pcie_lanes = 16; 28098c2ecf20Sopenharmony_ci rdev->pm.default_power_state_index = state_index; 28108c2ecf20Sopenharmony_ci rdev->pm.power_state[state_index].flags = 0; 28118c2ecf20Sopenharmony_ci state_index++; 28128c2ecf20Sopenharmony_ci } 28138c2ecf20Sopenharmony_ci } 28148c2ecf20Sopenharmony_ci } 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci rdev->pm.num_power_states = state_index; 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; 28198c2ecf20Sopenharmony_ci rdev->pm.current_clock_mode_index = 0; 28208c2ecf20Sopenharmony_ci if (rdev->pm.default_power_state_index >= 0) 28218c2ecf20Sopenharmony_ci rdev->pm.current_vddc = 28228c2ecf20Sopenharmony_ci rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; 28238c2ecf20Sopenharmony_ci else 28248c2ecf20Sopenharmony_ci rdev->pm.current_vddc = 0; 28258c2ecf20Sopenharmony_ci} 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ciunion get_clock_dividers { 28288c2ecf20Sopenharmony_ci struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1; 28298c2ecf20Sopenharmony_ci struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2; 28308c2ecf20Sopenharmony_ci struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3; 28318c2ecf20Sopenharmony_ci struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4; 28328c2ecf20Sopenharmony_ci struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5; 28338c2ecf20Sopenharmony_ci struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in; 28348c2ecf20Sopenharmony_ci struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out; 28358c2ecf20Sopenharmony_ci}; 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ciint radeon_atom_get_clock_dividers(struct radeon_device *rdev, 28388c2ecf20Sopenharmony_ci u8 clock_type, 28398c2ecf20Sopenharmony_ci u32 clock, 28408c2ecf20Sopenharmony_ci bool strobe_mode, 28418c2ecf20Sopenharmony_ci struct atom_clock_dividers *dividers) 28428c2ecf20Sopenharmony_ci{ 28438c2ecf20Sopenharmony_ci union get_clock_dividers args; 28448c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL); 28458c2ecf20Sopenharmony_ci u8 frev, crev; 28468c2ecf20Sopenharmony_ci 28478c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 28488c2ecf20Sopenharmony_ci memset(dividers, 0, sizeof(struct atom_clock_dividers)); 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 28518c2ecf20Sopenharmony_ci return -EINVAL; 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci switch (crev) { 28548c2ecf20Sopenharmony_ci case 1: 28558c2ecf20Sopenharmony_ci /* r4xx, r5xx */ 28568c2ecf20Sopenharmony_ci args.v1.ucAction = clock_type; 28578c2ecf20Sopenharmony_ci args.v1.ulClock = cpu_to_le32(clock); /* 10 khz */ 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci dividers->post_div = args.v1.ucPostDiv; 28628c2ecf20Sopenharmony_ci dividers->fb_div = args.v1.ucFbDiv; 28638c2ecf20Sopenharmony_ci dividers->enable_post_div = true; 28648c2ecf20Sopenharmony_ci break; 28658c2ecf20Sopenharmony_ci case 2: 28668c2ecf20Sopenharmony_ci case 3: 28678c2ecf20Sopenharmony_ci case 5: 28688c2ecf20Sopenharmony_ci /* r6xx, r7xx, evergreen, ni, si */ 28698c2ecf20Sopenharmony_ci if (rdev->family <= CHIP_RV770) { 28708c2ecf20Sopenharmony_ci args.v2.ucAction = clock_type; 28718c2ecf20Sopenharmony_ci args.v2.ulClock = cpu_to_le32(clock); /* 10 khz */ 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci dividers->post_div = args.v2.ucPostDiv; 28768c2ecf20Sopenharmony_ci dividers->fb_div = le16_to_cpu(args.v2.usFbDiv); 28778c2ecf20Sopenharmony_ci dividers->ref_div = args.v2.ucAction; 28788c2ecf20Sopenharmony_ci if (rdev->family == CHIP_RV770) { 28798c2ecf20Sopenharmony_ci dividers->enable_post_div = (le32_to_cpu(args.v2.ulClock) & (1 << 24)) ? 28808c2ecf20Sopenharmony_ci true : false; 28818c2ecf20Sopenharmony_ci dividers->vco_mode = (le32_to_cpu(args.v2.ulClock) & (1 << 25)) ? 1 : 0; 28828c2ecf20Sopenharmony_ci } else 28838c2ecf20Sopenharmony_ci dividers->enable_post_div = (dividers->fb_div & 1) ? true : false; 28848c2ecf20Sopenharmony_ci } else { 28858c2ecf20Sopenharmony_ci if (clock_type == COMPUTE_ENGINE_PLL_PARAM) { 28868c2ecf20Sopenharmony_ci args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock); 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci dividers->post_div = args.v3.ucPostDiv; 28918c2ecf20Sopenharmony_ci dividers->enable_post_div = (args.v3.ucCntlFlag & 28928c2ecf20Sopenharmony_ci ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false; 28938c2ecf20Sopenharmony_ci dividers->enable_dithen = (args.v3.ucCntlFlag & 28948c2ecf20Sopenharmony_ci ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true; 28958c2ecf20Sopenharmony_ci dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv); 28968c2ecf20Sopenharmony_ci dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac); 28978c2ecf20Sopenharmony_ci dividers->ref_div = args.v3.ucRefDiv; 28988c2ecf20Sopenharmony_ci dividers->vco_mode = (args.v3.ucCntlFlag & 28998c2ecf20Sopenharmony_ci ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0; 29008c2ecf20Sopenharmony_ci } else { 29018c2ecf20Sopenharmony_ci /* for SI we use ComputeMemoryClockParam for memory plls */ 29028c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_TAHITI) 29038c2ecf20Sopenharmony_ci return -EINVAL; 29048c2ecf20Sopenharmony_ci args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock); 29058c2ecf20Sopenharmony_ci if (strobe_mode) 29068c2ecf20Sopenharmony_ci args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN; 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci dividers->post_div = args.v5.ucPostDiv; 29118c2ecf20Sopenharmony_ci dividers->enable_post_div = (args.v5.ucCntlFlag & 29128c2ecf20Sopenharmony_ci ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false; 29138c2ecf20Sopenharmony_ci dividers->enable_dithen = (args.v5.ucCntlFlag & 29148c2ecf20Sopenharmony_ci ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true; 29158c2ecf20Sopenharmony_ci dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv); 29168c2ecf20Sopenharmony_ci dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac); 29178c2ecf20Sopenharmony_ci dividers->ref_div = args.v5.ucRefDiv; 29188c2ecf20Sopenharmony_ci dividers->vco_mode = (args.v5.ucCntlFlag & 29198c2ecf20Sopenharmony_ci ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0; 29208c2ecf20Sopenharmony_ci } 29218c2ecf20Sopenharmony_ci } 29228c2ecf20Sopenharmony_ci break; 29238c2ecf20Sopenharmony_ci case 4: 29248c2ecf20Sopenharmony_ci /* fusion */ 29258c2ecf20Sopenharmony_ci args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */ 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci dividers->post_divider = dividers->post_div = args.v4.ucPostDiv; 29308c2ecf20Sopenharmony_ci dividers->real_clock = le32_to_cpu(args.v4.ulClock); 29318c2ecf20Sopenharmony_ci break; 29328c2ecf20Sopenharmony_ci case 6: 29338c2ecf20Sopenharmony_ci /* CI */ 29348c2ecf20Sopenharmony_ci /* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */ 29358c2ecf20Sopenharmony_ci args.v6_in.ulClock.ulComputeClockFlag = clock_type; 29368c2ecf20Sopenharmony_ci args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */ 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv); 29418c2ecf20Sopenharmony_ci dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac); 29428c2ecf20Sopenharmony_ci dividers->ref_div = args.v6_out.ucPllRefDiv; 29438c2ecf20Sopenharmony_ci dividers->post_div = args.v6_out.ucPllPostDiv; 29448c2ecf20Sopenharmony_ci dividers->flags = args.v6_out.ucPllCntlFlag; 29458c2ecf20Sopenharmony_ci dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock); 29468c2ecf20Sopenharmony_ci dividers->post_divider = args.v6_out.ulClock.ucPostDiv; 29478c2ecf20Sopenharmony_ci break; 29488c2ecf20Sopenharmony_ci default: 29498c2ecf20Sopenharmony_ci return -EINVAL; 29508c2ecf20Sopenharmony_ci } 29518c2ecf20Sopenharmony_ci return 0; 29528c2ecf20Sopenharmony_ci} 29538c2ecf20Sopenharmony_ci 29548c2ecf20Sopenharmony_ciint radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev, 29558c2ecf20Sopenharmony_ci u32 clock, 29568c2ecf20Sopenharmony_ci bool strobe_mode, 29578c2ecf20Sopenharmony_ci struct atom_mpll_param *mpll_param) 29588c2ecf20Sopenharmony_ci{ 29598c2ecf20Sopenharmony_ci COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 args; 29608c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam); 29618c2ecf20Sopenharmony_ci u8 frev, crev; 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 29648c2ecf20Sopenharmony_ci memset(mpll_param, 0, sizeof(struct atom_mpll_param)); 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 29678c2ecf20Sopenharmony_ci return -EINVAL; 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci switch (frev) { 29708c2ecf20Sopenharmony_ci case 2: 29718c2ecf20Sopenharmony_ci switch (crev) { 29728c2ecf20Sopenharmony_ci case 1: 29738c2ecf20Sopenharmony_ci /* SI */ 29748c2ecf20Sopenharmony_ci args.ulClock = cpu_to_le32(clock); /* 10 khz */ 29758c2ecf20Sopenharmony_ci args.ucInputFlag = 0; 29768c2ecf20Sopenharmony_ci if (strobe_mode) 29778c2ecf20Sopenharmony_ci args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN; 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac); 29828c2ecf20Sopenharmony_ci mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv); 29838c2ecf20Sopenharmony_ci mpll_param->post_div = args.ucPostDiv; 29848c2ecf20Sopenharmony_ci mpll_param->dll_speed = args.ucDllSpeed; 29858c2ecf20Sopenharmony_ci mpll_param->bwcntl = args.ucBWCntl; 29868c2ecf20Sopenharmony_ci mpll_param->vco_mode = 29878c2ecf20Sopenharmony_ci (args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK); 29888c2ecf20Sopenharmony_ci mpll_param->yclk_sel = 29898c2ecf20Sopenharmony_ci (args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0; 29908c2ecf20Sopenharmony_ci mpll_param->qdr = 29918c2ecf20Sopenharmony_ci (args.ucPllCntlFlag & MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0; 29928c2ecf20Sopenharmony_ci mpll_param->half_rate = 29938c2ecf20Sopenharmony_ci (args.ucPllCntlFlag & MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0; 29948c2ecf20Sopenharmony_ci break; 29958c2ecf20Sopenharmony_ci default: 29968c2ecf20Sopenharmony_ci return -EINVAL; 29978c2ecf20Sopenharmony_ci } 29988c2ecf20Sopenharmony_ci break; 29998c2ecf20Sopenharmony_ci default: 30008c2ecf20Sopenharmony_ci return -EINVAL; 30018c2ecf20Sopenharmony_ci } 30028c2ecf20Sopenharmony_ci return 0; 30038c2ecf20Sopenharmony_ci} 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_civoid radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) 30068c2ecf20Sopenharmony_ci{ 30078c2ecf20Sopenharmony_ci DYNAMIC_CLOCK_GATING_PS_ALLOCATION args; 30088c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating); 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci args.ucEnable = enable; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 30138c2ecf20Sopenharmony_ci} 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ciuint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev) 30168c2ecf20Sopenharmony_ci{ 30178c2ecf20Sopenharmony_ci GET_ENGINE_CLOCK_PS_ALLOCATION args; 30188c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock); 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 30218c2ecf20Sopenharmony_ci return le32_to_cpu(args.ulReturnEngineClock); 30228c2ecf20Sopenharmony_ci} 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ciuint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev) 30258c2ecf20Sopenharmony_ci{ 30268c2ecf20Sopenharmony_ci GET_MEMORY_CLOCK_PS_ALLOCATION args; 30278c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock); 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 30308c2ecf20Sopenharmony_ci return le32_to_cpu(args.ulReturnMemoryClock); 30318c2ecf20Sopenharmony_ci} 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_civoid radeon_atom_set_engine_clock(struct radeon_device *rdev, 30348c2ecf20Sopenharmony_ci uint32_t eng_clock) 30358c2ecf20Sopenharmony_ci{ 30368c2ecf20Sopenharmony_ci SET_ENGINE_CLOCK_PS_ALLOCATION args; 30378c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock); 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci args.ulTargetEngineClock = cpu_to_le32(eng_clock); /* 10 khz */ 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 30428c2ecf20Sopenharmony_ci} 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_civoid radeon_atom_set_memory_clock(struct radeon_device *rdev, 30458c2ecf20Sopenharmony_ci uint32_t mem_clock) 30468c2ecf20Sopenharmony_ci{ 30478c2ecf20Sopenharmony_ci SET_MEMORY_CLOCK_PS_ALLOCATION args; 30488c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock); 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci if (rdev->flags & RADEON_IS_IGP) 30518c2ecf20Sopenharmony_ci return; 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci args.ulTargetMemoryClock = cpu_to_le32(mem_clock); /* 10 khz */ 30548c2ecf20Sopenharmony_ci 30558c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 30568c2ecf20Sopenharmony_ci} 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_civoid radeon_atom_set_engine_dram_timings(struct radeon_device *rdev, 30598c2ecf20Sopenharmony_ci u32 eng_clock, u32 mem_clock) 30608c2ecf20Sopenharmony_ci{ 30618c2ecf20Sopenharmony_ci SET_ENGINE_CLOCK_PS_ALLOCATION args; 30628c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings); 30638c2ecf20Sopenharmony_ci u32 tmp; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci tmp = eng_clock & SET_CLOCK_FREQ_MASK; 30688c2ecf20Sopenharmony_ci tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24); 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci args.ulTargetEngineClock = cpu_to_le32(tmp); 30718c2ecf20Sopenharmony_ci if (mem_clock) 30728c2ecf20Sopenharmony_ci args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK); 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 30758c2ecf20Sopenharmony_ci} 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_civoid radeon_atom_update_memory_dll(struct radeon_device *rdev, 30788c2ecf20Sopenharmony_ci u32 mem_clock) 30798c2ecf20Sopenharmony_ci{ 30808c2ecf20Sopenharmony_ci u32 args; 30818c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings); 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci args = cpu_to_le32(mem_clock); /* 10 khz */ 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 30868c2ecf20Sopenharmony_ci} 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_civoid radeon_atom_set_ac_timing(struct radeon_device *rdev, 30898c2ecf20Sopenharmony_ci u32 mem_clock) 30908c2ecf20Sopenharmony_ci{ 30918c2ecf20Sopenharmony_ci SET_MEMORY_CLOCK_PS_ALLOCATION args; 30928c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings); 30938c2ecf20Sopenharmony_ci u32 tmp = mem_clock | (COMPUTE_MEMORY_PLL_PARAM << 24); 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci args.ulTargetMemoryClock = cpu_to_le32(tmp); /* 10 khz */ 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 30988c2ecf20Sopenharmony_ci} 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ciunion set_voltage { 31018c2ecf20Sopenharmony_ci struct _SET_VOLTAGE_PS_ALLOCATION alloc; 31028c2ecf20Sopenharmony_ci struct _SET_VOLTAGE_PARAMETERS v1; 31038c2ecf20Sopenharmony_ci struct _SET_VOLTAGE_PARAMETERS_V2 v2; 31048c2ecf20Sopenharmony_ci struct _SET_VOLTAGE_PARAMETERS_V1_3 v3; 31058c2ecf20Sopenharmony_ci}; 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_civoid radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type) 31088c2ecf20Sopenharmony_ci{ 31098c2ecf20Sopenharmony_ci union set_voltage args; 31108c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); 31118c2ecf20Sopenharmony_ci u8 frev, crev, volt_index = voltage_level; 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 31148c2ecf20Sopenharmony_ci return; 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci /* 0xff01 is a flag rather then an actual voltage */ 31178c2ecf20Sopenharmony_ci if (voltage_level == 0xff01) 31188c2ecf20Sopenharmony_ci return; 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci switch (crev) { 31218c2ecf20Sopenharmony_ci case 1: 31228c2ecf20Sopenharmony_ci args.v1.ucVoltageType = voltage_type; 31238c2ecf20Sopenharmony_ci args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE; 31248c2ecf20Sopenharmony_ci args.v1.ucVoltageIndex = volt_index; 31258c2ecf20Sopenharmony_ci break; 31268c2ecf20Sopenharmony_ci case 2: 31278c2ecf20Sopenharmony_ci args.v2.ucVoltageType = voltage_type; 31288c2ecf20Sopenharmony_ci args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE; 31298c2ecf20Sopenharmony_ci args.v2.usVoltageLevel = cpu_to_le16(voltage_level); 31308c2ecf20Sopenharmony_ci break; 31318c2ecf20Sopenharmony_ci case 3: 31328c2ecf20Sopenharmony_ci args.v3.ucVoltageType = voltage_type; 31338c2ecf20Sopenharmony_ci args.v3.ucVoltageMode = ATOM_SET_VOLTAGE; 31348c2ecf20Sopenharmony_ci args.v3.usVoltageLevel = cpu_to_le16(voltage_level); 31358c2ecf20Sopenharmony_ci break; 31368c2ecf20Sopenharmony_ci default: 31378c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 31388c2ecf20Sopenharmony_ci return; 31398c2ecf20Sopenharmony_ci } 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 31428c2ecf20Sopenharmony_ci} 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ciint radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, 31458c2ecf20Sopenharmony_ci u16 voltage_id, u16 *voltage) 31468c2ecf20Sopenharmony_ci{ 31478c2ecf20Sopenharmony_ci union set_voltage args; 31488c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); 31498c2ecf20Sopenharmony_ci u8 frev, crev; 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 31528c2ecf20Sopenharmony_ci return -EINVAL; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci switch (crev) { 31558c2ecf20Sopenharmony_ci case 1: 31568c2ecf20Sopenharmony_ci return -EINVAL; 31578c2ecf20Sopenharmony_ci case 2: 31588c2ecf20Sopenharmony_ci args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE; 31598c2ecf20Sopenharmony_ci args.v2.ucVoltageMode = 0; 31608c2ecf20Sopenharmony_ci args.v2.usVoltageLevel = 0; 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci *voltage = le16_to_cpu(args.v2.usVoltageLevel); 31658c2ecf20Sopenharmony_ci break; 31668c2ecf20Sopenharmony_ci case 3: 31678c2ecf20Sopenharmony_ci args.v3.ucVoltageType = voltage_type; 31688c2ecf20Sopenharmony_ci args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL; 31698c2ecf20Sopenharmony_ci args.v3.usVoltageLevel = cpu_to_le16(voltage_id); 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci *voltage = le16_to_cpu(args.v3.usVoltageLevel); 31748c2ecf20Sopenharmony_ci break; 31758c2ecf20Sopenharmony_ci default: 31768c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 31778c2ecf20Sopenharmony_ci return -EINVAL; 31788c2ecf20Sopenharmony_ci } 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci return 0; 31818c2ecf20Sopenharmony_ci} 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ciint radeon_atom_get_leakage_vddc_based_on_leakage_idx(struct radeon_device *rdev, 31848c2ecf20Sopenharmony_ci u16 *voltage, 31858c2ecf20Sopenharmony_ci u16 leakage_idx) 31868c2ecf20Sopenharmony_ci{ 31878c2ecf20Sopenharmony_ci return radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage); 31888c2ecf20Sopenharmony_ci} 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ciint radeon_atom_get_leakage_id_from_vbios(struct radeon_device *rdev, 31918c2ecf20Sopenharmony_ci u16 *leakage_id) 31928c2ecf20Sopenharmony_ci{ 31938c2ecf20Sopenharmony_ci union set_voltage args; 31948c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); 31958c2ecf20Sopenharmony_ci u8 frev, crev; 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 31988c2ecf20Sopenharmony_ci return -EINVAL; 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci switch (crev) { 32018c2ecf20Sopenharmony_ci case 3: 32028c2ecf20Sopenharmony_ci case 4: 32038c2ecf20Sopenharmony_ci args.v3.ucVoltageType = 0; 32048c2ecf20Sopenharmony_ci args.v3.ucVoltageMode = ATOM_GET_LEAKAGE_ID; 32058c2ecf20Sopenharmony_ci args.v3.usVoltageLevel = 0; 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci *leakage_id = le16_to_cpu(args.v3.usVoltageLevel); 32108c2ecf20Sopenharmony_ci break; 32118c2ecf20Sopenharmony_ci default: 32128c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 32138c2ecf20Sopenharmony_ci return -EINVAL; 32148c2ecf20Sopenharmony_ci } 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci return 0; 32178c2ecf20Sopenharmony_ci} 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ciint radeon_atom_get_leakage_vddc_based_on_leakage_params(struct radeon_device *rdev, 32208c2ecf20Sopenharmony_ci u16 *vddc, u16 *vddci, 32218c2ecf20Sopenharmony_ci u16 virtual_voltage_id, 32228c2ecf20Sopenharmony_ci u16 vbios_voltage_id) 32238c2ecf20Sopenharmony_ci{ 32248c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo); 32258c2ecf20Sopenharmony_ci u8 frev, crev; 32268c2ecf20Sopenharmony_ci u16 data_offset, size; 32278c2ecf20Sopenharmony_ci int i, j; 32288c2ecf20Sopenharmony_ci ATOM_ASIC_PROFILING_INFO_V2_1 *profile; 32298c2ecf20Sopenharmony_ci u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci *vddc = 0; 32328c2ecf20Sopenharmony_ci *vddci = 0; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci if (!atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 32358c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) 32368c2ecf20Sopenharmony_ci return -EINVAL; 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *) 32398c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci switch (frev) { 32428c2ecf20Sopenharmony_ci case 1: 32438c2ecf20Sopenharmony_ci return -EINVAL; 32448c2ecf20Sopenharmony_ci case 2: 32458c2ecf20Sopenharmony_ci switch (crev) { 32468c2ecf20Sopenharmony_ci case 1: 32478c2ecf20Sopenharmony_ci if (size < sizeof(ATOM_ASIC_PROFILING_INFO_V2_1)) 32488c2ecf20Sopenharmony_ci return -EINVAL; 32498c2ecf20Sopenharmony_ci leakage_bin = (u16 *) 32508c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset + 32518c2ecf20Sopenharmony_ci le16_to_cpu(profile->usLeakageBinArrayOffset)); 32528c2ecf20Sopenharmony_ci vddc_id_buf = (u16 *) 32538c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset + 32548c2ecf20Sopenharmony_ci le16_to_cpu(profile->usElbVDDC_IdArrayOffset)); 32558c2ecf20Sopenharmony_ci vddc_buf = (u16 *) 32568c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset + 32578c2ecf20Sopenharmony_ci le16_to_cpu(profile->usElbVDDC_LevelArrayOffset)); 32588c2ecf20Sopenharmony_ci vddci_id_buf = (u16 *) 32598c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset + 32608c2ecf20Sopenharmony_ci le16_to_cpu(profile->usElbVDDCI_IdArrayOffset)); 32618c2ecf20Sopenharmony_ci vddci_buf = (u16 *) 32628c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset + 32638c2ecf20Sopenharmony_ci le16_to_cpu(profile->usElbVDDCI_LevelArrayOffset)); 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci if (profile->ucElbVDDC_Num > 0) { 32668c2ecf20Sopenharmony_ci for (i = 0; i < profile->ucElbVDDC_Num; i++) { 32678c2ecf20Sopenharmony_ci if (vddc_id_buf[i] == virtual_voltage_id) { 32688c2ecf20Sopenharmony_ci for (j = 0; j < profile->ucLeakageBinNum; j++) { 32698c2ecf20Sopenharmony_ci if (vbios_voltage_id <= leakage_bin[j]) { 32708c2ecf20Sopenharmony_ci *vddc = vddc_buf[j * profile->ucElbVDDC_Num + i]; 32718c2ecf20Sopenharmony_ci break; 32728c2ecf20Sopenharmony_ci } 32738c2ecf20Sopenharmony_ci } 32748c2ecf20Sopenharmony_ci break; 32758c2ecf20Sopenharmony_ci } 32768c2ecf20Sopenharmony_ci } 32778c2ecf20Sopenharmony_ci } 32788c2ecf20Sopenharmony_ci if (profile->ucElbVDDCI_Num > 0) { 32798c2ecf20Sopenharmony_ci for (i = 0; i < profile->ucElbVDDCI_Num; i++) { 32808c2ecf20Sopenharmony_ci if (vddci_id_buf[i] == virtual_voltage_id) { 32818c2ecf20Sopenharmony_ci for (j = 0; j < profile->ucLeakageBinNum; j++) { 32828c2ecf20Sopenharmony_ci if (vbios_voltage_id <= leakage_bin[j]) { 32838c2ecf20Sopenharmony_ci *vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i]; 32848c2ecf20Sopenharmony_ci break; 32858c2ecf20Sopenharmony_ci } 32868c2ecf20Sopenharmony_ci } 32878c2ecf20Sopenharmony_ci break; 32888c2ecf20Sopenharmony_ci } 32898c2ecf20Sopenharmony_ci } 32908c2ecf20Sopenharmony_ci } 32918c2ecf20Sopenharmony_ci break; 32928c2ecf20Sopenharmony_ci default: 32938c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 32948c2ecf20Sopenharmony_ci return -EINVAL; 32958c2ecf20Sopenharmony_ci } 32968c2ecf20Sopenharmony_ci break; 32978c2ecf20Sopenharmony_ci default: 32988c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 32998c2ecf20Sopenharmony_ci return -EINVAL; 33008c2ecf20Sopenharmony_ci } 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci return 0; 33038c2ecf20Sopenharmony_ci} 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ciunion get_voltage_info { 33068c2ecf20Sopenharmony_ci struct _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 in; 33078c2ecf20Sopenharmony_ci struct _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 evv_out; 33088c2ecf20Sopenharmony_ci}; 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ciint radeon_atom_get_voltage_evv(struct radeon_device *rdev, 33118c2ecf20Sopenharmony_ci u16 virtual_voltage_id, 33128c2ecf20Sopenharmony_ci u16 *voltage) 33138c2ecf20Sopenharmony_ci{ 33148c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, GetVoltageInfo); 33158c2ecf20Sopenharmony_ci u32 entry_id; 33168c2ecf20Sopenharmony_ci u32 count = rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; 33178c2ecf20Sopenharmony_ci union get_voltage_info args; 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci for (entry_id = 0; entry_id < count; entry_id++) { 33208c2ecf20Sopenharmony_ci if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].v == 33218c2ecf20Sopenharmony_ci virtual_voltage_id) 33228c2ecf20Sopenharmony_ci break; 33238c2ecf20Sopenharmony_ci } 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci if (entry_id >= count) 33268c2ecf20Sopenharmony_ci return -EINVAL; 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci args.in.ucVoltageType = VOLTAGE_TYPE_VDDC; 33298c2ecf20Sopenharmony_ci args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE; 33308c2ecf20Sopenharmony_ci args.in.usVoltageLevel = cpu_to_le16(virtual_voltage_id); 33318c2ecf20Sopenharmony_ci args.in.ulSCLKFreq = 33328c2ecf20Sopenharmony_ci cpu_to_le32(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk); 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci *voltage = le16_to_cpu(args.evv_out.usVoltageLevel); 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci return 0; 33398c2ecf20Sopenharmony_ci} 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_ciint radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev, 33428c2ecf20Sopenharmony_ci u16 voltage_level, u8 voltage_type, 33438c2ecf20Sopenharmony_ci u32 *gpio_value, u32 *gpio_mask) 33448c2ecf20Sopenharmony_ci{ 33458c2ecf20Sopenharmony_ci union set_voltage args; 33468c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); 33478c2ecf20Sopenharmony_ci u8 frev, crev; 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) 33508c2ecf20Sopenharmony_ci return -EINVAL; 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci switch (crev) { 33538c2ecf20Sopenharmony_ci case 1: 33548c2ecf20Sopenharmony_ci return -EINVAL; 33558c2ecf20Sopenharmony_ci case 2: 33568c2ecf20Sopenharmony_ci args.v2.ucVoltageType = voltage_type; 33578c2ecf20Sopenharmony_ci args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK; 33588c2ecf20Sopenharmony_ci args.v2.usVoltageLevel = cpu_to_le16(voltage_level); 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 33618c2ecf20Sopenharmony_ci 33628c2ecf20Sopenharmony_ci *gpio_mask = le32_to_cpu(*(u32 *)&args.v2); 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci args.v2.ucVoltageType = voltage_type; 33658c2ecf20Sopenharmony_ci args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL; 33668c2ecf20Sopenharmony_ci args.v2.usVoltageLevel = cpu_to_le16(voltage_level); 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci *gpio_value = le32_to_cpu(*(u32 *)&args.v2); 33718c2ecf20Sopenharmony_ci break; 33728c2ecf20Sopenharmony_ci default: 33738c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 33748c2ecf20Sopenharmony_ci return -EINVAL; 33758c2ecf20Sopenharmony_ci } 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci return 0; 33788c2ecf20Sopenharmony_ci} 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ciunion voltage_object_info { 33818c2ecf20Sopenharmony_ci struct _ATOM_VOLTAGE_OBJECT_INFO v1; 33828c2ecf20Sopenharmony_ci struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2; 33838c2ecf20Sopenharmony_ci struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3; 33848c2ecf20Sopenharmony_ci}; 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ciunion voltage_object { 33878c2ecf20Sopenharmony_ci struct _ATOM_VOLTAGE_OBJECT v1; 33888c2ecf20Sopenharmony_ci struct _ATOM_VOLTAGE_OBJECT_V2 v2; 33898c2ecf20Sopenharmony_ci union _ATOM_VOLTAGE_OBJECT_V3 v3; 33908c2ecf20Sopenharmony_ci}; 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_cistatic ATOM_VOLTAGE_OBJECT *atom_lookup_voltage_object_v1(ATOM_VOLTAGE_OBJECT_INFO *v1, 33938c2ecf20Sopenharmony_ci u8 voltage_type) 33948c2ecf20Sopenharmony_ci{ 33958c2ecf20Sopenharmony_ci u32 size = le16_to_cpu(v1->sHeader.usStructureSize); 33968c2ecf20Sopenharmony_ci u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO, asVoltageObj[0]); 33978c2ecf20Sopenharmony_ci u8 *start = (u8 *)v1; 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci while (offset < size) { 34008c2ecf20Sopenharmony_ci ATOM_VOLTAGE_OBJECT *vo = (ATOM_VOLTAGE_OBJECT *)(start + offset); 34018c2ecf20Sopenharmony_ci if (vo->ucVoltageType == voltage_type) 34028c2ecf20Sopenharmony_ci return vo; 34038c2ecf20Sopenharmony_ci offset += offsetof(ATOM_VOLTAGE_OBJECT, asFormula.ucVIDAdjustEntries) + 34048c2ecf20Sopenharmony_ci vo->asFormula.ucNumOfVoltageEntries; 34058c2ecf20Sopenharmony_ci } 34068c2ecf20Sopenharmony_ci return NULL; 34078c2ecf20Sopenharmony_ci} 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_cistatic ATOM_VOLTAGE_OBJECT_V2 *atom_lookup_voltage_object_v2(ATOM_VOLTAGE_OBJECT_INFO_V2 *v2, 34108c2ecf20Sopenharmony_ci u8 voltage_type) 34118c2ecf20Sopenharmony_ci{ 34128c2ecf20Sopenharmony_ci u32 size = le16_to_cpu(v2->sHeader.usStructureSize); 34138c2ecf20Sopenharmony_ci u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V2, asVoltageObj[0]); 34148c2ecf20Sopenharmony_ci u8 *start = (u8*)v2; 34158c2ecf20Sopenharmony_ci 34168c2ecf20Sopenharmony_ci while (offset < size) { 34178c2ecf20Sopenharmony_ci ATOM_VOLTAGE_OBJECT_V2 *vo = (ATOM_VOLTAGE_OBJECT_V2 *)(start + offset); 34188c2ecf20Sopenharmony_ci if (vo->ucVoltageType == voltage_type) 34198c2ecf20Sopenharmony_ci return vo; 34208c2ecf20Sopenharmony_ci offset += offsetof(ATOM_VOLTAGE_OBJECT_V2, asFormula.asVIDAdjustEntries) + 34218c2ecf20Sopenharmony_ci (vo->asFormula.ucNumOfVoltageEntries * sizeof(VOLTAGE_LUT_ENTRY)); 34228c2ecf20Sopenharmony_ci } 34238c2ecf20Sopenharmony_ci return NULL; 34248c2ecf20Sopenharmony_ci} 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_cistatic ATOM_VOLTAGE_OBJECT_V3 *atom_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3, 34278c2ecf20Sopenharmony_ci u8 voltage_type, u8 voltage_mode) 34288c2ecf20Sopenharmony_ci{ 34298c2ecf20Sopenharmony_ci u32 size = le16_to_cpu(v3->sHeader.usStructureSize); 34308c2ecf20Sopenharmony_ci u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]); 34318c2ecf20Sopenharmony_ci u8 *start = (u8*)v3; 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci while (offset < size) { 34348c2ecf20Sopenharmony_ci ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset); 34358c2ecf20Sopenharmony_ci if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) && 34368c2ecf20Sopenharmony_ci (vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode)) 34378c2ecf20Sopenharmony_ci return vo; 34388c2ecf20Sopenharmony_ci offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize); 34398c2ecf20Sopenharmony_ci } 34408c2ecf20Sopenharmony_ci return NULL; 34418c2ecf20Sopenharmony_ci} 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_cibool 34448c2ecf20Sopenharmony_ciradeon_atom_is_voltage_gpio(struct radeon_device *rdev, 34458c2ecf20Sopenharmony_ci u8 voltage_type, u8 voltage_mode) 34468c2ecf20Sopenharmony_ci{ 34478c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 34488c2ecf20Sopenharmony_ci u8 frev, crev; 34498c2ecf20Sopenharmony_ci u16 data_offset, size; 34508c2ecf20Sopenharmony_ci union voltage_object_info *voltage_info; 34518c2ecf20Sopenharmony_ci union voltage_object *voltage_object = NULL; 34528c2ecf20Sopenharmony_ci 34538c2ecf20Sopenharmony_ci if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 34548c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 34558c2ecf20Sopenharmony_ci voltage_info = (union voltage_object_info *) 34568c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci switch (frev) { 34598c2ecf20Sopenharmony_ci case 1: 34608c2ecf20Sopenharmony_ci case 2: 34618c2ecf20Sopenharmony_ci switch (crev) { 34628c2ecf20Sopenharmony_ci case 1: 34638c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 34648c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type); 34658c2ecf20Sopenharmony_ci if (voltage_object && 34668c2ecf20Sopenharmony_ci (voltage_object->v1.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO)) 34678c2ecf20Sopenharmony_ci return true; 34688c2ecf20Sopenharmony_ci break; 34698c2ecf20Sopenharmony_ci case 2: 34708c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 34718c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type); 34728c2ecf20Sopenharmony_ci if (voltage_object && 34738c2ecf20Sopenharmony_ci (voltage_object->v2.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO)) 34748c2ecf20Sopenharmony_ci return true; 34758c2ecf20Sopenharmony_ci break; 34768c2ecf20Sopenharmony_ci default: 34778c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 34788c2ecf20Sopenharmony_ci return false; 34798c2ecf20Sopenharmony_ci } 34808c2ecf20Sopenharmony_ci break; 34818c2ecf20Sopenharmony_ci case 3: 34828c2ecf20Sopenharmony_ci switch (crev) { 34838c2ecf20Sopenharmony_ci case 1: 34848c2ecf20Sopenharmony_ci if (atom_lookup_voltage_object_v3(&voltage_info->v3, 34858c2ecf20Sopenharmony_ci voltage_type, voltage_mode)) 34868c2ecf20Sopenharmony_ci return true; 34878c2ecf20Sopenharmony_ci break; 34888c2ecf20Sopenharmony_ci default: 34898c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 34908c2ecf20Sopenharmony_ci return false; 34918c2ecf20Sopenharmony_ci } 34928c2ecf20Sopenharmony_ci break; 34938c2ecf20Sopenharmony_ci default: 34948c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 34958c2ecf20Sopenharmony_ci return false; 34968c2ecf20Sopenharmony_ci } 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci } 34998c2ecf20Sopenharmony_ci return false; 35008c2ecf20Sopenharmony_ci} 35018c2ecf20Sopenharmony_ci 35028c2ecf20Sopenharmony_ciint radeon_atom_get_svi2_info(struct radeon_device *rdev, 35038c2ecf20Sopenharmony_ci u8 voltage_type, 35048c2ecf20Sopenharmony_ci u8 *svd_gpio_id, u8 *svc_gpio_id) 35058c2ecf20Sopenharmony_ci{ 35068c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 35078c2ecf20Sopenharmony_ci u8 frev, crev; 35088c2ecf20Sopenharmony_ci u16 data_offset, size; 35098c2ecf20Sopenharmony_ci union voltage_object_info *voltage_info; 35108c2ecf20Sopenharmony_ci union voltage_object *voltage_object = NULL; 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_ci if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 35138c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 35148c2ecf20Sopenharmony_ci voltage_info = (union voltage_object_info *) 35158c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci switch (frev) { 35188c2ecf20Sopenharmony_ci case 3: 35198c2ecf20Sopenharmony_ci switch (crev) { 35208c2ecf20Sopenharmony_ci case 1: 35218c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 35228c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v3(&voltage_info->v3, 35238c2ecf20Sopenharmony_ci voltage_type, 35248c2ecf20Sopenharmony_ci VOLTAGE_OBJ_SVID2); 35258c2ecf20Sopenharmony_ci if (voltage_object) { 35268c2ecf20Sopenharmony_ci *svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId; 35278c2ecf20Sopenharmony_ci *svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId; 35288c2ecf20Sopenharmony_ci } else { 35298c2ecf20Sopenharmony_ci return -EINVAL; 35308c2ecf20Sopenharmony_ci } 35318c2ecf20Sopenharmony_ci break; 35328c2ecf20Sopenharmony_ci default: 35338c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 35348c2ecf20Sopenharmony_ci return -EINVAL; 35358c2ecf20Sopenharmony_ci } 35368c2ecf20Sopenharmony_ci break; 35378c2ecf20Sopenharmony_ci default: 35388c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 35398c2ecf20Sopenharmony_ci return -EINVAL; 35408c2ecf20Sopenharmony_ci } 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci } 35438c2ecf20Sopenharmony_ci return 0; 35448c2ecf20Sopenharmony_ci} 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_ciint radeon_atom_get_max_voltage(struct radeon_device *rdev, 35478c2ecf20Sopenharmony_ci u8 voltage_type, u16 *max_voltage) 35488c2ecf20Sopenharmony_ci{ 35498c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 35508c2ecf20Sopenharmony_ci u8 frev, crev; 35518c2ecf20Sopenharmony_ci u16 data_offset, size; 35528c2ecf20Sopenharmony_ci union voltage_object_info *voltage_info; 35538c2ecf20Sopenharmony_ci union voltage_object *voltage_object = NULL; 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_ci if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 35568c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 35578c2ecf20Sopenharmony_ci voltage_info = (union voltage_object_info *) 35588c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci switch (crev) { 35618c2ecf20Sopenharmony_ci case 1: 35628c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 35638c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type); 35648c2ecf20Sopenharmony_ci if (voltage_object) { 35658c2ecf20Sopenharmony_ci ATOM_VOLTAGE_FORMULA *formula = 35668c2ecf20Sopenharmony_ci &voltage_object->v1.asFormula; 35678c2ecf20Sopenharmony_ci if (formula->ucFlag & 1) 35688c2ecf20Sopenharmony_ci *max_voltage = 35698c2ecf20Sopenharmony_ci le16_to_cpu(formula->usVoltageBaseLevel) + 35708c2ecf20Sopenharmony_ci formula->ucNumOfVoltageEntries / 2 * 35718c2ecf20Sopenharmony_ci le16_to_cpu(formula->usVoltageStep); 35728c2ecf20Sopenharmony_ci else 35738c2ecf20Sopenharmony_ci *max_voltage = 35748c2ecf20Sopenharmony_ci le16_to_cpu(formula->usVoltageBaseLevel) + 35758c2ecf20Sopenharmony_ci (formula->ucNumOfVoltageEntries - 1) * 35768c2ecf20Sopenharmony_ci le16_to_cpu(formula->usVoltageStep); 35778c2ecf20Sopenharmony_ci return 0; 35788c2ecf20Sopenharmony_ci } 35798c2ecf20Sopenharmony_ci break; 35808c2ecf20Sopenharmony_ci case 2: 35818c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 35828c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type); 35838c2ecf20Sopenharmony_ci if (voltage_object) { 35848c2ecf20Sopenharmony_ci ATOM_VOLTAGE_FORMULA_V2 *formula = 35858c2ecf20Sopenharmony_ci &voltage_object->v2.asFormula; 35868c2ecf20Sopenharmony_ci if (formula->ucNumOfVoltageEntries) { 35878c2ecf20Sopenharmony_ci VOLTAGE_LUT_ENTRY *lut = (VOLTAGE_LUT_ENTRY *) 35888c2ecf20Sopenharmony_ci ((u8 *)&formula->asVIDAdjustEntries[0] + 35898c2ecf20Sopenharmony_ci (sizeof(VOLTAGE_LUT_ENTRY) * (formula->ucNumOfVoltageEntries - 1))); 35908c2ecf20Sopenharmony_ci *max_voltage = 35918c2ecf20Sopenharmony_ci le16_to_cpu(lut->usVoltageValue); 35928c2ecf20Sopenharmony_ci return 0; 35938c2ecf20Sopenharmony_ci } 35948c2ecf20Sopenharmony_ci } 35958c2ecf20Sopenharmony_ci break; 35968c2ecf20Sopenharmony_ci default: 35978c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 35988c2ecf20Sopenharmony_ci return -EINVAL; 35998c2ecf20Sopenharmony_ci } 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_ci } 36028c2ecf20Sopenharmony_ci return -EINVAL; 36038c2ecf20Sopenharmony_ci} 36048c2ecf20Sopenharmony_ci 36058c2ecf20Sopenharmony_ciint radeon_atom_get_min_voltage(struct radeon_device *rdev, 36068c2ecf20Sopenharmony_ci u8 voltage_type, u16 *min_voltage) 36078c2ecf20Sopenharmony_ci{ 36088c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 36098c2ecf20Sopenharmony_ci u8 frev, crev; 36108c2ecf20Sopenharmony_ci u16 data_offset, size; 36118c2ecf20Sopenharmony_ci union voltage_object_info *voltage_info; 36128c2ecf20Sopenharmony_ci union voltage_object *voltage_object = NULL; 36138c2ecf20Sopenharmony_ci 36148c2ecf20Sopenharmony_ci if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 36158c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 36168c2ecf20Sopenharmony_ci voltage_info = (union voltage_object_info *) 36178c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_ci switch (crev) { 36208c2ecf20Sopenharmony_ci case 1: 36218c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 36228c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type); 36238c2ecf20Sopenharmony_ci if (voltage_object) { 36248c2ecf20Sopenharmony_ci ATOM_VOLTAGE_FORMULA *formula = 36258c2ecf20Sopenharmony_ci &voltage_object->v1.asFormula; 36268c2ecf20Sopenharmony_ci *min_voltage = 36278c2ecf20Sopenharmony_ci le16_to_cpu(formula->usVoltageBaseLevel); 36288c2ecf20Sopenharmony_ci return 0; 36298c2ecf20Sopenharmony_ci } 36308c2ecf20Sopenharmony_ci break; 36318c2ecf20Sopenharmony_ci case 2: 36328c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 36338c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type); 36348c2ecf20Sopenharmony_ci if (voltage_object) { 36358c2ecf20Sopenharmony_ci ATOM_VOLTAGE_FORMULA_V2 *formula = 36368c2ecf20Sopenharmony_ci &voltage_object->v2.asFormula; 36378c2ecf20Sopenharmony_ci if (formula->ucNumOfVoltageEntries) { 36388c2ecf20Sopenharmony_ci *min_voltage = 36398c2ecf20Sopenharmony_ci le16_to_cpu(formula->asVIDAdjustEntries[ 36408c2ecf20Sopenharmony_ci 0 36418c2ecf20Sopenharmony_ci ].usVoltageValue); 36428c2ecf20Sopenharmony_ci return 0; 36438c2ecf20Sopenharmony_ci } 36448c2ecf20Sopenharmony_ci } 36458c2ecf20Sopenharmony_ci break; 36468c2ecf20Sopenharmony_ci default: 36478c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 36488c2ecf20Sopenharmony_ci return -EINVAL; 36498c2ecf20Sopenharmony_ci } 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci } 36528c2ecf20Sopenharmony_ci return -EINVAL; 36538c2ecf20Sopenharmony_ci} 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ciint radeon_atom_get_voltage_step(struct radeon_device *rdev, 36568c2ecf20Sopenharmony_ci u8 voltage_type, u16 *voltage_step) 36578c2ecf20Sopenharmony_ci{ 36588c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 36598c2ecf20Sopenharmony_ci u8 frev, crev; 36608c2ecf20Sopenharmony_ci u16 data_offset, size; 36618c2ecf20Sopenharmony_ci union voltage_object_info *voltage_info; 36628c2ecf20Sopenharmony_ci union voltage_object *voltage_object = NULL; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 36658c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 36668c2ecf20Sopenharmony_ci voltage_info = (union voltage_object_info *) 36678c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci switch (crev) { 36708c2ecf20Sopenharmony_ci case 1: 36718c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 36728c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type); 36738c2ecf20Sopenharmony_ci if (voltage_object) { 36748c2ecf20Sopenharmony_ci ATOM_VOLTAGE_FORMULA *formula = 36758c2ecf20Sopenharmony_ci &voltage_object->v1.asFormula; 36768c2ecf20Sopenharmony_ci if (formula->ucFlag & 1) 36778c2ecf20Sopenharmony_ci *voltage_step = 36788c2ecf20Sopenharmony_ci (le16_to_cpu(formula->usVoltageStep) + 1) / 2; 36798c2ecf20Sopenharmony_ci else 36808c2ecf20Sopenharmony_ci *voltage_step = 36818c2ecf20Sopenharmony_ci le16_to_cpu(formula->usVoltageStep); 36828c2ecf20Sopenharmony_ci return 0; 36838c2ecf20Sopenharmony_ci } 36848c2ecf20Sopenharmony_ci break; 36858c2ecf20Sopenharmony_ci case 2: 36868c2ecf20Sopenharmony_ci return -EINVAL; 36878c2ecf20Sopenharmony_ci default: 36888c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 36898c2ecf20Sopenharmony_ci return -EINVAL; 36908c2ecf20Sopenharmony_ci } 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci } 36938c2ecf20Sopenharmony_ci return -EINVAL; 36948c2ecf20Sopenharmony_ci} 36958c2ecf20Sopenharmony_ci 36968c2ecf20Sopenharmony_ciint radeon_atom_round_to_true_voltage(struct radeon_device *rdev, 36978c2ecf20Sopenharmony_ci u8 voltage_type, 36988c2ecf20Sopenharmony_ci u16 nominal_voltage, 36998c2ecf20Sopenharmony_ci u16 *true_voltage) 37008c2ecf20Sopenharmony_ci{ 37018c2ecf20Sopenharmony_ci u16 min_voltage, max_voltage, voltage_step; 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci if (radeon_atom_get_max_voltage(rdev, voltage_type, &max_voltage)) 37048c2ecf20Sopenharmony_ci return -EINVAL; 37058c2ecf20Sopenharmony_ci if (radeon_atom_get_min_voltage(rdev, voltage_type, &min_voltage)) 37068c2ecf20Sopenharmony_ci return -EINVAL; 37078c2ecf20Sopenharmony_ci if (radeon_atom_get_voltage_step(rdev, voltage_type, &voltage_step)) 37088c2ecf20Sopenharmony_ci return -EINVAL; 37098c2ecf20Sopenharmony_ci 37108c2ecf20Sopenharmony_ci if (nominal_voltage <= min_voltage) 37118c2ecf20Sopenharmony_ci *true_voltage = min_voltage; 37128c2ecf20Sopenharmony_ci else if (nominal_voltage >= max_voltage) 37138c2ecf20Sopenharmony_ci *true_voltage = max_voltage; 37148c2ecf20Sopenharmony_ci else 37158c2ecf20Sopenharmony_ci *true_voltage = min_voltage + 37168c2ecf20Sopenharmony_ci ((nominal_voltage - min_voltage) / voltage_step) * 37178c2ecf20Sopenharmony_ci voltage_step; 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci return 0; 37208c2ecf20Sopenharmony_ci} 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ciint radeon_atom_get_voltage_table(struct radeon_device *rdev, 37238c2ecf20Sopenharmony_ci u8 voltage_type, u8 voltage_mode, 37248c2ecf20Sopenharmony_ci struct atom_voltage_table *voltage_table) 37258c2ecf20Sopenharmony_ci{ 37268c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 37278c2ecf20Sopenharmony_ci u8 frev, crev; 37288c2ecf20Sopenharmony_ci u16 data_offset, size; 37298c2ecf20Sopenharmony_ci int i, ret; 37308c2ecf20Sopenharmony_ci union voltage_object_info *voltage_info; 37318c2ecf20Sopenharmony_ci union voltage_object *voltage_object = NULL; 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_ci if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 37348c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 37358c2ecf20Sopenharmony_ci voltage_info = (union voltage_object_info *) 37368c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci switch (frev) { 37398c2ecf20Sopenharmony_ci case 1: 37408c2ecf20Sopenharmony_ci case 2: 37418c2ecf20Sopenharmony_ci switch (crev) { 37428c2ecf20Sopenharmony_ci case 1: 37438c2ecf20Sopenharmony_ci DRM_ERROR("old table version %d, %d\n", frev, crev); 37448c2ecf20Sopenharmony_ci return -EINVAL; 37458c2ecf20Sopenharmony_ci case 2: 37468c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 37478c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type); 37488c2ecf20Sopenharmony_ci if (voltage_object) { 37498c2ecf20Sopenharmony_ci ATOM_VOLTAGE_FORMULA_V2 *formula = 37508c2ecf20Sopenharmony_ci &voltage_object->v2.asFormula; 37518c2ecf20Sopenharmony_ci VOLTAGE_LUT_ENTRY *lut; 37528c2ecf20Sopenharmony_ci if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES) 37538c2ecf20Sopenharmony_ci return -EINVAL; 37548c2ecf20Sopenharmony_ci lut = &formula->asVIDAdjustEntries[0]; 37558c2ecf20Sopenharmony_ci for (i = 0; i < formula->ucNumOfVoltageEntries; i++) { 37568c2ecf20Sopenharmony_ci voltage_table->entries[i].value = 37578c2ecf20Sopenharmony_ci le16_to_cpu(lut->usVoltageValue); 37588c2ecf20Sopenharmony_ci ret = radeon_atom_get_voltage_gpio_settings(rdev, 37598c2ecf20Sopenharmony_ci voltage_table->entries[i].value, 37608c2ecf20Sopenharmony_ci voltage_type, 37618c2ecf20Sopenharmony_ci &voltage_table->entries[i].smio_low, 37628c2ecf20Sopenharmony_ci &voltage_table->mask_low); 37638c2ecf20Sopenharmony_ci if (ret) 37648c2ecf20Sopenharmony_ci return ret; 37658c2ecf20Sopenharmony_ci lut = (VOLTAGE_LUT_ENTRY *) 37668c2ecf20Sopenharmony_ci ((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY)); 37678c2ecf20Sopenharmony_ci } 37688c2ecf20Sopenharmony_ci voltage_table->count = formula->ucNumOfVoltageEntries; 37698c2ecf20Sopenharmony_ci return 0; 37708c2ecf20Sopenharmony_ci } 37718c2ecf20Sopenharmony_ci break; 37728c2ecf20Sopenharmony_ci default: 37738c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 37748c2ecf20Sopenharmony_ci return -EINVAL; 37758c2ecf20Sopenharmony_ci } 37768c2ecf20Sopenharmony_ci break; 37778c2ecf20Sopenharmony_ci case 3: 37788c2ecf20Sopenharmony_ci switch (crev) { 37798c2ecf20Sopenharmony_ci case 1: 37808c2ecf20Sopenharmony_ci voltage_object = (union voltage_object *) 37818c2ecf20Sopenharmony_ci atom_lookup_voltage_object_v3(&voltage_info->v3, 37828c2ecf20Sopenharmony_ci voltage_type, voltage_mode); 37838c2ecf20Sopenharmony_ci if (voltage_object) { 37848c2ecf20Sopenharmony_ci ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio = 37858c2ecf20Sopenharmony_ci &voltage_object->v3.asGpioVoltageObj; 37868c2ecf20Sopenharmony_ci VOLTAGE_LUT_ENTRY_V2 *lut; 37878c2ecf20Sopenharmony_ci if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES) 37888c2ecf20Sopenharmony_ci return -EINVAL; 37898c2ecf20Sopenharmony_ci lut = &gpio->asVolGpioLut[0]; 37908c2ecf20Sopenharmony_ci for (i = 0; i < gpio->ucGpioEntryNum; i++) { 37918c2ecf20Sopenharmony_ci voltage_table->entries[i].value = 37928c2ecf20Sopenharmony_ci le16_to_cpu(lut->usVoltageValue); 37938c2ecf20Sopenharmony_ci voltage_table->entries[i].smio_low = 37948c2ecf20Sopenharmony_ci le32_to_cpu(lut->ulVoltageId); 37958c2ecf20Sopenharmony_ci lut = (VOLTAGE_LUT_ENTRY_V2 *) 37968c2ecf20Sopenharmony_ci ((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY_V2)); 37978c2ecf20Sopenharmony_ci } 37988c2ecf20Sopenharmony_ci voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal); 37998c2ecf20Sopenharmony_ci voltage_table->count = gpio->ucGpioEntryNum; 38008c2ecf20Sopenharmony_ci voltage_table->phase_delay = gpio->ucPhaseDelay; 38018c2ecf20Sopenharmony_ci return 0; 38028c2ecf20Sopenharmony_ci } 38038c2ecf20Sopenharmony_ci break; 38048c2ecf20Sopenharmony_ci default: 38058c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 38068c2ecf20Sopenharmony_ci return -EINVAL; 38078c2ecf20Sopenharmony_ci } 38088c2ecf20Sopenharmony_ci break; 38098c2ecf20Sopenharmony_ci default: 38108c2ecf20Sopenharmony_ci DRM_ERROR("unknown voltage object table\n"); 38118c2ecf20Sopenharmony_ci return -EINVAL; 38128c2ecf20Sopenharmony_ci } 38138c2ecf20Sopenharmony_ci } 38148c2ecf20Sopenharmony_ci return -EINVAL; 38158c2ecf20Sopenharmony_ci} 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_ciunion vram_info { 38188c2ecf20Sopenharmony_ci struct _ATOM_VRAM_INFO_V3 v1_3; 38198c2ecf20Sopenharmony_ci struct _ATOM_VRAM_INFO_V4 v1_4; 38208c2ecf20Sopenharmony_ci struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1; 38218c2ecf20Sopenharmony_ci}; 38228c2ecf20Sopenharmony_ci 38238c2ecf20Sopenharmony_ciint radeon_atom_get_memory_info(struct radeon_device *rdev, 38248c2ecf20Sopenharmony_ci u8 module_index, struct atom_memory_info *mem_info) 38258c2ecf20Sopenharmony_ci{ 38268c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, VRAM_Info); 38278c2ecf20Sopenharmony_ci u8 frev, crev, i; 38288c2ecf20Sopenharmony_ci u16 data_offset, size; 38298c2ecf20Sopenharmony_ci union vram_info *vram_info; 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci memset(mem_info, 0, sizeof(struct atom_memory_info)); 38328c2ecf20Sopenharmony_ci 38338c2ecf20Sopenharmony_ci if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 38348c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 38358c2ecf20Sopenharmony_ci vram_info = (union vram_info *) 38368c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 38378c2ecf20Sopenharmony_ci switch (frev) { 38388c2ecf20Sopenharmony_ci case 1: 38398c2ecf20Sopenharmony_ci switch (crev) { 38408c2ecf20Sopenharmony_ci case 3: 38418c2ecf20Sopenharmony_ci /* r6xx */ 38428c2ecf20Sopenharmony_ci if (module_index < vram_info->v1_3.ucNumOfVRAMModule) { 38438c2ecf20Sopenharmony_ci ATOM_VRAM_MODULE_V3 *vram_module = 38448c2ecf20Sopenharmony_ci (ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo; 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci for (i = 0; i < module_index; i++) { 38478c2ecf20Sopenharmony_ci if (le16_to_cpu(vram_module->usSize) == 0) 38488c2ecf20Sopenharmony_ci return -EINVAL; 38498c2ecf20Sopenharmony_ci vram_module = (ATOM_VRAM_MODULE_V3 *) 38508c2ecf20Sopenharmony_ci ((u8 *)vram_module + le16_to_cpu(vram_module->usSize)); 38518c2ecf20Sopenharmony_ci } 38528c2ecf20Sopenharmony_ci mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf; 38538c2ecf20Sopenharmony_ci mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0; 38548c2ecf20Sopenharmony_ci } else 38558c2ecf20Sopenharmony_ci return -EINVAL; 38568c2ecf20Sopenharmony_ci break; 38578c2ecf20Sopenharmony_ci case 4: 38588c2ecf20Sopenharmony_ci /* r7xx, evergreen */ 38598c2ecf20Sopenharmony_ci if (module_index < vram_info->v1_4.ucNumOfVRAMModule) { 38608c2ecf20Sopenharmony_ci ATOM_VRAM_MODULE_V4 *vram_module = 38618c2ecf20Sopenharmony_ci (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ci for (i = 0; i < module_index; i++) { 38648c2ecf20Sopenharmony_ci if (le16_to_cpu(vram_module->usModuleSize) == 0) 38658c2ecf20Sopenharmony_ci return -EINVAL; 38668c2ecf20Sopenharmony_ci vram_module = (ATOM_VRAM_MODULE_V4 *) 38678c2ecf20Sopenharmony_ci ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); 38688c2ecf20Sopenharmony_ci } 38698c2ecf20Sopenharmony_ci mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; 38708c2ecf20Sopenharmony_ci mem_info->mem_type = vram_module->ucMemoryType & 0xf0; 38718c2ecf20Sopenharmony_ci } else 38728c2ecf20Sopenharmony_ci return -EINVAL; 38738c2ecf20Sopenharmony_ci break; 38748c2ecf20Sopenharmony_ci default: 38758c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 38768c2ecf20Sopenharmony_ci return -EINVAL; 38778c2ecf20Sopenharmony_ci } 38788c2ecf20Sopenharmony_ci break; 38798c2ecf20Sopenharmony_ci case 2: 38808c2ecf20Sopenharmony_ci switch (crev) { 38818c2ecf20Sopenharmony_ci case 1: 38828c2ecf20Sopenharmony_ci /* ni */ 38838c2ecf20Sopenharmony_ci if (module_index < vram_info->v2_1.ucNumOfVRAMModule) { 38848c2ecf20Sopenharmony_ci ATOM_VRAM_MODULE_V7 *vram_module = 38858c2ecf20Sopenharmony_ci (ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo; 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci for (i = 0; i < module_index; i++) { 38888c2ecf20Sopenharmony_ci if (le16_to_cpu(vram_module->usModuleSize) == 0) 38898c2ecf20Sopenharmony_ci return -EINVAL; 38908c2ecf20Sopenharmony_ci vram_module = (ATOM_VRAM_MODULE_V7 *) 38918c2ecf20Sopenharmony_ci ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); 38928c2ecf20Sopenharmony_ci } 38938c2ecf20Sopenharmony_ci mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf; 38948c2ecf20Sopenharmony_ci mem_info->mem_type = vram_module->ucMemoryType & 0xf0; 38958c2ecf20Sopenharmony_ci } else 38968c2ecf20Sopenharmony_ci return -EINVAL; 38978c2ecf20Sopenharmony_ci break; 38988c2ecf20Sopenharmony_ci default: 38998c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 39008c2ecf20Sopenharmony_ci return -EINVAL; 39018c2ecf20Sopenharmony_ci } 39028c2ecf20Sopenharmony_ci break; 39038c2ecf20Sopenharmony_ci default: 39048c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 39058c2ecf20Sopenharmony_ci return -EINVAL; 39068c2ecf20Sopenharmony_ci } 39078c2ecf20Sopenharmony_ci return 0; 39088c2ecf20Sopenharmony_ci } 39098c2ecf20Sopenharmony_ci return -EINVAL; 39108c2ecf20Sopenharmony_ci} 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ciint radeon_atom_get_mclk_range_table(struct radeon_device *rdev, 39138c2ecf20Sopenharmony_ci bool gddr5, u8 module_index, 39148c2ecf20Sopenharmony_ci struct atom_memory_clock_range_table *mclk_range_table) 39158c2ecf20Sopenharmony_ci{ 39168c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, VRAM_Info); 39178c2ecf20Sopenharmony_ci u8 frev, crev, i; 39188c2ecf20Sopenharmony_ci u16 data_offset, size; 39198c2ecf20Sopenharmony_ci union vram_info *vram_info; 39208c2ecf20Sopenharmony_ci u32 mem_timing_size = gddr5 ? 39218c2ecf20Sopenharmony_ci sizeof(ATOM_MEMORY_TIMING_FORMAT_V2) : sizeof(ATOM_MEMORY_TIMING_FORMAT); 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci memset(mclk_range_table, 0, sizeof(struct atom_memory_clock_range_table)); 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 39268c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 39278c2ecf20Sopenharmony_ci vram_info = (union vram_info *) 39288c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 39298c2ecf20Sopenharmony_ci switch (frev) { 39308c2ecf20Sopenharmony_ci case 1: 39318c2ecf20Sopenharmony_ci switch (crev) { 39328c2ecf20Sopenharmony_ci case 3: 39338c2ecf20Sopenharmony_ci DRM_ERROR("old table version %d, %d\n", frev, crev); 39348c2ecf20Sopenharmony_ci return -EINVAL; 39358c2ecf20Sopenharmony_ci case 4: 39368c2ecf20Sopenharmony_ci /* r7xx, evergreen */ 39378c2ecf20Sopenharmony_ci if (module_index < vram_info->v1_4.ucNumOfVRAMModule) { 39388c2ecf20Sopenharmony_ci ATOM_VRAM_MODULE_V4 *vram_module = 39398c2ecf20Sopenharmony_ci (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo; 39408c2ecf20Sopenharmony_ci ATOM_MEMORY_TIMING_FORMAT *format; 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci for (i = 0; i < module_index; i++) { 39438c2ecf20Sopenharmony_ci if (le16_to_cpu(vram_module->usModuleSize) == 0) 39448c2ecf20Sopenharmony_ci return -EINVAL; 39458c2ecf20Sopenharmony_ci vram_module = (ATOM_VRAM_MODULE_V4 *) 39468c2ecf20Sopenharmony_ci ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize)); 39478c2ecf20Sopenharmony_ci } 39488c2ecf20Sopenharmony_ci mclk_range_table->num_entries = (u8) 39498c2ecf20Sopenharmony_ci ((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) / 39508c2ecf20Sopenharmony_ci mem_timing_size); 39518c2ecf20Sopenharmony_ci format = &vram_module->asMemTiming[0]; 39528c2ecf20Sopenharmony_ci for (i = 0; i < mclk_range_table->num_entries; i++) { 39538c2ecf20Sopenharmony_ci mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange); 39548c2ecf20Sopenharmony_ci format = (ATOM_MEMORY_TIMING_FORMAT *) 39558c2ecf20Sopenharmony_ci ((u8 *)format + mem_timing_size); 39568c2ecf20Sopenharmony_ci } 39578c2ecf20Sopenharmony_ci } else 39588c2ecf20Sopenharmony_ci return -EINVAL; 39598c2ecf20Sopenharmony_ci break; 39608c2ecf20Sopenharmony_ci default: 39618c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 39628c2ecf20Sopenharmony_ci return -EINVAL; 39638c2ecf20Sopenharmony_ci } 39648c2ecf20Sopenharmony_ci break; 39658c2ecf20Sopenharmony_ci case 2: 39668c2ecf20Sopenharmony_ci DRM_ERROR("new table version %d, %d\n", frev, crev); 39678c2ecf20Sopenharmony_ci return -EINVAL; 39688c2ecf20Sopenharmony_ci default: 39698c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 39708c2ecf20Sopenharmony_ci return -EINVAL; 39718c2ecf20Sopenharmony_ci } 39728c2ecf20Sopenharmony_ci return 0; 39738c2ecf20Sopenharmony_ci } 39748c2ecf20Sopenharmony_ci return -EINVAL; 39758c2ecf20Sopenharmony_ci} 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci#define MEM_ID_MASK 0xff000000 39788c2ecf20Sopenharmony_ci#define MEM_ID_SHIFT 24 39798c2ecf20Sopenharmony_ci#define CLOCK_RANGE_MASK 0x00ffffff 39808c2ecf20Sopenharmony_ci#define CLOCK_RANGE_SHIFT 0 39818c2ecf20Sopenharmony_ci#define LOW_NIBBLE_MASK 0xf 39828c2ecf20Sopenharmony_ci#define DATA_EQU_PREV 0 39838c2ecf20Sopenharmony_ci#define DATA_FROM_TABLE 4 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ciint radeon_atom_init_mc_reg_table(struct radeon_device *rdev, 39868c2ecf20Sopenharmony_ci u8 module_index, 39878c2ecf20Sopenharmony_ci struct atom_mc_reg_table *reg_table) 39888c2ecf20Sopenharmony_ci{ 39898c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, VRAM_Info); 39908c2ecf20Sopenharmony_ci u8 frev, crev, num_entries, t_mem_id, num_ranges = 0; 39918c2ecf20Sopenharmony_ci u32 i = 0, j; 39928c2ecf20Sopenharmony_ci u16 data_offset, size; 39938c2ecf20Sopenharmony_ci union vram_info *vram_info; 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci memset(reg_table, 0, sizeof(struct atom_mc_reg_table)); 39968c2ecf20Sopenharmony_ci 39978c2ecf20Sopenharmony_ci if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, 39988c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) { 39998c2ecf20Sopenharmony_ci vram_info = (union vram_info *) 40008c2ecf20Sopenharmony_ci (rdev->mode_info.atom_context->bios + data_offset); 40018c2ecf20Sopenharmony_ci switch (frev) { 40028c2ecf20Sopenharmony_ci case 1: 40038c2ecf20Sopenharmony_ci DRM_ERROR("old table version %d, %d\n", frev, crev); 40048c2ecf20Sopenharmony_ci return -EINVAL; 40058c2ecf20Sopenharmony_ci case 2: 40068c2ecf20Sopenharmony_ci switch (crev) { 40078c2ecf20Sopenharmony_ci case 1: 40088c2ecf20Sopenharmony_ci if (module_index < vram_info->v2_1.ucNumOfVRAMModule) { 40098c2ecf20Sopenharmony_ci ATOM_INIT_REG_BLOCK *reg_block = 40108c2ecf20Sopenharmony_ci (ATOM_INIT_REG_BLOCK *) 40118c2ecf20Sopenharmony_ci ((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset)); 40128c2ecf20Sopenharmony_ci ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = 40138c2ecf20Sopenharmony_ci (ATOM_MEMORY_SETTING_DATA_BLOCK *) 40148c2ecf20Sopenharmony_ci ((u8 *)reg_block + (2 * sizeof(u16)) + 40158c2ecf20Sopenharmony_ci le16_to_cpu(reg_block->usRegIndexTblSize)); 40168c2ecf20Sopenharmony_ci ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0]; 40178c2ecf20Sopenharmony_ci num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) / 40188c2ecf20Sopenharmony_ci sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1; 40198c2ecf20Sopenharmony_ci if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE) 40208c2ecf20Sopenharmony_ci return -EINVAL; 40218c2ecf20Sopenharmony_ci while (i < num_entries) { 40228c2ecf20Sopenharmony_ci if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER) 40238c2ecf20Sopenharmony_ci break; 40248c2ecf20Sopenharmony_ci reg_table->mc_reg_address[i].s1 = 40258c2ecf20Sopenharmony_ci (u16)(le16_to_cpu(format->usRegIndex)); 40268c2ecf20Sopenharmony_ci reg_table->mc_reg_address[i].pre_reg_data = 40278c2ecf20Sopenharmony_ci (u8)(format->ucPreRegDataLength); 40288c2ecf20Sopenharmony_ci i++; 40298c2ecf20Sopenharmony_ci format = (ATOM_INIT_REG_INDEX_FORMAT *) 40308c2ecf20Sopenharmony_ci ((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT)); 40318c2ecf20Sopenharmony_ci } 40328c2ecf20Sopenharmony_ci reg_table->last = i; 40338c2ecf20Sopenharmony_ci while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) && 40348c2ecf20Sopenharmony_ci (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) { 40358c2ecf20Sopenharmony_ci t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK) 40368c2ecf20Sopenharmony_ci >> MEM_ID_SHIFT); 40378c2ecf20Sopenharmony_ci if (module_index == t_mem_id) { 40388c2ecf20Sopenharmony_ci reg_table->mc_reg_table_entry[num_ranges].mclk_max = 40398c2ecf20Sopenharmony_ci (u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK) 40408c2ecf20Sopenharmony_ci >> CLOCK_RANGE_SHIFT); 40418c2ecf20Sopenharmony_ci for (i = 0, j = 1; i < reg_table->last; i++) { 40428c2ecf20Sopenharmony_ci if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) { 40438c2ecf20Sopenharmony_ci reg_table->mc_reg_table_entry[num_ranges].mc_data[i] = 40448c2ecf20Sopenharmony_ci (u32)le32_to_cpu(*((u32 *)reg_data + j)); 40458c2ecf20Sopenharmony_ci j++; 40468c2ecf20Sopenharmony_ci } else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) { 40478c2ecf20Sopenharmony_ci reg_table->mc_reg_table_entry[num_ranges].mc_data[i] = 40488c2ecf20Sopenharmony_ci reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1]; 40498c2ecf20Sopenharmony_ci } 40508c2ecf20Sopenharmony_ci } 40518c2ecf20Sopenharmony_ci num_ranges++; 40528c2ecf20Sopenharmony_ci } 40538c2ecf20Sopenharmony_ci reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *) 40548c2ecf20Sopenharmony_ci ((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)); 40558c2ecf20Sopenharmony_ci } 40568c2ecf20Sopenharmony_ci if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) 40578c2ecf20Sopenharmony_ci return -EINVAL; 40588c2ecf20Sopenharmony_ci reg_table->num_entries = num_ranges; 40598c2ecf20Sopenharmony_ci } else 40608c2ecf20Sopenharmony_ci return -EINVAL; 40618c2ecf20Sopenharmony_ci break; 40628c2ecf20Sopenharmony_ci default: 40638c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 40648c2ecf20Sopenharmony_ci return -EINVAL; 40658c2ecf20Sopenharmony_ci } 40668c2ecf20Sopenharmony_ci break; 40678c2ecf20Sopenharmony_ci default: 40688c2ecf20Sopenharmony_ci DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 40698c2ecf20Sopenharmony_ci return -EINVAL; 40708c2ecf20Sopenharmony_ci } 40718c2ecf20Sopenharmony_ci return 0; 40728c2ecf20Sopenharmony_ci } 40738c2ecf20Sopenharmony_ci return -EINVAL; 40748c2ecf20Sopenharmony_ci} 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_civoid radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) 40778c2ecf20Sopenharmony_ci{ 40788c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 40798c2ecf20Sopenharmony_ci uint32_t bios_2_scratch, bios_6_scratch; 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) { 40828c2ecf20Sopenharmony_ci bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); 40838c2ecf20Sopenharmony_ci bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH); 40848c2ecf20Sopenharmony_ci } else { 40858c2ecf20Sopenharmony_ci bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); 40868c2ecf20Sopenharmony_ci bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); 40878c2ecf20Sopenharmony_ci } 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_ci /* let the bios control the backlight */ 40908c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE; 40918c2ecf20Sopenharmony_ci 40928c2ecf20Sopenharmony_ci /* tell the bios not to handle mode switching */ 40938c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH; 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_ci /* clear the vbios dpms state */ 40968c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 40978c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE; 40988c2ecf20Sopenharmony_ci 40998c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) { 41008c2ecf20Sopenharmony_ci WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); 41018c2ecf20Sopenharmony_ci WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); 41028c2ecf20Sopenharmony_ci } else { 41038c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); 41048c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); 41058c2ecf20Sopenharmony_ci } 41068c2ecf20Sopenharmony_ci 41078c2ecf20Sopenharmony_ci} 41088c2ecf20Sopenharmony_ci 41098c2ecf20Sopenharmony_civoid radeon_save_bios_scratch_regs(struct radeon_device *rdev) 41108c2ecf20Sopenharmony_ci{ 41118c2ecf20Sopenharmony_ci uint32_t scratch_reg; 41128c2ecf20Sopenharmony_ci int i; 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 41158c2ecf20Sopenharmony_ci scratch_reg = R600_BIOS_0_SCRATCH; 41168c2ecf20Sopenharmony_ci else 41178c2ecf20Sopenharmony_ci scratch_reg = RADEON_BIOS_0_SCRATCH; 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++) 41208c2ecf20Sopenharmony_ci rdev->bios_scratch[i] = RREG32(scratch_reg + (i * 4)); 41218c2ecf20Sopenharmony_ci} 41228c2ecf20Sopenharmony_ci 41238c2ecf20Sopenharmony_civoid radeon_restore_bios_scratch_regs(struct radeon_device *rdev) 41248c2ecf20Sopenharmony_ci{ 41258c2ecf20Sopenharmony_ci uint32_t scratch_reg; 41268c2ecf20Sopenharmony_ci int i; 41278c2ecf20Sopenharmony_ci 41288c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 41298c2ecf20Sopenharmony_ci scratch_reg = R600_BIOS_0_SCRATCH; 41308c2ecf20Sopenharmony_ci else 41318c2ecf20Sopenharmony_ci scratch_reg = RADEON_BIOS_0_SCRATCH; 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++) 41348c2ecf20Sopenharmony_ci WREG32(scratch_reg + (i * 4), rdev->bios_scratch[i]); 41358c2ecf20Sopenharmony_ci} 41368c2ecf20Sopenharmony_ci 41378c2ecf20Sopenharmony_civoid radeon_atom_output_lock(struct drm_encoder *encoder, bool lock) 41388c2ecf20Sopenharmony_ci{ 41398c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 41408c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 41418c2ecf20Sopenharmony_ci uint32_t bios_6_scratch; 41428c2ecf20Sopenharmony_ci 41438c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 41448c2ecf20Sopenharmony_ci bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH); 41458c2ecf20Sopenharmony_ci else 41468c2ecf20Sopenharmony_ci bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); 41478c2ecf20Sopenharmony_ci 41488c2ecf20Sopenharmony_ci if (lock) { 41498c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_CRITICAL_STATE; 41508c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_MODE; 41518c2ecf20Sopenharmony_ci } else { 41528c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE; 41538c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_MODE; 41548c2ecf20Sopenharmony_ci } 41558c2ecf20Sopenharmony_ci 41568c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 41578c2ecf20Sopenharmony_ci WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); 41588c2ecf20Sopenharmony_ci else 41598c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); 41608c2ecf20Sopenharmony_ci} 41618c2ecf20Sopenharmony_ci 41628c2ecf20Sopenharmony_ci/* at some point we may want to break this out into individual functions */ 41638c2ecf20Sopenharmony_civoid 41648c2ecf20Sopenharmony_ciradeon_atombios_connected_scratch_regs(struct drm_connector *connector, 41658c2ecf20Sopenharmony_ci struct drm_encoder *encoder, 41668c2ecf20Sopenharmony_ci bool connected) 41678c2ecf20Sopenharmony_ci{ 41688c2ecf20Sopenharmony_ci struct drm_device *dev = connector->dev; 41698c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 41708c2ecf20Sopenharmony_ci struct radeon_connector *radeon_connector = 41718c2ecf20Sopenharmony_ci to_radeon_connector(connector); 41728c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 41738c2ecf20Sopenharmony_ci uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch; 41748c2ecf20Sopenharmony_ci 41758c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) { 41768c2ecf20Sopenharmony_ci bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); 41778c2ecf20Sopenharmony_ci bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH); 41788c2ecf20Sopenharmony_ci bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH); 41798c2ecf20Sopenharmony_ci } else { 41808c2ecf20Sopenharmony_ci bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); 41818c2ecf20Sopenharmony_ci bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH); 41828c2ecf20Sopenharmony_ci bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); 41838c2ecf20Sopenharmony_ci } 41848c2ecf20Sopenharmony_ci 41858c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) && 41868c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) { 41878c2ecf20Sopenharmony_ci if (connected) { 41888c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("TV1 connected\n"); 41898c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_TV1_ACTIVE; 41908c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_TV1; 41918c2ecf20Sopenharmony_ci } else { 41928c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("TV1 disconnected\n"); 41938c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_TV1_MASK; 41948c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE; 41958c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1; 41968c2ecf20Sopenharmony_ci } 41978c2ecf20Sopenharmony_ci } 41988c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) && 41998c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) { 42008c2ecf20Sopenharmony_ci if (connected) { 42018c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("CV connected\n"); 42028c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_CV_ACTIVE; 42038c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_CV; 42048c2ecf20Sopenharmony_ci } else { 42058c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("CV disconnected\n"); 42068c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_CV_MASK; 42078c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_CV_ACTIVE; 42088c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV; 42098c2ecf20Sopenharmony_ci } 42108c2ecf20Sopenharmony_ci } 42118c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) && 42128c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) { 42138c2ecf20Sopenharmony_ci if (connected) { 42148c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("LCD1 connected\n"); 42158c2ecf20Sopenharmony_ci bios_0_scratch |= ATOM_S0_LCD1; 42168c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_LCD1_ACTIVE; 42178c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1; 42188c2ecf20Sopenharmony_ci } else { 42198c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("LCD1 disconnected\n"); 42208c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_LCD1; 42218c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE; 42228c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1; 42238c2ecf20Sopenharmony_ci } 42248c2ecf20Sopenharmony_ci } 42258c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) && 42268c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) { 42278c2ecf20Sopenharmony_ci if (connected) { 42288c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("CRT1 connected\n"); 42298c2ecf20Sopenharmony_ci bios_0_scratch |= ATOM_S0_CRT1_COLOR; 42308c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_CRT1_ACTIVE; 42318c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1; 42328c2ecf20Sopenharmony_ci } else { 42338c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("CRT1 disconnected\n"); 42348c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_CRT1_MASK; 42358c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE; 42368c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1; 42378c2ecf20Sopenharmony_ci } 42388c2ecf20Sopenharmony_ci } 42398c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) && 42408c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) { 42418c2ecf20Sopenharmony_ci if (connected) { 42428c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("CRT2 connected\n"); 42438c2ecf20Sopenharmony_ci bios_0_scratch |= ATOM_S0_CRT2_COLOR; 42448c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_CRT2_ACTIVE; 42458c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2; 42468c2ecf20Sopenharmony_ci } else { 42478c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("CRT2 disconnected\n"); 42488c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_CRT2_MASK; 42498c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE; 42508c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2; 42518c2ecf20Sopenharmony_ci } 42528c2ecf20Sopenharmony_ci } 42538c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) && 42548c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) { 42558c2ecf20Sopenharmony_ci if (connected) { 42568c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP1 connected\n"); 42578c2ecf20Sopenharmony_ci bios_0_scratch |= ATOM_S0_DFP1; 42588c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_DFP1_ACTIVE; 42598c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1; 42608c2ecf20Sopenharmony_ci } else { 42618c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP1 disconnected\n"); 42628c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_DFP1; 42638c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE; 42648c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1; 42658c2ecf20Sopenharmony_ci } 42668c2ecf20Sopenharmony_ci } 42678c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) && 42688c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) { 42698c2ecf20Sopenharmony_ci if (connected) { 42708c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP2 connected\n"); 42718c2ecf20Sopenharmony_ci bios_0_scratch |= ATOM_S0_DFP2; 42728c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_DFP2_ACTIVE; 42738c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2; 42748c2ecf20Sopenharmony_ci } else { 42758c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP2 disconnected\n"); 42768c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_DFP2; 42778c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE; 42788c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2; 42798c2ecf20Sopenharmony_ci } 42808c2ecf20Sopenharmony_ci } 42818c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) && 42828c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) { 42838c2ecf20Sopenharmony_ci if (connected) { 42848c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP3 connected\n"); 42858c2ecf20Sopenharmony_ci bios_0_scratch |= ATOM_S0_DFP3; 42868c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_DFP3_ACTIVE; 42878c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3; 42888c2ecf20Sopenharmony_ci } else { 42898c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP3 disconnected\n"); 42908c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_DFP3; 42918c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE; 42928c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3; 42938c2ecf20Sopenharmony_ci } 42948c2ecf20Sopenharmony_ci } 42958c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) && 42968c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) { 42978c2ecf20Sopenharmony_ci if (connected) { 42988c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP4 connected\n"); 42998c2ecf20Sopenharmony_ci bios_0_scratch |= ATOM_S0_DFP4; 43008c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_DFP4_ACTIVE; 43018c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4; 43028c2ecf20Sopenharmony_ci } else { 43038c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP4 disconnected\n"); 43048c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_DFP4; 43058c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE; 43068c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4; 43078c2ecf20Sopenharmony_ci } 43088c2ecf20Sopenharmony_ci } 43098c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) && 43108c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) { 43118c2ecf20Sopenharmony_ci if (connected) { 43128c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP5 connected\n"); 43138c2ecf20Sopenharmony_ci bios_0_scratch |= ATOM_S0_DFP5; 43148c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_DFP5_ACTIVE; 43158c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5; 43168c2ecf20Sopenharmony_ci } else { 43178c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP5 disconnected\n"); 43188c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_DFP5; 43198c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE; 43208c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5; 43218c2ecf20Sopenharmony_ci } 43228c2ecf20Sopenharmony_ci } 43238c2ecf20Sopenharmony_ci if ((radeon_encoder->devices & ATOM_DEVICE_DFP6_SUPPORT) && 43248c2ecf20Sopenharmony_ci (radeon_connector->devices & ATOM_DEVICE_DFP6_SUPPORT)) { 43258c2ecf20Sopenharmony_ci if (connected) { 43268c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP6 connected\n"); 43278c2ecf20Sopenharmony_ci bios_0_scratch |= ATOM_S0_DFP6; 43288c2ecf20Sopenharmony_ci bios_3_scratch |= ATOM_S3_DFP6_ACTIVE; 43298c2ecf20Sopenharmony_ci bios_6_scratch |= ATOM_S6_ACC_REQ_DFP6; 43308c2ecf20Sopenharmony_ci } else { 43318c2ecf20Sopenharmony_ci DRM_DEBUG_KMS("DFP6 disconnected\n"); 43328c2ecf20Sopenharmony_ci bios_0_scratch &= ~ATOM_S0_DFP6; 43338c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_DFP6_ACTIVE; 43348c2ecf20Sopenharmony_ci bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP6; 43358c2ecf20Sopenharmony_ci } 43368c2ecf20Sopenharmony_ci } 43378c2ecf20Sopenharmony_ci 43388c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) { 43398c2ecf20Sopenharmony_ci WREG32(R600_BIOS_0_SCRATCH, bios_0_scratch); 43408c2ecf20Sopenharmony_ci WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch); 43418c2ecf20Sopenharmony_ci WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch); 43428c2ecf20Sopenharmony_ci } else { 43438c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch); 43448c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch); 43458c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch); 43468c2ecf20Sopenharmony_ci } 43478c2ecf20Sopenharmony_ci} 43488c2ecf20Sopenharmony_ci 43498c2ecf20Sopenharmony_civoid 43508c2ecf20Sopenharmony_ciradeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc) 43518c2ecf20Sopenharmony_ci{ 43528c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 43538c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 43548c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 43558c2ecf20Sopenharmony_ci uint32_t bios_3_scratch; 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 43588c2ecf20Sopenharmony_ci return; 43598c2ecf20Sopenharmony_ci 43608c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 43618c2ecf20Sopenharmony_ci bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH); 43628c2ecf20Sopenharmony_ci else 43638c2ecf20Sopenharmony_ci bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH); 43648c2ecf20Sopenharmony_ci 43658c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { 43668c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE; 43678c2ecf20Sopenharmony_ci bios_3_scratch |= (crtc << 18); 43688c2ecf20Sopenharmony_ci } 43698c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { 43708c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE; 43718c2ecf20Sopenharmony_ci bios_3_scratch |= (crtc << 24); 43728c2ecf20Sopenharmony_ci } 43738c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { 43748c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE; 43758c2ecf20Sopenharmony_ci bios_3_scratch |= (crtc << 16); 43768c2ecf20Sopenharmony_ci } 43778c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { 43788c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE; 43798c2ecf20Sopenharmony_ci bios_3_scratch |= (crtc << 20); 43808c2ecf20Sopenharmony_ci } 43818c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { 43828c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE; 43838c2ecf20Sopenharmony_ci bios_3_scratch |= (crtc << 17); 43848c2ecf20Sopenharmony_ci } 43858c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) { 43868c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE; 43878c2ecf20Sopenharmony_ci bios_3_scratch |= (crtc << 19); 43888c2ecf20Sopenharmony_ci } 43898c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) { 43908c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE; 43918c2ecf20Sopenharmony_ci bios_3_scratch |= (crtc << 23); 43928c2ecf20Sopenharmony_ci } 43938c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) { 43948c2ecf20Sopenharmony_ci bios_3_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE; 43958c2ecf20Sopenharmony_ci bios_3_scratch |= (crtc << 25); 43968c2ecf20Sopenharmony_ci } 43978c2ecf20Sopenharmony_ci 43988c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 43998c2ecf20Sopenharmony_ci WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch); 44008c2ecf20Sopenharmony_ci else 44018c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch); 44028c2ecf20Sopenharmony_ci} 44038c2ecf20Sopenharmony_ci 44048c2ecf20Sopenharmony_civoid 44058c2ecf20Sopenharmony_ciradeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on) 44068c2ecf20Sopenharmony_ci{ 44078c2ecf20Sopenharmony_ci struct drm_device *dev = encoder->dev; 44088c2ecf20Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 44098c2ecf20Sopenharmony_ci struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 44108c2ecf20Sopenharmony_ci uint32_t bios_2_scratch; 44118c2ecf20Sopenharmony_ci 44128c2ecf20Sopenharmony_ci if (ASIC_IS_DCE4(rdev)) 44138c2ecf20Sopenharmony_ci return; 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 44168c2ecf20Sopenharmony_ci bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH); 44178c2ecf20Sopenharmony_ci else 44188c2ecf20Sopenharmony_ci bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH); 44198c2ecf20Sopenharmony_ci 44208c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { 44218c2ecf20Sopenharmony_ci if (on) 44228c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE; 44238c2ecf20Sopenharmony_ci else 44248c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_TV1_DPMS_STATE; 44258c2ecf20Sopenharmony_ci } 44268c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { 44278c2ecf20Sopenharmony_ci if (on) 44288c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE; 44298c2ecf20Sopenharmony_ci else 44308c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_CV_DPMS_STATE; 44318c2ecf20Sopenharmony_ci } 44328c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { 44338c2ecf20Sopenharmony_ci if (on) 44348c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE; 44358c2ecf20Sopenharmony_ci else 44368c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_CRT1_DPMS_STATE; 44378c2ecf20Sopenharmony_ci } 44388c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { 44398c2ecf20Sopenharmony_ci if (on) 44408c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE; 44418c2ecf20Sopenharmony_ci else 44428c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_CRT2_DPMS_STATE; 44438c2ecf20Sopenharmony_ci } 44448c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { 44458c2ecf20Sopenharmony_ci if (on) 44468c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_LCD1_DPMS_STATE; 44478c2ecf20Sopenharmony_ci else 44488c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_LCD1_DPMS_STATE; 44498c2ecf20Sopenharmony_ci } 44508c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) { 44518c2ecf20Sopenharmony_ci if (on) 44528c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE; 44538c2ecf20Sopenharmony_ci else 44548c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_DFP1_DPMS_STATE; 44558c2ecf20Sopenharmony_ci } 44568c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) { 44578c2ecf20Sopenharmony_ci if (on) 44588c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE; 44598c2ecf20Sopenharmony_ci else 44608c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_DFP2_DPMS_STATE; 44618c2ecf20Sopenharmony_ci } 44628c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) { 44638c2ecf20Sopenharmony_ci if (on) 44648c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE; 44658c2ecf20Sopenharmony_ci else 44668c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_DFP3_DPMS_STATE; 44678c2ecf20Sopenharmony_ci } 44688c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) { 44698c2ecf20Sopenharmony_ci if (on) 44708c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_DFP4_DPMS_STATE; 44718c2ecf20Sopenharmony_ci else 44728c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_DFP4_DPMS_STATE; 44738c2ecf20Sopenharmony_ci } 44748c2ecf20Sopenharmony_ci if (radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) { 44758c2ecf20Sopenharmony_ci if (on) 44768c2ecf20Sopenharmony_ci bios_2_scratch &= ~ATOM_S2_DFP5_DPMS_STATE; 44778c2ecf20Sopenharmony_ci else 44788c2ecf20Sopenharmony_ci bios_2_scratch |= ATOM_S2_DFP5_DPMS_STATE; 44798c2ecf20Sopenharmony_ci } 44808c2ecf20Sopenharmony_ci 44818c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_R600) 44828c2ecf20Sopenharmony_ci WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch); 44838c2ecf20Sopenharmony_ci else 44848c2ecf20Sopenharmony_ci WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch); 44858c2ecf20Sopenharmony_ci} 4486