1fb4d8502Sjsg /* 2fb4d8502Sjsg * Copyright 2007-8 Advanced Micro Devices, Inc. 3fb4d8502Sjsg * Copyright 2008 Red Hat Inc. 4fb4d8502Sjsg * 5fb4d8502Sjsg * Permission is hereby granted, free of charge, to any person obtaining a 6fb4d8502Sjsg * copy of this software and associated documentation files (the "Software"), 7fb4d8502Sjsg * to deal in the Software without restriction, including without limitation 8fb4d8502Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9fb4d8502Sjsg * and/or sell copies of the Software, and to permit persons to whom the 10fb4d8502Sjsg * Software is furnished to do so, subject to the following conditions: 11fb4d8502Sjsg * 12fb4d8502Sjsg * The above copyright notice and this permission notice shall be included in 13fb4d8502Sjsg * all copies or substantial portions of the Software. 14fb4d8502Sjsg * 15fb4d8502Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16fb4d8502Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17fb4d8502Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18fb4d8502Sjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19fb4d8502Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20fb4d8502Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21fb4d8502Sjsg * OTHER DEALINGS IN THE SOFTWARE. 22fb4d8502Sjsg * 23fb4d8502Sjsg * Authors: Dave Airlie 24fb4d8502Sjsg * Alex Deucher 25fb4d8502Sjsg */ 26c349dbc7Sjsg 27fb4d8502Sjsg #include <drm/amdgpu_drm.h> 28fb4d8502Sjsg #include "amdgpu.h" 29fb4d8502Sjsg #include "amdgpu_atombios.h" 30fb4d8502Sjsg #include "amdgpu_atomfirmware.h" 31fb4d8502Sjsg #include "amdgpu_i2c.h" 32c349dbc7Sjsg #include "amdgpu_display.h" 33fb4d8502Sjsg 34fb4d8502Sjsg #include "atom.h" 35fb4d8502Sjsg #include "atom-bits.h" 36fb4d8502Sjsg #include "atombios_encoders.h" 37fb4d8502Sjsg #include "bif/bif_4_1_d.h" 38fb4d8502Sjsg 39fb4d8502Sjsg static void amdgpu_atombios_lookup_i2c_gpio_quirks(struct amdgpu_device *adev, 40fb4d8502Sjsg ATOM_GPIO_I2C_ASSIGMENT *gpio, 41fb4d8502Sjsg u8 index) 42fb4d8502Sjsg { 43fb4d8502Sjsg 44fb4d8502Sjsg } 45fb4d8502Sjsg 46fb4d8502Sjsg static struct amdgpu_i2c_bus_rec amdgpu_atombios_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio) 47fb4d8502Sjsg { 48fb4d8502Sjsg struct amdgpu_i2c_bus_rec i2c; 49fb4d8502Sjsg 50fb4d8502Sjsg memset(&i2c, 0, sizeof(struct amdgpu_i2c_bus_rec)); 51fb4d8502Sjsg 52fb4d8502Sjsg i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex); 53fb4d8502Sjsg i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex); 54fb4d8502Sjsg i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex); 55fb4d8502Sjsg i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex); 56fb4d8502Sjsg i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex); 57fb4d8502Sjsg i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex); 58fb4d8502Sjsg i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex); 59fb4d8502Sjsg i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex); 60fb4d8502Sjsg i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift); 61fb4d8502Sjsg i2c.mask_data_mask = (1 << gpio->ucDataMaskShift); 62fb4d8502Sjsg i2c.en_clk_mask = (1 << gpio->ucClkEnShift); 63fb4d8502Sjsg i2c.en_data_mask = (1 << gpio->ucDataEnShift); 64fb4d8502Sjsg i2c.y_clk_mask = (1 << gpio->ucClkY_Shift); 65fb4d8502Sjsg i2c.y_data_mask = (1 << gpio->ucDataY_Shift); 66fb4d8502Sjsg i2c.a_clk_mask = (1 << gpio->ucClkA_Shift); 67fb4d8502Sjsg i2c.a_data_mask = (1 << gpio->ucDataA_Shift); 68fb4d8502Sjsg 69fb4d8502Sjsg if (gpio->sucI2cId.sbfAccess.bfHW_Capable) 70fb4d8502Sjsg i2c.hw_capable = true; 71fb4d8502Sjsg else 72fb4d8502Sjsg i2c.hw_capable = false; 73fb4d8502Sjsg 74fb4d8502Sjsg if (gpio->sucI2cId.ucAccess == 0xa0) 75fb4d8502Sjsg i2c.mm_i2c = true; 76fb4d8502Sjsg else 77fb4d8502Sjsg i2c.mm_i2c = false; 78fb4d8502Sjsg 79fb4d8502Sjsg i2c.i2c_id = gpio->sucI2cId.ucAccess; 80fb4d8502Sjsg 81fb4d8502Sjsg if (i2c.mask_clk_reg) 82fb4d8502Sjsg i2c.valid = true; 83fb4d8502Sjsg else 84fb4d8502Sjsg i2c.valid = false; 85fb4d8502Sjsg 86fb4d8502Sjsg return i2c; 87fb4d8502Sjsg } 88fb4d8502Sjsg 89fb4d8502Sjsg struct amdgpu_i2c_bus_rec amdgpu_atombios_lookup_i2c_gpio(struct amdgpu_device *adev, 90fb4d8502Sjsg uint8_t id) 91fb4d8502Sjsg { 92fb4d8502Sjsg struct atom_context *ctx = adev->mode_info.atom_context; 93fb4d8502Sjsg ATOM_GPIO_I2C_ASSIGMENT *gpio; 94fb4d8502Sjsg struct amdgpu_i2c_bus_rec i2c; 95fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info); 96fb4d8502Sjsg struct _ATOM_GPIO_I2C_INFO *i2c_info; 97fb4d8502Sjsg uint16_t data_offset, size; 98fb4d8502Sjsg int i, num_indices; 99fb4d8502Sjsg 100fb4d8502Sjsg memset(&i2c, 0, sizeof(struct amdgpu_i2c_bus_rec)); 101fb4d8502Sjsg i2c.valid = false; 102fb4d8502Sjsg 103fb4d8502Sjsg if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { 104fb4d8502Sjsg i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); 105fb4d8502Sjsg 106fb4d8502Sjsg num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 107fb4d8502Sjsg sizeof(ATOM_GPIO_I2C_ASSIGMENT); 108fb4d8502Sjsg 109fb4d8502Sjsg gpio = &i2c_info->asGPIO_Info[0]; 110fb4d8502Sjsg for (i = 0; i < num_indices; i++) { 111fb4d8502Sjsg 112fb4d8502Sjsg amdgpu_atombios_lookup_i2c_gpio_quirks(adev, gpio, i); 113fb4d8502Sjsg 114fb4d8502Sjsg if (gpio->sucI2cId.ucAccess == id) { 115fb4d8502Sjsg i2c = amdgpu_atombios_get_bus_rec_for_i2c_gpio(gpio); 116fb4d8502Sjsg break; 117fb4d8502Sjsg } 118fb4d8502Sjsg gpio = (ATOM_GPIO_I2C_ASSIGMENT *) 119fb4d8502Sjsg ((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT)); 120fb4d8502Sjsg } 121fb4d8502Sjsg } 122fb4d8502Sjsg 123fb4d8502Sjsg return i2c; 124fb4d8502Sjsg } 125fb4d8502Sjsg 126fb4d8502Sjsg void amdgpu_atombios_i2c_init(struct amdgpu_device *adev) 127fb4d8502Sjsg { 128fb4d8502Sjsg struct atom_context *ctx = adev->mode_info.atom_context; 129fb4d8502Sjsg ATOM_GPIO_I2C_ASSIGMENT *gpio; 130fb4d8502Sjsg struct amdgpu_i2c_bus_rec i2c; 131fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info); 132fb4d8502Sjsg struct _ATOM_GPIO_I2C_INFO *i2c_info; 133fb4d8502Sjsg uint16_t data_offset, size; 134fb4d8502Sjsg int i, num_indices; 135fb4d8502Sjsg char stmp[32]; 136fb4d8502Sjsg 137fb4d8502Sjsg if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { 138fb4d8502Sjsg i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); 139fb4d8502Sjsg 140fb4d8502Sjsg num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 141fb4d8502Sjsg sizeof(ATOM_GPIO_I2C_ASSIGMENT); 142fb4d8502Sjsg 143fb4d8502Sjsg gpio = &i2c_info->asGPIO_Info[0]; 144fb4d8502Sjsg for (i = 0; i < num_indices; i++) { 145fb4d8502Sjsg amdgpu_atombios_lookup_i2c_gpio_quirks(adev, gpio, i); 146fb4d8502Sjsg 147fb4d8502Sjsg i2c = amdgpu_atombios_get_bus_rec_for_i2c_gpio(gpio); 148fb4d8502Sjsg 149fb4d8502Sjsg if (i2c.valid) { 150fb4d8502Sjsg snprintf(stmp, sizeof(stmp), "0x%x", i2c.i2c_id); 151ad8b1aafSjsg adev->i2c_bus[i] = amdgpu_i2c_create(adev_to_drm(adev), &i2c, stmp); 152fb4d8502Sjsg } 153fb4d8502Sjsg gpio = (ATOM_GPIO_I2C_ASSIGMENT *) 154fb4d8502Sjsg ((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT)); 155fb4d8502Sjsg } 156fb4d8502Sjsg } 157fb4d8502Sjsg } 158fb4d8502Sjsg 159fb4d8502Sjsg struct amdgpu_gpio_rec 160fb4d8502Sjsg amdgpu_atombios_lookup_gpio(struct amdgpu_device *adev, 161fb4d8502Sjsg u8 id) 162fb4d8502Sjsg { 163fb4d8502Sjsg struct atom_context *ctx = adev->mode_info.atom_context; 164fb4d8502Sjsg struct amdgpu_gpio_rec gpio; 165fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT); 166fb4d8502Sjsg struct _ATOM_GPIO_PIN_LUT *gpio_info; 167fb4d8502Sjsg ATOM_GPIO_PIN_ASSIGNMENT *pin; 168fb4d8502Sjsg u16 data_offset, size; 169fb4d8502Sjsg int i, num_indices; 170fb4d8502Sjsg 171fb4d8502Sjsg memset(&gpio, 0, sizeof(struct amdgpu_gpio_rec)); 172fb4d8502Sjsg gpio.valid = false; 173fb4d8502Sjsg 174fb4d8502Sjsg if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { 175fb4d8502Sjsg gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset); 176fb4d8502Sjsg 177fb4d8502Sjsg num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 178fb4d8502Sjsg sizeof(ATOM_GPIO_PIN_ASSIGNMENT); 179fb4d8502Sjsg 180fb4d8502Sjsg pin = gpio_info->asGPIO_Pin; 181fb4d8502Sjsg for (i = 0; i < num_indices; i++) { 182fb4d8502Sjsg if (id == pin->ucGPIO_ID) { 183fb4d8502Sjsg gpio.id = pin->ucGPIO_ID; 184fb4d8502Sjsg gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex); 185fb4d8502Sjsg gpio.shift = pin->ucGpioPinBitShift; 186fb4d8502Sjsg gpio.mask = (1 << pin->ucGpioPinBitShift); 187fb4d8502Sjsg gpio.valid = true; 188fb4d8502Sjsg break; 189fb4d8502Sjsg } 190fb4d8502Sjsg pin = (ATOM_GPIO_PIN_ASSIGNMENT *) 191fb4d8502Sjsg ((u8 *)pin + sizeof(ATOM_GPIO_PIN_ASSIGNMENT)); 192fb4d8502Sjsg } 193fb4d8502Sjsg } 194fb4d8502Sjsg 195fb4d8502Sjsg return gpio; 196fb4d8502Sjsg } 197fb4d8502Sjsg 198fb4d8502Sjsg static struct amdgpu_hpd 199fb4d8502Sjsg amdgpu_atombios_get_hpd_info_from_gpio(struct amdgpu_device *adev, 200fb4d8502Sjsg struct amdgpu_gpio_rec *gpio) 201fb4d8502Sjsg { 202fb4d8502Sjsg struct amdgpu_hpd hpd; 203fb4d8502Sjsg u32 reg; 204fb4d8502Sjsg 205fb4d8502Sjsg memset(&hpd, 0, sizeof(struct amdgpu_hpd)); 206fb4d8502Sjsg 207fb4d8502Sjsg reg = amdgpu_display_hpd_get_gpio_reg(adev); 208fb4d8502Sjsg 209fb4d8502Sjsg hpd.gpio = *gpio; 210fb4d8502Sjsg if (gpio->reg == reg) { 211fb4d8502Sjsg switch(gpio->mask) { 212fb4d8502Sjsg case (1 << 0): 213fb4d8502Sjsg hpd.hpd = AMDGPU_HPD_1; 214fb4d8502Sjsg break; 215fb4d8502Sjsg case (1 << 8): 216fb4d8502Sjsg hpd.hpd = AMDGPU_HPD_2; 217fb4d8502Sjsg break; 218fb4d8502Sjsg case (1 << 16): 219fb4d8502Sjsg hpd.hpd = AMDGPU_HPD_3; 220fb4d8502Sjsg break; 221fb4d8502Sjsg case (1 << 24): 222fb4d8502Sjsg hpd.hpd = AMDGPU_HPD_4; 223fb4d8502Sjsg break; 224fb4d8502Sjsg case (1 << 26): 225fb4d8502Sjsg hpd.hpd = AMDGPU_HPD_5; 226fb4d8502Sjsg break; 227fb4d8502Sjsg case (1 << 28): 228fb4d8502Sjsg hpd.hpd = AMDGPU_HPD_6; 229fb4d8502Sjsg break; 230fb4d8502Sjsg default: 231fb4d8502Sjsg hpd.hpd = AMDGPU_HPD_NONE; 232fb4d8502Sjsg break; 233fb4d8502Sjsg } 234fb4d8502Sjsg } else 235fb4d8502Sjsg hpd.hpd = AMDGPU_HPD_NONE; 236fb4d8502Sjsg return hpd; 237fb4d8502Sjsg } 238fb4d8502Sjsg 239fb4d8502Sjsg static const int object_connector_convert[] = { 240fb4d8502Sjsg DRM_MODE_CONNECTOR_Unknown, 241fb4d8502Sjsg DRM_MODE_CONNECTOR_DVII, 242fb4d8502Sjsg DRM_MODE_CONNECTOR_DVII, 243fb4d8502Sjsg DRM_MODE_CONNECTOR_DVID, 244fb4d8502Sjsg DRM_MODE_CONNECTOR_DVID, 245fb4d8502Sjsg DRM_MODE_CONNECTOR_VGA, 246fb4d8502Sjsg DRM_MODE_CONNECTOR_Composite, 247fb4d8502Sjsg DRM_MODE_CONNECTOR_SVIDEO, 248fb4d8502Sjsg DRM_MODE_CONNECTOR_Unknown, 249fb4d8502Sjsg DRM_MODE_CONNECTOR_Unknown, 250fb4d8502Sjsg DRM_MODE_CONNECTOR_9PinDIN, 251fb4d8502Sjsg DRM_MODE_CONNECTOR_Unknown, 252fb4d8502Sjsg DRM_MODE_CONNECTOR_HDMIA, 253fb4d8502Sjsg DRM_MODE_CONNECTOR_HDMIB, 254fb4d8502Sjsg DRM_MODE_CONNECTOR_LVDS, 255fb4d8502Sjsg DRM_MODE_CONNECTOR_9PinDIN, 256fb4d8502Sjsg DRM_MODE_CONNECTOR_Unknown, 257fb4d8502Sjsg DRM_MODE_CONNECTOR_Unknown, 258fb4d8502Sjsg DRM_MODE_CONNECTOR_Unknown, 259fb4d8502Sjsg DRM_MODE_CONNECTOR_DisplayPort, 260fb4d8502Sjsg DRM_MODE_CONNECTOR_eDP, 261fb4d8502Sjsg DRM_MODE_CONNECTOR_Unknown 262fb4d8502Sjsg }; 263fb4d8502Sjsg 264fb4d8502Sjsg bool amdgpu_atombios_has_dce_engine_info(struct amdgpu_device *adev) 265fb4d8502Sjsg { 266fb4d8502Sjsg struct amdgpu_mode_info *mode_info = &adev->mode_info; 267fb4d8502Sjsg struct atom_context *ctx = mode_info->atom_context; 268fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, Object_Header); 269fb4d8502Sjsg u16 size, data_offset; 270fb4d8502Sjsg u8 frev, crev; 271fb4d8502Sjsg ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj; 272fb4d8502Sjsg ATOM_OBJECT_HEADER *obj_header; 273fb4d8502Sjsg 274fb4d8502Sjsg if (!amdgpu_atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) 275fb4d8502Sjsg return false; 276fb4d8502Sjsg 277fb4d8502Sjsg if (crev < 2) 278fb4d8502Sjsg return false; 279fb4d8502Sjsg 280fb4d8502Sjsg obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset); 281fb4d8502Sjsg path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *) 282fb4d8502Sjsg (ctx->bios + data_offset + 283fb4d8502Sjsg le16_to_cpu(obj_header->usDisplayPathTableOffset)); 284fb4d8502Sjsg 285fb4d8502Sjsg if (path_obj->ucNumOfDispPath) 286fb4d8502Sjsg return true; 287fb4d8502Sjsg else 288fb4d8502Sjsg return false; 289fb4d8502Sjsg } 290fb4d8502Sjsg 291fb4d8502Sjsg bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev) 292fb4d8502Sjsg { 293fb4d8502Sjsg struct amdgpu_mode_info *mode_info = &adev->mode_info; 294fb4d8502Sjsg struct atom_context *ctx = mode_info->atom_context; 295fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, Object_Header); 296fb4d8502Sjsg u16 size, data_offset; 297fb4d8502Sjsg u8 frev, crev; 298fb4d8502Sjsg ATOM_CONNECTOR_OBJECT_TABLE *con_obj; 299fb4d8502Sjsg ATOM_ENCODER_OBJECT_TABLE *enc_obj; 300fb4d8502Sjsg ATOM_OBJECT_TABLE *router_obj; 301fb4d8502Sjsg ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj; 302fb4d8502Sjsg ATOM_OBJECT_HEADER *obj_header; 303fb4d8502Sjsg int i, j, k, path_size, device_support; 304fb4d8502Sjsg int connector_type; 305fb4d8502Sjsg u16 conn_id, connector_object_id; 306fb4d8502Sjsg struct amdgpu_i2c_bus_rec ddc_bus; 307fb4d8502Sjsg struct amdgpu_router router; 308fb4d8502Sjsg struct amdgpu_gpio_rec gpio; 309fb4d8502Sjsg struct amdgpu_hpd hpd; 310fb4d8502Sjsg 311fb4d8502Sjsg if (!amdgpu_atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) 312fb4d8502Sjsg return false; 313fb4d8502Sjsg 314fb4d8502Sjsg if (crev < 2) 315fb4d8502Sjsg return false; 316fb4d8502Sjsg 317fb4d8502Sjsg obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset); 318fb4d8502Sjsg path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *) 319fb4d8502Sjsg (ctx->bios + data_offset + 320fb4d8502Sjsg le16_to_cpu(obj_header->usDisplayPathTableOffset)); 321fb4d8502Sjsg con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *) 322fb4d8502Sjsg (ctx->bios + data_offset + 323fb4d8502Sjsg le16_to_cpu(obj_header->usConnectorObjectTableOffset)); 324fb4d8502Sjsg enc_obj = (ATOM_ENCODER_OBJECT_TABLE *) 325fb4d8502Sjsg (ctx->bios + data_offset + 326fb4d8502Sjsg le16_to_cpu(obj_header->usEncoderObjectTableOffset)); 327fb4d8502Sjsg router_obj = (ATOM_OBJECT_TABLE *) 328fb4d8502Sjsg (ctx->bios + data_offset + 329fb4d8502Sjsg le16_to_cpu(obj_header->usRouterObjectTableOffset)); 330fb4d8502Sjsg device_support = le16_to_cpu(obj_header->usDeviceSupport); 331fb4d8502Sjsg 332fb4d8502Sjsg path_size = 0; 333fb4d8502Sjsg for (i = 0; i < path_obj->ucNumOfDispPath; i++) { 334fb4d8502Sjsg uint8_t *addr = (uint8_t *) path_obj->asDispPath; 335fb4d8502Sjsg ATOM_DISPLAY_OBJECT_PATH *path; 336fb4d8502Sjsg addr += path_size; 337fb4d8502Sjsg path = (ATOM_DISPLAY_OBJECT_PATH *) addr; 338fb4d8502Sjsg path_size += le16_to_cpu(path->usSize); 339fb4d8502Sjsg 340fb4d8502Sjsg if (device_support & le16_to_cpu(path->usDeviceTag)) { 341328ac520Sjsg uint8_t con_obj_id = 342fb4d8502Sjsg (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) 343fb4d8502Sjsg >> OBJECT_ID_SHIFT; 344fb4d8502Sjsg 345fb4d8502Sjsg /* Skip TV/CV support */ 346fb4d8502Sjsg if ((le16_to_cpu(path->usDeviceTag) == 347fb4d8502Sjsg ATOM_DEVICE_TV1_SUPPORT) || 348fb4d8502Sjsg (le16_to_cpu(path->usDeviceTag) == 349fb4d8502Sjsg ATOM_DEVICE_CV_SUPPORT)) 350fb4d8502Sjsg continue; 351fb4d8502Sjsg 352fb4d8502Sjsg if (con_obj_id >= ARRAY_SIZE(object_connector_convert)) { 353fb4d8502Sjsg DRM_ERROR("invalid con_obj_id %d for device tag 0x%04x\n", 354fb4d8502Sjsg con_obj_id, le16_to_cpu(path->usDeviceTag)); 355fb4d8502Sjsg continue; 356fb4d8502Sjsg } 357fb4d8502Sjsg 358fb4d8502Sjsg connector_type = 359fb4d8502Sjsg object_connector_convert[con_obj_id]; 360fb4d8502Sjsg connector_object_id = con_obj_id; 361fb4d8502Sjsg 362fb4d8502Sjsg if (connector_type == DRM_MODE_CONNECTOR_Unknown) 363fb4d8502Sjsg continue; 364fb4d8502Sjsg 365fb4d8502Sjsg router.ddc_valid = false; 366fb4d8502Sjsg router.cd_valid = false; 367fb4d8502Sjsg for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) { 368328ac520Sjsg uint8_t grph_obj_type = 369fb4d8502Sjsg (le16_to_cpu(path->usGraphicObjIds[j]) & 370fb4d8502Sjsg OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; 371fb4d8502Sjsg 372fb4d8502Sjsg if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) { 373fb4d8502Sjsg for (k = 0; k < enc_obj->ucNumberOfObjects; k++) { 374fb4d8502Sjsg u16 encoder_obj = le16_to_cpu(enc_obj->asObjects[k].usObjectID); 375fb4d8502Sjsg if (le16_to_cpu(path->usGraphicObjIds[j]) == encoder_obj) { 376fb4d8502Sjsg ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *) 377fb4d8502Sjsg (ctx->bios + data_offset + 378fb4d8502Sjsg le16_to_cpu(enc_obj->asObjects[k].usRecordOffset)); 379fb4d8502Sjsg ATOM_ENCODER_CAP_RECORD *cap_record; 380fb4d8502Sjsg u16 caps = 0; 381fb4d8502Sjsg 382fb4d8502Sjsg while (record->ucRecordSize > 0 && 383fb4d8502Sjsg record->ucRecordType > 0 && 384fb4d8502Sjsg record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 385fb4d8502Sjsg switch (record->ucRecordType) { 386fb4d8502Sjsg case ATOM_ENCODER_CAP_RECORD_TYPE: 387fb4d8502Sjsg cap_record =(ATOM_ENCODER_CAP_RECORD *) 388fb4d8502Sjsg record; 389fb4d8502Sjsg caps = le16_to_cpu(cap_record->usEncoderCap); 390fb4d8502Sjsg break; 391fb4d8502Sjsg } 392fb4d8502Sjsg record = (ATOM_COMMON_RECORD_HEADER *) 393fb4d8502Sjsg ((char *)record + record->ucRecordSize); 394fb4d8502Sjsg } 395fb4d8502Sjsg amdgpu_display_add_encoder(adev, encoder_obj, 396fb4d8502Sjsg le16_to_cpu(path->usDeviceTag), 397fb4d8502Sjsg caps); 398fb4d8502Sjsg } 399fb4d8502Sjsg } 400fb4d8502Sjsg } else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) { 401fb4d8502Sjsg for (k = 0; k < router_obj->ucNumberOfObjects; k++) { 402fb4d8502Sjsg u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID); 403fb4d8502Sjsg if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) { 404fb4d8502Sjsg ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *) 405fb4d8502Sjsg (ctx->bios + data_offset + 406fb4d8502Sjsg le16_to_cpu(router_obj->asObjects[k].usRecordOffset)); 407fb4d8502Sjsg ATOM_I2C_RECORD *i2c_record; 408fb4d8502Sjsg ATOM_I2C_ID_CONFIG_ACCESS *i2c_config; 409fb4d8502Sjsg ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path; 410fb4d8502Sjsg ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path; 411fb4d8502Sjsg ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table = 412fb4d8502Sjsg (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) 413fb4d8502Sjsg (ctx->bios + data_offset + 414fb4d8502Sjsg le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset)); 415fb4d8502Sjsg u8 *num_dst_objs = (u8 *) 416fb4d8502Sjsg ((u8 *)router_src_dst_table + 1 + 417fb4d8502Sjsg (router_src_dst_table->ucNumberOfSrc * 2)); 418fb4d8502Sjsg u16 *dst_objs = (u16 *)(num_dst_objs + 1); 419fb4d8502Sjsg int enum_id; 420fb4d8502Sjsg 421fb4d8502Sjsg router.router_id = router_obj_id; 422fb4d8502Sjsg for (enum_id = 0; enum_id < (*num_dst_objs); enum_id++) { 423fb4d8502Sjsg if (le16_to_cpu(path->usConnObjectId) == 424fb4d8502Sjsg le16_to_cpu(dst_objs[enum_id])) 425fb4d8502Sjsg break; 426fb4d8502Sjsg } 427fb4d8502Sjsg 428fb4d8502Sjsg while (record->ucRecordSize > 0 && 429fb4d8502Sjsg record->ucRecordType > 0 && 430fb4d8502Sjsg record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 431fb4d8502Sjsg switch (record->ucRecordType) { 432fb4d8502Sjsg case ATOM_I2C_RECORD_TYPE: 433fb4d8502Sjsg i2c_record = 434fb4d8502Sjsg (ATOM_I2C_RECORD *) 435fb4d8502Sjsg record; 436fb4d8502Sjsg i2c_config = 437fb4d8502Sjsg (ATOM_I2C_ID_CONFIG_ACCESS *) 438fb4d8502Sjsg &i2c_record->sucI2cId; 439fb4d8502Sjsg router.i2c_info = 440fb4d8502Sjsg amdgpu_atombios_lookup_i2c_gpio(adev, 441fb4d8502Sjsg i2c_config-> 442fb4d8502Sjsg ucAccess); 443fb4d8502Sjsg router.i2c_addr = i2c_record->ucI2CAddr >> 1; 444fb4d8502Sjsg break; 445fb4d8502Sjsg case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE: 446fb4d8502Sjsg ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *) 447fb4d8502Sjsg record; 448fb4d8502Sjsg router.ddc_valid = true; 449fb4d8502Sjsg router.ddc_mux_type = ddc_path->ucMuxType; 450fb4d8502Sjsg router.ddc_mux_control_pin = ddc_path->ucMuxControlPin; 451fb4d8502Sjsg router.ddc_mux_state = ddc_path->ucMuxState[enum_id]; 452fb4d8502Sjsg break; 453fb4d8502Sjsg case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE: 454fb4d8502Sjsg cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *) 455fb4d8502Sjsg record; 456fb4d8502Sjsg router.cd_valid = true; 457fb4d8502Sjsg router.cd_mux_type = cd_path->ucMuxType; 458fb4d8502Sjsg router.cd_mux_control_pin = cd_path->ucMuxControlPin; 459fb4d8502Sjsg router.cd_mux_state = cd_path->ucMuxState[enum_id]; 460fb4d8502Sjsg break; 461fb4d8502Sjsg } 462fb4d8502Sjsg record = (ATOM_COMMON_RECORD_HEADER *) 463fb4d8502Sjsg ((char *)record + record->ucRecordSize); 464fb4d8502Sjsg } 465fb4d8502Sjsg } 466fb4d8502Sjsg } 467fb4d8502Sjsg } 468fb4d8502Sjsg } 469fb4d8502Sjsg 470fb4d8502Sjsg /* look up gpio for ddc, hpd */ 471fb4d8502Sjsg ddc_bus.valid = false; 472fb4d8502Sjsg hpd.hpd = AMDGPU_HPD_NONE; 473fb4d8502Sjsg if ((le16_to_cpu(path->usDeviceTag) & 474fb4d8502Sjsg (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) { 475fb4d8502Sjsg for (j = 0; j < con_obj->ucNumberOfObjects; j++) { 476fb4d8502Sjsg if (le16_to_cpu(path->usConnObjectId) == 477fb4d8502Sjsg le16_to_cpu(con_obj->asObjects[j]. 478fb4d8502Sjsg usObjectID)) { 479fb4d8502Sjsg ATOM_COMMON_RECORD_HEADER 480fb4d8502Sjsg *record = 481fb4d8502Sjsg (ATOM_COMMON_RECORD_HEADER 482fb4d8502Sjsg *) 483fb4d8502Sjsg (ctx->bios + data_offset + 484fb4d8502Sjsg le16_to_cpu(con_obj-> 485fb4d8502Sjsg asObjects[j]. 486fb4d8502Sjsg usRecordOffset)); 487fb4d8502Sjsg ATOM_I2C_RECORD *i2c_record; 488fb4d8502Sjsg ATOM_HPD_INT_RECORD *hpd_record; 489fb4d8502Sjsg ATOM_I2C_ID_CONFIG_ACCESS *i2c_config; 490fb4d8502Sjsg 491fb4d8502Sjsg while (record->ucRecordSize > 0 && 492fb4d8502Sjsg record->ucRecordType > 0 && 493fb4d8502Sjsg record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { 494fb4d8502Sjsg switch (record->ucRecordType) { 495fb4d8502Sjsg case ATOM_I2C_RECORD_TYPE: 496fb4d8502Sjsg i2c_record = 497fb4d8502Sjsg (ATOM_I2C_RECORD *) 498fb4d8502Sjsg record; 499fb4d8502Sjsg i2c_config = 500fb4d8502Sjsg (ATOM_I2C_ID_CONFIG_ACCESS *) 501fb4d8502Sjsg &i2c_record->sucI2cId; 502fb4d8502Sjsg ddc_bus = amdgpu_atombios_lookup_i2c_gpio(adev, 503fb4d8502Sjsg i2c_config-> 504fb4d8502Sjsg ucAccess); 505fb4d8502Sjsg break; 506fb4d8502Sjsg case ATOM_HPD_INT_RECORD_TYPE: 507fb4d8502Sjsg hpd_record = 508fb4d8502Sjsg (ATOM_HPD_INT_RECORD *) 509fb4d8502Sjsg record; 510fb4d8502Sjsg gpio = amdgpu_atombios_lookup_gpio(adev, 511fb4d8502Sjsg hpd_record->ucHPDIntGPIOID); 512fb4d8502Sjsg hpd = amdgpu_atombios_get_hpd_info_from_gpio(adev, &gpio); 513fb4d8502Sjsg hpd.plugged_state = hpd_record->ucPlugged_PinState; 514fb4d8502Sjsg break; 515fb4d8502Sjsg } 516fb4d8502Sjsg record = 517fb4d8502Sjsg (ATOM_COMMON_RECORD_HEADER 518fb4d8502Sjsg *) ((char *)record 519fb4d8502Sjsg + 520fb4d8502Sjsg record-> 521fb4d8502Sjsg ucRecordSize); 522fb4d8502Sjsg } 523fb4d8502Sjsg break; 524fb4d8502Sjsg } 525fb4d8502Sjsg } 526fb4d8502Sjsg } 527fb4d8502Sjsg 528fb4d8502Sjsg /* needed for aux chan transactions */ 529fb4d8502Sjsg ddc_bus.hpd = hpd.hpd; 530fb4d8502Sjsg 531fb4d8502Sjsg conn_id = le16_to_cpu(path->usConnObjectId); 532fb4d8502Sjsg 533fb4d8502Sjsg amdgpu_display_add_connector(adev, 534fb4d8502Sjsg conn_id, 535fb4d8502Sjsg le16_to_cpu(path->usDeviceTag), 536fb4d8502Sjsg connector_type, &ddc_bus, 537fb4d8502Sjsg connector_object_id, 538fb4d8502Sjsg &hpd, 539fb4d8502Sjsg &router); 540fb4d8502Sjsg 541fb4d8502Sjsg } 542fb4d8502Sjsg } 543fb4d8502Sjsg 544ad8b1aafSjsg amdgpu_link_encoder_connector(adev_to_drm(adev)); 545fb4d8502Sjsg 546fb4d8502Sjsg return true; 547fb4d8502Sjsg } 548fb4d8502Sjsg 549fb4d8502Sjsg union firmware_info { 550fb4d8502Sjsg ATOM_FIRMWARE_INFO info; 551fb4d8502Sjsg ATOM_FIRMWARE_INFO_V1_2 info_12; 552fb4d8502Sjsg ATOM_FIRMWARE_INFO_V1_3 info_13; 553fb4d8502Sjsg ATOM_FIRMWARE_INFO_V1_4 info_14; 554fb4d8502Sjsg ATOM_FIRMWARE_INFO_V2_1 info_21; 555fb4d8502Sjsg ATOM_FIRMWARE_INFO_V2_2 info_22; 556fb4d8502Sjsg }; 557fb4d8502Sjsg 558fb4d8502Sjsg int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev) 559fb4d8502Sjsg { 560fb4d8502Sjsg struct amdgpu_mode_info *mode_info = &adev->mode_info; 561fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); 562fb4d8502Sjsg uint8_t frev, crev; 563fb4d8502Sjsg uint16_t data_offset; 564fb4d8502Sjsg int ret = -EINVAL; 565fb4d8502Sjsg 566fb4d8502Sjsg if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL, 567fb4d8502Sjsg &frev, &crev, &data_offset)) { 568fb4d8502Sjsg int i; 569fb4d8502Sjsg struct amdgpu_pll *ppll = &adev->clock.ppll[0]; 570fb4d8502Sjsg struct amdgpu_pll *spll = &adev->clock.spll; 571fb4d8502Sjsg struct amdgpu_pll *mpll = &adev->clock.mpll; 572fb4d8502Sjsg union firmware_info *firmware_info = 573fb4d8502Sjsg (union firmware_info *)(mode_info->atom_context->bios + 574fb4d8502Sjsg data_offset); 575fb4d8502Sjsg /* pixel clocks */ 576fb4d8502Sjsg ppll->reference_freq = 577fb4d8502Sjsg le16_to_cpu(firmware_info->info.usReferenceClock); 578fb4d8502Sjsg ppll->reference_div = 0; 579fb4d8502Sjsg 580fb4d8502Sjsg ppll->pll_out_min = 581fb4d8502Sjsg le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output); 582fb4d8502Sjsg ppll->pll_out_max = 583fb4d8502Sjsg le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); 584fb4d8502Sjsg 585fb4d8502Sjsg ppll->lcd_pll_out_min = 586fb4d8502Sjsg le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100; 587fb4d8502Sjsg if (ppll->lcd_pll_out_min == 0) 588fb4d8502Sjsg ppll->lcd_pll_out_min = ppll->pll_out_min; 589fb4d8502Sjsg ppll->lcd_pll_out_max = 590fb4d8502Sjsg le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100; 591fb4d8502Sjsg if (ppll->lcd_pll_out_max == 0) 592fb4d8502Sjsg ppll->lcd_pll_out_max = ppll->pll_out_max; 593fb4d8502Sjsg 594fb4d8502Sjsg if (ppll->pll_out_min == 0) 595fb4d8502Sjsg ppll->pll_out_min = 64800; 596fb4d8502Sjsg 597fb4d8502Sjsg ppll->pll_in_min = 598fb4d8502Sjsg le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input); 599fb4d8502Sjsg ppll->pll_in_max = 600fb4d8502Sjsg le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input); 601fb4d8502Sjsg 602fb4d8502Sjsg ppll->min_post_div = 2; 603fb4d8502Sjsg ppll->max_post_div = 0x7f; 604fb4d8502Sjsg ppll->min_frac_feedback_div = 0; 605fb4d8502Sjsg ppll->max_frac_feedback_div = 9; 606fb4d8502Sjsg ppll->min_ref_div = 2; 607fb4d8502Sjsg ppll->max_ref_div = 0x3ff; 608fb4d8502Sjsg ppll->min_feedback_div = 4; 609fb4d8502Sjsg ppll->max_feedback_div = 0xfff; 610fb4d8502Sjsg ppll->best_vco = 0; 611fb4d8502Sjsg 612fb4d8502Sjsg for (i = 1; i < AMDGPU_MAX_PPLL; i++) 613fb4d8502Sjsg adev->clock.ppll[i] = *ppll; 614fb4d8502Sjsg 615fb4d8502Sjsg /* system clock */ 616fb4d8502Sjsg spll->reference_freq = 617fb4d8502Sjsg le16_to_cpu(firmware_info->info_21.usCoreReferenceClock); 618fb4d8502Sjsg spll->reference_div = 0; 619fb4d8502Sjsg 620fb4d8502Sjsg spll->pll_out_min = 621fb4d8502Sjsg le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output); 622fb4d8502Sjsg spll->pll_out_max = 623fb4d8502Sjsg le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output); 624fb4d8502Sjsg 625fb4d8502Sjsg /* ??? */ 626fb4d8502Sjsg if (spll->pll_out_min == 0) 627fb4d8502Sjsg spll->pll_out_min = 64800; 628fb4d8502Sjsg 629fb4d8502Sjsg spll->pll_in_min = 630fb4d8502Sjsg le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input); 631fb4d8502Sjsg spll->pll_in_max = 632fb4d8502Sjsg le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input); 633fb4d8502Sjsg 634fb4d8502Sjsg spll->min_post_div = 1; 635fb4d8502Sjsg spll->max_post_div = 1; 636fb4d8502Sjsg spll->min_ref_div = 2; 637fb4d8502Sjsg spll->max_ref_div = 0xff; 638fb4d8502Sjsg spll->min_feedback_div = 4; 639fb4d8502Sjsg spll->max_feedback_div = 0xff; 640fb4d8502Sjsg spll->best_vco = 0; 641fb4d8502Sjsg 642fb4d8502Sjsg /* memory clock */ 643fb4d8502Sjsg mpll->reference_freq = 644fb4d8502Sjsg le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock); 645fb4d8502Sjsg mpll->reference_div = 0; 646fb4d8502Sjsg 647fb4d8502Sjsg mpll->pll_out_min = 648fb4d8502Sjsg le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output); 649fb4d8502Sjsg mpll->pll_out_max = 650fb4d8502Sjsg le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output); 651fb4d8502Sjsg 652fb4d8502Sjsg /* ??? */ 653fb4d8502Sjsg if (mpll->pll_out_min == 0) 654fb4d8502Sjsg mpll->pll_out_min = 64800; 655fb4d8502Sjsg 656fb4d8502Sjsg mpll->pll_in_min = 657fb4d8502Sjsg le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input); 658fb4d8502Sjsg mpll->pll_in_max = 659fb4d8502Sjsg le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input); 660fb4d8502Sjsg 661fb4d8502Sjsg adev->clock.default_sclk = 662fb4d8502Sjsg le32_to_cpu(firmware_info->info.ulDefaultEngineClock); 663fb4d8502Sjsg adev->clock.default_mclk = 664fb4d8502Sjsg le32_to_cpu(firmware_info->info.ulDefaultMemoryClock); 665fb4d8502Sjsg 666fb4d8502Sjsg mpll->min_post_div = 1; 667fb4d8502Sjsg mpll->max_post_div = 1; 668fb4d8502Sjsg mpll->min_ref_div = 2; 669fb4d8502Sjsg mpll->max_ref_div = 0xff; 670fb4d8502Sjsg mpll->min_feedback_div = 4; 671fb4d8502Sjsg mpll->max_feedback_div = 0xff; 672fb4d8502Sjsg mpll->best_vco = 0; 673fb4d8502Sjsg 674fb4d8502Sjsg /* disp clock */ 675fb4d8502Sjsg adev->clock.default_dispclk = 676fb4d8502Sjsg le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq); 677fb4d8502Sjsg /* set a reasonable default for DP */ 678fb4d8502Sjsg if (adev->clock.default_dispclk < 53900) { 679fb4d8502Sjsg DRM_DEBUG("Changing default dispclk from %dMhz to 600Mhz\n", 680fb4d8502Sjsg adev->clock.default_dispclk / 100); 681fb4d8502Sjsg adev->clock.default_dispclk = 60000; 682fb4d8502Sjsg } else if (adev->clock.default_dispclk <= 60000) { 683fb4d8502Sjsg DRM_DEBUG("Changing default dispclk from %dMhz to 625Mhz\n", 684fb4d8502Sjsg adev->clock.default_dispclk / 100); 685fb4d8502Sjsg adev->clock.default_dispclk = 62500; 686fb4d8502Sjsg } 687fb4d8502Sjsg adev->clock.dp_extclk = 688fb4d8502Sjsg le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq); 689fb4d8502Sjsg adev->clock.current_dispclk = adev->clock.default_dispclk; 690fb4d8502Sjsg 691fb4d8502Sjsg adev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock); 692fb4d8502Sjsg if (adev->clock.max_pixel_clock == 0) 693fb4d8502Sjsg adev->clock.max_pixel_clock = 40000; 694fb4d8502Sjsg 695fb4d8502Sjsg /* not technically a clock, but... */ 696fb4d8502Sjsg adev->mode_info.firmware_flags = 697fb4d8502Sjsg le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess); 698fb4d8502Sjsg 699fb4d8502Sjsg ret = 0; 700fb4d8502Sjsg } 701fb4d8502Sjsg 702fb4d8502Sjsg adev->pm.current_sclk = adev->clock.default_sclk; 703fb4d8502Sjsg adev->pm.current_mclk = adev->clock.default_mclk; 704fb4d8502Sjsg 705fb4d8502Sjsg return ret; 706fb4d8502Sjsg } 707fb4d8502Sjsg 708fb4d8502Sjsg union gfx_info { 709fb4d8502Sjsg ATOM_GFX_INFO_V2_1 info; 710fb4d8502Sjsg }; 711fb4d8502Sjsg 712fb4d8502Sjsg int amdgpu_atombios_get_gfx_info(struct amdgpu_device *adev) 713fb4d8502Sjsg { 714fb4d8502Sjsg struct amdgpu_mode_info *mode_info = &adev->mode_info; 715fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, GFX_Info); 716fb4d8502Sjsg uint8_t frev, crev; 717fb4d8502Sjsg uint16_t data_offset; 718fb4d8502Sjsg int ret = -EINVAL; 719fb4d8502Sjsg 720fb4d8502Sjsg if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL, 721fb4d8502Sjsg &frev, &crev, &data_offset)) { 722fb4d8502Sjsg union gfx_info *gfx_info = (union gfx_info *) 723fb4d8502Sjsg (mode_info->atom_context->bios + data_offset); 724fb4d8502Sjsg 725fb4d8502Sjsg adev->gfx.config.max_shader_engines = gfx_info->info.max_shader_engines; 726fb4d8502Sjsg adev->gfx.config.max_tile_pipes = gfx_info->info.max_tile_pipes; 727fb4d8502Sjsg adev->gfx.config.max_cu_per_sh = gfx_info->info.max_cu_per_sh; 728fb4d8502Sjsg adev->gfx.config.max_sh_per_se = gfx_info->info.max_sh_per_se; 729fb4d8502Sjsg adev->gfx.config.max_backends_per_se = gfx_info->info.max_backends_per_se; 730fb4d8502Sjsg adev->gfx.config.max_texture_channel_caches = 731fb4d8502Sjsg gfx_info->info.max_texture_channel_caches; 732fb4d8502Sjsg 733fb4d8502Sjsg ret = 0; 734fb4d8502Sjsg } 735fb4d8502Sjsg return ret; 736fb4d8502Sjsg } 737fb4d8502Sjsg 738fb4d8502Sjsg union igp_info { 739fb4d8502Sjsg struct _ATOM_INTEGRATED_SYSTEM_INFO info; 740fb4d8502Sjsg struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; 741fb4d8502Sjsg struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; 742fb4d8502Sjsg struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; 743fb4d8502Sjsg struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; 744fb4d8502Sjsg struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9 info_9; 745fb4d8502Sjsg }; 746fb4d8502Sjsg 747fb4d8502Sjsg /* 748fb4d8502Sjsg * Return vram width from integrated system info table, if available, 749fb4d8502Sjsg * or 0 if not. 750fb4d8502Sjsg */ 751fb4d8502Sjsg int amdgpu_atombios_get_vram_width(struct amdgpu_device *adev) 752fb4d8502Sjsg { 753fb4d8502Sjsg struct amdgpu_mode_info *mode_info = &adev->mode_info; 754fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 755fb4d8502Sjsg u16 data_offset, size; 756fb4d8502Sjsg union igp_info *igp_info; 757fb4d8502Sjsg u8 frev, crev; 758fb4d8502Sjsg 759fb4d8502Sjsg /* get any igp specific overrides */ 760fb4d8502Sjsg if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size, 761fb4d8502Sjsg &frev, &crev, &data_offset)) { 762fb4d8502Sjsg igp_info = (union igp_info *) 763fb4d8502Sjsg (mode_info->atom_context->bios + data_offset); 764fb4d8502Sjsg switch (crev) { 765fb4d8502Sjsg case 8: 766fb4d8502Sjsg case 9: 767fb4d8502Sjsg return igp_info->info_8.ucUMAChannelNumber * 64; 768fb4d8502Sjsg default: 769fb4d8502Sjsg return 0; 770fb4d8502Sjsg } 771fb4d8502Sjsg } 772fb4d8502Sjsg 773fb4d8502Sjsg return 0; 774fb4d8502Sjsg } 775fb4d8502Sjsg 776fb4d8502Sjsg static void amdgpu_atombios_get_igp_ss_overrides(struct amdgpu_device *adev, 777fb4d8502Sjsg struct amdgpu_atom_ss *ss, 778fb4d8502Sjsg int id) 779fb4d8502Sjsg { 780fb4d8502Sjsg struct amdgpu_mode_info *mode_info = &adev->mode_info; 781fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 782fb4d8502Sjsg u16 data_offset, size; 783fb4d8502Sjsg union igp_info *igp_info; 784fb4d8502Sjsg u8 frev, crev; 785fb4d8502Sjsg u16 percentage = 0, rate = 0; 786fb4d8502Sjsg 787fb4d8502Sjsg /* get any igp specific overrides */ 788fb4d8502Sjsg if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size, 789fb4d8502Sjsg &frev, &crev, &data_offset)) { 790fb4d8502Sjsg igp_info = (union igp_info *) 791fb4d8502Sjsg (mode_info->atom_context->bios + data_offset); 792fb4d8502Sjsg switch (crev) { 793fb4d8502Sjsg case 6: 794fb4d8502Sjsg switch (id) { 795fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_TMDS: 796fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage); 797fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz); 798fb4d8502Sjsg break; 799fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_HDMI: 800fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage); 801fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz); 802fb4d8502Sjsg break; 803fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_LVDS: 804fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage); 805fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz); 806fb4d8502Sjsg break; 807fb4d8502Sjsg } 808fb4d8502Sjsg break; 809fb4d8502Sjsg case 7: 810fb4d8502Sjsg switch (id) { 811fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_TMDS: 812fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage); 813fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz); 814fb4d8502Sjsg break; 815fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_HDMI: 816fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage); 817fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz); 818fb4d8502Sjsg break; 819fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_LVDS: 820fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage); 821fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz); 822fb4d8502Sjsg break; 823fb4d8502Sjsg } 824fb4d8502Sjsg break; 825fb4d8502Sjsg case 8: 826fb4d8502Sjsg switch (id) { 827fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_TMDS: 828fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage); 829fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz); 830fb4d8502Sjsg break; 831fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_HDMI: 832fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage); 833fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz); 834fb4d8502Sjsg break; 835fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_LVDS: 836fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage); 837fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz); 838fb4d8502Sjsg break; 839fb4d8502Sjsg } 840fb4d8502Sjsg break; 841fb4d8502Sjsg case 9: 842fb4d8502Sjsg switch (id) { 843fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_TMDS: 844fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_9.usDVISSPercentage); 845fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_9.usDVISSpreadRateIn10Hz); 846fb4d8502Sjsg break; 847fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_HDMI: 848fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_9.usHDMISSPercentage); 849fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_9.usHDMISSpreadRateIn10Hz); 850fb4d8502Sjsg break; 851fb4d8502Sjsg case ASIC_INTERNAL_SS_ON_LVDS: 852fb4d8502Sjsg percentage = le16_to_cpu(igp_info->info_9.usLvdsSSPercentage); 853fb4d8502Sjsg rate = le16_to_cpu(igp_info->info_9.usLvdsSSpreadRateIn10Hz); 854fb4d8502Sjsg break; 855fb4d8502Sjsg } 856fb4d8502Sjsg break; 857fb4d8502Sjsg default: 858fb4d8502Sjsg DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); 859fb4d8502Sjsg break; 860fb4d8502Sjsg } 861fb4d8502Sjsg if (percentage) 862fb4d8502Sjsg ss->percentage = percentage; 863fb4d8502Sjsg if (rate) 864fb4d8502Sjsg ss->rate = rate; 865fb4d8502Sjsg } 866fb4d8502Sjsg } 867fb4d8502Sjsg 868fb4d8502Sjsg union asic_ss_info { 869fb4d8502Sjsg struct _ATOM_ASIC_INTERNAL_SS_INFO info; 870fb4d8502Sjsg struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2; 871fb4d8502Sjsg struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3; 872fb4d8502Sjsg }; 873fb4d8502Sjsg 874fb4d8502Sjsg union asic_ss_assignment { 875fb4d8502Sjsg struct _ATOM_ASIC_SS_ASSIGNMENT v1; 876fb4d8502Sjsg struct _ATOM_ASIC_SS_ASSIGNMENT_V2 v2; 877fb4d8502Sjsg struct _ATOM_ASIC_SS_ASSIGNMENT_V3 v3; 878fb4d8502Sjsg }; 879fb4d8502Sjsg 880fb4d8502Sjsg bool amdgpu_atombios_get_asic_ss_info(struct amdgpu_device *adev, 881fb4d8502Sjsg struct amdgpu_atom_ss *ss, 882fb4d8502Sjsg int id, u32 clock) 883fb4d8502Sjsg { 884fb4d8502Sjsg struct amdgpu_mode_info *mode_info = &adev->mode_info; 885fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); 886fb4d8502Sjsg uint16_t data_offset, size; 887fb4d8502Sjsg union asic_ss_info *ss_info; 888fb4d8502Sjsg union asic_ss_assignment *ss_assign; 889fb4d8502Sjsg uint8_t frev, crev; 890fb4d8502Sjsg int i, num_indices; 891fb4d8502Sjsg 892fb4d8502Sjsg if (id == ASIC_INTERNAL_MEMORY_SS) { 893fb4d8502Sjsg if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT)) 894fb4d8502Sjsg return false; 895fb4d8502Sjsg } 896fb4d8502Sjsg if (id == ASIC_INTERNAL_ENGINE_SS) { 897fb4d8502Sjsg if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT)) 898fb4d8502Sjsg return false; 899fb4d8502Sjsg } 900fb4d8502Sjsg 901fb4d8502Sjsg memset(ss, 0, sizeof(struct amdgpu_atom_ss)); 902fb4d8502Sjsg if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size, 903fb4d8502Sjsg &frev, &crev, &data_offset)) { 904fb4d8502Sjsg 905fb4d8502Sjsg ss_info = 906fb4d8502Sjsg (union asic_ss_info *)(mode_info->atom_context->bios + data_offset); 907fb4d8502Sjsg 908fb4d8502Sjsg switch (frev) { 909fb4d8502Sjsg case 1: 910fb4d8502Sjsg num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 911fb4d8502Sjsg sizeof(ATOM_ASIC_SS_ASSIGNMENT); 912fb4d8502Sjsg 913fb4d8502Sjsg ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info.asSpreadSpectrum[0]); 914fb4d8502Sjsg for (i = 0; i < num_indices; i++) { 915fb4d8502Sjsg if ((ss_assign->v1.ucClockIndication == id) && 916fb4d8502Sjsg (clock <= le32_to_cpu(ss_assign->v1.ulTargetClockRange))) { 917fb4d8502Sjsg ss->percentage = 918fb4d8502Sjsg le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage); 919fb4d8502Sjsg ss->type = ss_assign->v1.ucSpreadSpectrumMode; 920fb4d8502Sjsg ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz); 921fb4d8502Sjsg ss->percentage_divider = 100; 922fb4d8502Sjsg return true; 923fb4d8502Sjsg } 924fb4d8502Sjsg ss_assign = (union asic_ss_assignment *) 925fb4d8502Sjsg ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT)); 926fb4d8502Sjsg } 927fb4d8502Sjsg break; 928fb4d8502Sjsg case 2: 929fb4d8502Sjsg num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 930fb4d8502Sjsg sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2); 931fb4d8502Sjsg ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_2.asSpreadSpectrum[0]); 932fb4d8502Sjsg for (i = 0; i < num_indices; i++) { 933fb4d8502Sjsg if ((ss_assign->v2.ucClockIndication == id) && 934fb4d8502Sjsg (clock <= le32_to_cpu(ss_assign->v2.ulTargetClockRange))) { 935fb4d8502Sjsg ss->percentage = 936fb4d8502Sjsg le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage); 937fb4d8502Sjsg ss->type = ss_assign->v2.ucSpreadSpectrumMode; 938fb4d8502Sjsg ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz); 939fb4d8502Sjsg ss->percentage_divider = 100; 940fb4d8502Sjsg if ((crev == 2) && 941fb4d8502Sjsg ((id == ASIC_INTERNAL_ENGINE_SS) || 942fb4d8502Sjsg (id == ASIC_INTERNAL_MEMORY_SS))) 943fb4d8502Sjsg ss->rate /= 100; 944fb4d8502Sjsg return true; 945fb4d8502Sjsg } 946fb4d8502Sjsg ss_assign = (union asic_ss_assignment *) 947fb4d8502Sjsg ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2)); 948fb4d8502Sjsg } 949fb4d8502Sjsg break; 950fb4d8502Sjsg case 3: 951fb4d8502Sjsg num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / 952fb4d8502Sjsg sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3); 953fb4d8502Sjsg ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_3.asSpreadSpectrum[0]); 954fb4d8502Sjsg for (i = 0; i < num_indices; i++) { 955fb4d8502Sjsg if ((ss_assign->v3.ucClockIndication == id) && 956fb4d8502Sjsg (clock <= le32_to_cpu(ss_assign->v3.ulTargetClockRange))) { 957fb4d8502Sjsg ss->percentage = 958fb4d8502Sjsg le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage); 959fb4d8502Sjsg ss->type = ss_assign->v3.ucSpreadSpectrumMode; 960fb4d8502Sjsg ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz); 961fb4d8502Sjsg if (ss_assign->v3.ucSpreadSpectrumMode & 962fb4d8502Sjsg SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK) 963fb4d8502Sjsg ss->percentage_divider = 1000; 964fb4d8502Sjsg else 965fb4d8502Sjsg ss->percentage_divider = 100; 966fb4d8502Sjsg if ((id == ASIC_INTERNAL_ENGINE_SS) || 967fb4d8502Sjsg (id == ASIC_INTERNAL_MEMORY_SS)) 968fb4d8502Sjsg ss->rate /= 100; 969fb4d8502Sjsg if (adev->flags & AMD_IS_APU) 970fb4d8502Sjsg amdgpu_atombios_get_igp_ss_overrides(adev, ss, id); 971fb4d8502Sjsg return true; 972fb4d8502Sjsg } 973fb4d8502Sjsg ss_assign = (union asic_ss_assignment *) 974fb4d8502Sjsg ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3)); 975fb4d8502Sjsg } 976fb4d8502Sjsg break; 977fb4d8502Sjsg default: 978fb4d8502Sjsg DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev); 979fb4d8502Sjsg break; 980fb4d8502Sjsg } 981fb4d8502Sjsg 982fb4d8502Sjsg } 983fb4d8502Sjsg return false; 984fb4d8502Sjsg } 985fb4d8502Sjsg 986fb4d8502Sjsg union get_clock_dividers { 987fb4d8502Sjsg struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1; 988fb4d8502Sjsg struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2; 989fb4d8502Sjsg struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3; 990fb4d8502Sjsg struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4; 991fb4d8502Sjsg struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5; 992fb4d8502Sjsg struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in; 993fb4d8502Sjsg struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out; 994fb4d8502Sjsg }; 995fb4d8502Sjsg 996fb4d8502Sjsg int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev, 997fb4d8502Sjsg u8 clock_type, 998fb4d8502Sjsg u32 clock, 999fb4d8502Sjsg bool strobe_mode, 1000fb4d8502Sjsg struct atom_clock_dividers *dividers) 1001fb4d8502Sjsg { 1002fb4d8502Sjsg union get_clock_dividers args; 1003fb4d8502Sjsg int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL); 1004fb4d8502Sjsg u8 frev, crev; 1005fb4d8502Sjsg 1006fb4d8502Sjsg memset(&args, 0, sizeof(args)); 1007fb4d8502Sjsg memset(dividers, 0, sizeof(struct atom_clock_dividers)); 1008fb4d8502Sjsg 1009fb4d8502Sjsg if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev)) 1010fb4d8502Sjsg return -EINVAL; 1011fb4d8502Sjsg 1012fb4d8502Sjsg switch (crev) { 1013fb4d8502Sjsg case 2: 1014fb4d8502Sjsg case 3: 1015fb4d8502Sjsg case 5: 1016fb4d8502Sjsg /* r6xx, r7xx, evergreen, ni, si. 1017fb4d8502Sjsg * TODO: add support for asic_type <= CHIP_RV770*/ 1018fb4d8502Sjsg if (clock_type == COMPUTE_ENGINE_PLL_PARAM) { 1019fb4d8502Sjsg args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock); 1020fb4d8502Sjsg 1021fb4d8502Sjsg amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 1022fb4d8502Sjsg 1023fb4d8502Sjsg dividers->post_div = args.v3.ucPostDiv; 1024fb4d8502Sjsg dividers->enable_post_div = (args.v3.ucCntlFlag & 1025fb4d8502Sjsg ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false; 1026fb4d8502Sjsg dividers->enable_dithen = (args.v3.ucCntlFlag & 1027fb4d8502Sjsg ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true; 1028fb4d8502Sjsg dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv); 1029fb4d8502Sjsg dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac); 1030fb4d8502Sjsg dividers->ref_div = args.v3.ucRefDiv; 1031fb4d8502Sjsg dividers->vco_mode = (args.v3.ucCntlFlag & 1032fb4d8502Sjsg ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0; 1033fb4d8502Sjsg } else { 1034fb4d8502Sjsg /* for SI we use ComputeMemoryClockParam for memory plls */ 1035fb4d8502Sjsg if (adev->asic_type >= CHIP_TAHITI) 1036fb4d8502Sjsg return -EINVAL; 1037fb4d8502Sjsg args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock); 1038fb4d8502Sjsg if (strobe_mode) 1039fb4d8502Sjsg args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN; 1040fb4d8502Sjsg 1041fb4d8502Sjsg amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 1042fb4d8502Sjsg 1043fb4d8502Sjsg dividers->post_div = args.v5.ucPostDiv; 1044fb4d8502Sjsg dividers->enable_post_div = (args.v5.ucCntlFlag & 1045fb4d8502Sjsg ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false; 1046fb4d8502Sjsg dividers->enable_dithen = (args.v5.ucCntlFlag & 1047fb4d8502Sjsg ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true; 1048fb4d8502Sjsg dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv); 1049fb4d8502Sjsg dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac); 1050fb4d8502Sjsg dividers->ref_div = args.v5.ucRefDiv; 1051fb4d8502Sjsg dividers->vco_mode = (args.v5.ucCntlFlag & 1052fb4d8502Sjsg ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0; 1053fb4d8502Sjsg } 1054fb4d8502Sjsg break; 1055fb4d8502Sjsg case 4: 1056fb4d8502Sjsg /* fusion */ 1057fb4d8502Sjsg args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */ 1058fb4d8502Sjsg 1059fb4d8502Sjsg amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 1060fb4d8502Sjsg 1061fb4d8502Sjsg dividers->post_divider = dividers->post_div = args.v4.ucPostDiv; 1062fb4d8502Sjsg dividers->real_clock = le32_to_cpu(args.v4.ulClock); 1063fb4d8502Sjsg break; 1064fb4d8502Sjsg case 6: 1065fb4d8502Sjsg /* CI */ 1066fb4d8502Sjsg /* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */ 1067fb4d8502Sjsg args.v6_in.ulClock.ulComputeClockFlag = clock_type; 1068fb4d8502Sjsg args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */ 1069fb4d8502Sjsg 1070fb4d8502Sjsg amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 1071fb4d8502Sjsg 1072fb4d8502Sjsg dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv); 1073fb4d8502Sjsg dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac); 1074fb4d8502Sjsg dividers->ref_div = args.v6_out.ucPllRefDiv; 1075fb4d8502Sjsg dividers->post_div = args.v6_out.ucPllPostDiv; 1076fb4d8502Sjsg dividers->flags = args.v6_out.ucPllCntlFlag; 1077fb4d8502Sjsg dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock); 1078fb4d8502Sjsg dividers->post_divider = args.v6_out.ulClock.ucPostDiv; 1079fb4d8502Sjsg break; 1080fb4d8502Sjsg default: 1081fb4d8502Sjsg return -EINVAL; 1082fb4d8502Sjsg } 1083fb4d8502Sjsg return 0; 1084fb4d8502Sjsg } 1085fb4d8502Sjsg 10861bb76ff1Sjsg #ifdef CONFIG_DRM_AMDGPU_SI 1087fb4d8502Sjsg int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev, 1088fb4d8502Sjsg u32 clock, 1089fb4d8502Sjsg bool strobe_mode, 1090fb4d8502Sjsg struct atom_mpll_param *mpll_param) 1091fb4d8502Sjsg { 1092fb4d8502Sjsg COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 args; 1093fb4d8502Sjsg int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam); 1094fb4d8502Sjsg u8 frev, crev; 1095fb4d8502Sjsg 1096fb4d8502Sjsg memset(&args, 0, sizeof(args)); 1097fb4d8502Sjsg memset(mpll_param, 0, sizeof(struct atom_mpll_param)); 1098fb4d8502Sjsg 1099fb4d8502Sjsg if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev)) 1100fb4d8502Sjsg return -EINVAL; 1101fb4d8502Sjsg 1102fb4d8502Sjsg switch (frev) { 1103fb4d8502Sjsg case 2: 1104fb4d8502Sjsg switch (crev) { 1105fb4d8502Sjsg case 1: 1106fb4d8502Sjsg /* SI */ 1107fb4d8502Sjsg args.ulClock = cpu_to_le32(clock); /* 10 khz */ 1108fb4d8502Sjsg args.ucInputFlag = 0; 1109fb4d8502Sjsg if (strobe_mode) 1110fb4d8502Sjsg args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN; 1111fb4d8502Sjsg 1112fb4d8502Sjsg amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 1113fb4d8502Sjsg 1114fb4d8502Sjsg mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac); 1115fb4d8502Sjsg mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv); 1116fb4d8502Sjsg mpll_param->post_div = args.ucPostDiv; 1117fb4d8502Sjsg mpll_param->dll_speed = args.ucDllSpeed; 1118fb4d8502Sjsg mpll_param->bwcntl = args.ucBWCntl; 1119fb4d8502Sjsg mpll_param->vco_mode = 1120fb4d8502Sjsg (args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK); 1121fb4d8502Sjsg mpll_param->yclk_sel = 1122fb4d8502Sjsg (args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0; 1123fb4d8502Sjsg mpll_param->qdr = 1124fb4d8502Sjsg (args.ucPllCntlFlag & MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0; 1125fb4d8502Sjsg mpll_param->half_rate = 1126fb4d8502Sjsg (args.ucPllCntlFlag & MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0; 1127fb4d8502Sjsg break; 1128fb4d8502Sjsg default: 1129fb4d8502Sjsg return -EINVAL; 1130fb4d8502Sjsg } 1131fb4d8502Sjsg break; 1132fb4d8502Sjsg default: 1133fb4d8502Sjsg return -EINVAL; 1134fb4d8502Sjsg } 1135fb4d8502Sjsg return 0; 1136fb4d8502Sjsg } 1137fb4d8502Sjsg 1138fb4d8502Sjsg void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev, 1139fb4d8502Sjsg u32 eng_clock, u32 mem_clock) 1140fb4d8502Sjsg { 1141fb4d8502Sjsg SET_ENGINE_CLOCK_PS_ALLOCATION args; 1142fb4d8502Sjsg int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings); 1143fb4d8502Sjsg u32 tmp; 1144fb4d8502Sjsg 1145fb4d8502Sjsg memset(&args, 0, sizeof(args)); 1146fb4d8502Sjsg 1147fb4d8502Sjsg tmp = eng_clock & SET_CLOCK_FREQ_MASK; 1148fb4d8502Sjsg tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24); 1149fb4d8502Sjsg 1150fb4d8502Sjsg args.ulTargetEngineClock = cpu_to_le32(tmp); 1151fb4d8502Sjsg if (mem_clock) 1152fb4d8502Sjsg args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK); 1153fb4d8502Sjsg 1154fb4d8502Sjsg amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 1155fb4d8502Sjsg } 1156fb4d8502Sjsg 1157fb4d8502Sjsg void amdgpu_atombios_get_default_voltages(struct amdgpu_device *adev, 1158fb4d8502Sjsg u16 *vddc, u16 *vddci, u16 *mvdd) 1159fb4d8502Sjsg { 1160fb4d8502Sjsg struct amdgpu_mode_info *mode_info = &adev->mode_info; 1161fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); 1162fb4d8502Sjsg u8 frev, crev; 1163fb4d8502Sjsg u16 data_offset; 1164fb4d8502Sjsg union firmware_info *firmware_info; 1165fb4d8502Sjsg 1166fb4d8502Sjsg *vddc = 0; 1167fb4d8502Sjsg *vddci = 0; 1168fb4d8502Sjsg *mvdd = 0; 1169fb4d8502Sjsg 1170fb4d8502Sjsg if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL, 1171fb4d8502Sjsg &frev, &crev, &data_offset)) { 1172fb4d8502Sjsg firmware_info = 1173fb4d8502Sjsg (union firmware_info *)(mode_info->atom_context->bios + 1174fb4d8502Sjsg data_offset); 1175fb4d8502Sjsg *vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage); 1176fb4d8502Sjsg if ((frev == 2) && (crev >= 2)) { 1177fb4d8502Sjsg *vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage); 1178fb4d8502Sjsg *mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage); 1179fb4d8502Sjsg } 1180fb4d8502Sjsg } 1181fb4d8502Sjsg } 1182fb4d8502Sjsg 1183fb4d8502Sjsg union set_voltage { 1184fb4d8502Sjsg struct _SET_VOLTAGE_PS_ALLOCATION alloc; 1185fb4d8502Sjsg struct _SET_VOLTAGE_PARAMETERS v1; 1186fb4d8502Sjsg struct _SET_VOLTAGE_PARAMETERS_V2 v2; 1187fb4d8502Sjsg struct _SET_VOLTAGE_PARAMETERS_V1_3 v3; 1188fb4d8502Sjsg }; 1189fb4d8502Sjsg 1190fb4d8502Sjsg int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type, 1191fb4d8502Sjsg u16 voltage_id, u16 *voltage) 1192fb4d8502Sjsg { 1193fb4d8502Sjsg union set_voltage args; 1194fb4d8502Sjsg int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); 1195fb4d8502Sjsg u8 frev, crev; 1196fb4d8502Sjsg 1197fb4d8502Sjsg if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev)) 1198fb4d8502Sjsg return -EINVAL; 1199fb4d8502Sjsg 1200fb4d8502Sjsg switch (crev) { 1201fb4d8502Sjsg case 1: 1202fb4d8502Sjsg return -EINVAL; 1203fb4d8502Sjsg case 2: 1204fb4d8502Sjsg args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE; 1205fb4d8502Sjsg args.v2.ucVoltageMode = 0; 1206fb4d8502Sjsg args.v2.usVoltageLevel = 0; 1207fb4d8502Sjsg 1208fb4d8502Sjsg amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 1209fb4d8502Sjsg 1210fb4d8502Sjsg *voltage = le16_to_cpu(args.v2.usVoltageLevel); 1211fb4d8502Sjsg break; 1212fb4d8502Sjsg case 3: 1213fb4d8502Sjsg args.v3.ucVoltageType = voltage_type; 1214fb4d8502Sjsg args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL; 1215fb4d8502Sjsg args.v3.usVoltageLevel = cpu_to_le16(voltage_id); 1216fb4d8502Sjsg 1217fb4d8502Sjsg amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); 1218fb4d8502Sjsg 1219fb4d8502Sjsg *voltage = le16_to_cpu(args.v3.usVoltageLevel); 1220fb4d8502Sjsg break; 1221fb4d8502Sjsg default: 1222fb4d8502Sjsg DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 1223fb4d8502Sjsg return -EINVAL; 1224fb4d8502Sjsg } 1225fb4d8502Sjsg 1226fb4d8502Sjsg return 0; 1227fb4d8502Sjsg } 1228fb4d8502Sjsg 1229fb4d8502Sjsg int amdgpu_atombios_get_leakage_vddc_based_on_leakage_idx(struct amdgpu_device *adev, 1230fb4d8502Sjsg u16 *voltage, 1231fb4d8502Sjsg u16 leakage_idx) 1232fb4d8502Sjsg { 1233fb4d8502Sjsg return amdgpu_atombios_get_max_vddc(adev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage); 1234fb4d8502Sjsg } 1235fb4d8502Sjsg 1236fb4d8502Sjsg union voltage_object_info { 1237fb4d8502Sjsg struct _ATOM_VOLTAGE_OBJECT_INFO v1; 1238fb4d8502Sjsg struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2; 1239fb4d8502Sjsg struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3; 1240fb4d8502Sjsg }; 1241fb4d8502Sjsg 1242fb4d8502Sjsg union voltage_object { 1243fb4d8502Sjsg struct _ATOM_VOLTAGE_OBJECT v1; 1244fb4d8502Sjsg struct _ATOM_VOLTAGE_OBJECT_V2 v2; 1245fb4d8502Sjsg union _ATOM_VOLTAGE_OBJECT_V3 v3; 1246fb4d8502Sjsg }; 1247fb4d8502Sjsg 1248fb4d8502Sjsg 1249fb4d8502Sjsg static ATOM_VOLTAGE_OBJECT_V3 *amdgpu_atombios_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3, 1250fb4d8502Sjsg u8 voltage_type, u8 voltage_mode) 1251fb4d8502Sjsg { 1252fb4d8502Sjsg u32 size = le16_to_cpu(v3->sHeader.usStructureSize); 1253fb4d8502Sjsg u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]); 1254fb4d8502Sjsg u8 *start = (u8 *)v3; 1255fb4d8502Sjsg 1256fb4d8502Sjsg while (offset < size) { 1257fb4d8502Sjsg ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset); 1258fb4d8502Sjsg if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) && 1259fb4d8502Sjsg (vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode)) 1260fb4d8502Sjsg return vo; 1261fb4d8502Sjsg offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize); 1262fb4d8502Sjsg } 1263fb4d8502Sjsg return NULL; 1264fb4d8502Sjsg } 1265fb4d8502Sjsg 1266fb4d8502Sjsg int amdgpu_atombios_get_svi2_info(struct amdgpu_device *adev, 1267fb4d8502Sjsg u8 voltage_type, 1268fb4d8502Sjsg u8 *svd_gpio_id, u8 *svc_gpio_id) 1269fb4d8502Sjsg { 1270fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 1271fb4d8502Sjsg u8 frev, crev; 1272fb4d8502Sjsg u16 data_offset, size; 1273fb4d8502Sjsg union voltage_object_info *voltage_info; 1274fb4d8502Sjsg union voltage_object *voltage_object = NULL; 1275fb4d8502Sjsg 1276fb4d8502Sjsg if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size, 1277fb4d8502Sjsg &frev, &crev, &data_offset)) { 1278fb4d8502Sjsg voltage_info = (union voltage_object_info *) 1279fb4d8502Sjsg (adev->mode_info.atom_context->bios + data_offset); 1280fb4d8502Sjsg 1281fb4d8502Sjsg switch (frev) { 1282fb4d8502Sjsg case 3: 1283fb4d8502Sjsg switch (crev) { 1284fb4d8502Sjsg case 1: 1285fb4d8502Sjsg voltage_object = (union voltage_object *) 1286fb4d8502Sjsg amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3, 1287fb4d8502Sjsg voltage_type, 1288fb4d8502Sjsg VOLTAGE_OBJ_SVID2); 1289fb4d8502Sjsg if (voltage_object) { 1290fb4d8502Sjsg *svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId; 1291fb4d8502Sjsg *svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId; 1292fb4d8502Sjsg } else { 1293fb4d8502Sjsg return -EINVAL; 1294fb4d8502Sjsg } 1295fb4d8502Sjsg break; 1296fb4d8502Sjsg default: 1297fb4d8502Sjsg DRM_ERROR("unknown voltage object table\n"); 1298fb4d8502Sjsg return -EINVAL; 1299fb4d8502Sjsg } 1300fb4d8502Sjsg break; 1301fb4d8502Sjsg default: 1302fb4d8502Sjsg DRM_ERROR("unknown voltage object table\n"); 1303fb4d8502Sjsg return -EINVAL; 1304fb4d8502Sjsg } 1305fb4d8502Sjsg 1306fb4d8502Sjsg } 1307fb4d8502Sjsg return 0; 1308fb4d8502Sjsg } 1309fb4d8502Sjsg 1310fb4d8502Sjsg bool 1311fb4d8502Sjsg amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev, 1312fb4d8502Sjsg u8 voltage_type, u8 voltage_mode) 1313fb4d8502Sjsg { 1314fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 1315fb4d8502Sjsg u8 frev, crev; 1316fb4d8502Sjsg u16 data_offset, size; 1317fb4d8502Sjsg union voltage_object_info *voltage_info; 1318fb4d8502Sjsg 1319fb4d8502Sjsg if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size, 1320fb4d8502Sjsg &frev, &crev, &data_offset)) { 1321fb4d8502Sjsg voltage_info = (union voltage_object_info *) 1322fb4d8502Sjsg (adev->mode_info.atom_context->bios + data_offset); 1323fb4d8502Sjsg 1324fb4d8502Sjsg switch (frev) { 1325fb4d8502Sjsg case 3: 1326fb4d8502Sjsg switch (crev) { 1327fb4d8502Sjsg case 1: 1328fb4d8502Sjsg if (amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3, 1329fb4d8502Sjsg voltage_type, voltage_mode)) 1330fb4d8502Sjsg return true; 1331fb4d8502Sjsg break; 1332fb4d8502Sjsg default: 1333fb4d8502Sjsg DRM_ERROR("unknown voltage object table\n"); 1334fb4d8502Sjsg return false; 1335fb4d8502Sjsg } 1336fb4d8502Sjsg break; 1337fb4d8502Sjsg default: 1338fb4d8502Sjsg DRM_ERROR("unknown voltage object table\n"); 1339fb4d8502Sjsg return false; 1340fb4d8502Sjsg } 1341fb4d8502Sjsg 1342fb4d8502Sjsg } 1343fb4d8502Sjsg return false; 1344fb4d8502Sjsg } 1345fb4d8502Sjsg 1346fb4d8502Sjsg int amdgpu_atombios_get_voltage_table(struct amdgpu_device *adev, 1347fb4d8502Sjsg u8 voltage_type, u8 voltage_mode, 1348fb4d8502Sjsg struct atom_voltage_table *voltage_table) 1349fb4d8502Sjsg { 1350fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 1351fb4d8502Sjsg u8 frev, crev; 1352fb4d8502Sjsg u16 data_offset, size; 1353fb4d8502Sjsg int i; 1354fb4d8502Sjsg union voltage_object_info *voltage_info; 1355fb4d8502Sjsg union voltage_object *voltage_object = NULL; 1356fb4d8502Sjsg 1357fb4d8502Sjsg if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size, 1358fb4d8502Sjsg &frev, &crev, &data_offset)) { 1359fb4d8502Sjsg voltage_info = (union voltage_object_info *) 1360fb4d8502Sjsg (adev->mode_info.atom_context->bios + data_offset); 1361fb4d8502Sjsg 1362fb4d8502Sjsg switch (frev) { 1363fb4d8502Sjsg case 3: 1364fb4d8502Sjsg switch (crev) { 1365fb4d8502Sjsg case 1: 1366fb4d8502Sjsg voltage_object = (union voltage_object *) 1367fb4d8502Sjsg amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3, 1368fb4d8502Sjsg voltage_type, voltage_mode); 1369fb4d8502Sjsg if (voltage_object) { 1370fb4d8502Sjsg ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio = 1371fb4d8502Sjsg &voltage_object->v3.asGpioVoltageObj; 1372fb4d8502Sjsg VOLTAGE_LUT_ENTRY_V2 *lut; 1373fb4d8502Sjsg if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES) 1374fb4d8502Sjsg return -EINVAL; 1375fb4d8502Sjsg lut = &gpio->asVolGpioLut[0]; 1376fb4d8502Sjsg for (i = 0; i < gpio->ucGpioEntryNum; i++) { 1377fb4d8502Sjsg voltage_table->entries[i].value = 1378fb4d8502Sjsg le16_to_cpu(lut->usVoltageValue); 1379fb4d8502Sjsg voltage_table->entries[i].smio_low = 1380fb4d8502Sjsg le32_to_cpu(lut->ulVoltageId); 1381fb4d8502Sjsg lut = (VOLTAGE_LUT_ENTRY_V2 *) 1382fb4d8502Sjsg ((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY_V2)); 1383fb4d8502Sjsg } 1384fb4d8502Sjsg voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal); 1385fb4d8502Sjsg voltage_table->count = gpio->ucGpioEntryNum; 1386fb4d8502Sjsg voltage_table->phase_delay = gpio->ucPhaseDelay; 1387fb4d8502Sjsg return 0; 1388fb4d8502Sjsg } 1389fb4d8502Sjsg break; 1390fb4d8502Sjsg default: 1391fb4d8502Sjsg DRM_ERROR("unknown voltage object table\n"); 1392fb4d8502Sjsg return -EINVAL; 1393fb4d8502Sjsg } 1394fb4d8502Sjsg break; 1395fb4d8502Sjsg default: 1396fb4d8502Sjsg DRM_ERROR("unknown voltage object table\n"); 1397fb4d8502Sjsg return -EINVAL; 1398fb4d8502Sjsg } 1399fb4d8502Sjsg } 1400fb4d8502Sjsg return -EINVAL; 1401fb4d8502Sjsg } 1402fb4d8502Sjsg 1403fb4d8502Sjsg union vram_info { 1404fb4d8502Sjsg struct _ATOM_VRAM_INFO_V3 v1_3; 1405fb4d8502Sjsg struct _ATOM_VRAM_INFO_V4 v1_4; 1406fb4d8502Sjsg struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1; 1407fb4d8502Sjsg }; 1408fb4d8502Sjsg 1409fb4d8502Sjsg #define MEM_ID_MASK 0xff000000 1410fb4d8502Sjsg #define MEM_ID_SHIFT 24 1411fb4d8502Sjsg #define CLOCK_RANGE_MASK 0x00ffffff 1412fb4d8502Sjsg #define CLOCK_RANGE_SHIFT 0 1413fb4d8502Sjsg #define LOW_NIBBLE_MASK 0xf 1414fb4d8502Sjsg #define DATA_EQU_PREV 0 1415fb4d8502Sjsg #define DATA_FROM_TABLE 4 1416fb4d8502Sjsg 1417fb4d8502Sjsg int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev, 1418fb4d8502Sjsg u8 module_index, 1419fb4d8502Sjsg struct atom_mc_reg_table *reg_table) 1420fb4d8502Sjsg { 1421fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, VRAM_Info); 1422fb4d8502Sjsg u8 frev, crev, num_entries, t_mem_id, num_ranges = 0; 1423fb4d8502Sjsg u32 i = 0, j; 1424fb4d8502Sjsg u16 data_offset, size; 1425fb4d8502Sjsg union vram_info *vram_info; 1426fb4d8502Sjsg 1427fb4d8502Sjsg memset(reg_table, 0, sizeof(struct atom_mc_reg_table)); 1428fb4d8502Sjsg 1429fb4d8502Sjsg if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size, 1430fb4d8502Sjsg &frev, &crev, &data_offset)) { 1431fb4d8502Sjsg vram_info = (union vram_info *) 1432fb4d8502Sjsg (adev->mode_info.atom_context->bios + data_offset); 1433fb4d8502Sjsg switch (frev) { 1434fb4d8502Sjsg case 1: 1435fb4d8502Sjsg DRM_ERROR("old table version %d, %d\n", frev, crev); 1436fb4d8502Sjsg return -EINVAL; 1437fb4d8502Sjsg case 2: 1438fb4d8502Sjsg switch (crev) { 1439fb4d8502Sjsg case 1: 1440fb4d8502Sjsg if (module_index < vram_info->v2_1.ucNumOfVRAMModule) { 1441fb4d8502Sjsg ATOM_INIT_REG_BLOCK *reg_block = 1442fb4d8502Sjsg (ATOM_INIT_REG_BLOCK *) 1443fb4d8502Sjsg ((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset)); 1444fb4d8502Sjsg ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = 1445fb4d8502Sjsg (ATOM_MEMORY_SETTING_DATA_BLOCK *) 1446fb4d8502Sjsg ((u8 *)reg_block + (2 * sizeof(u16)) + 1447fb4d8502Sjsg le16_to_cpu(reg_block->usRegIndexTblSize)); 1448fb4d8502Sjsg ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0]; 1449fb4d8502Sjsg num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) / 1450fb4d8502Sjsg sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1; 1451fb4d8502Sjsg if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE) 1452fb4d8502Sjsg return -EINVAL; 1453fb4d8502Sjsg while (i < num_entries) { 1454fb4d8502Sjsg if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER) 1455fb4d8502Sjsg break; 1456fb4d8502Sjsg reg_table->mc_reg_address[i].s1 = 1457fb4d8502Sjsg (u16)(le16_to_cpu(format->usRegIndex)); 1458fb4d8502Sjsg reg_table->mc_reg_address[i].pre_reg_data = 1459fb4d8502Sjsg (u8)(format->ucPreRegDataLength); 1460fb4d8502Sjsg i++; 1461fb4d8502Sjsg format = (ATOM_INIT_REG_INDEX_FORMAT *) 1462fb4d8502Sjsg ((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT)); 1463fb4d8502Sjsg } 1464fb4d8502Sjsg reg_table->last = i; 1465fb4d8502Sjsg while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) && 1466fb4d8502Sjsg (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) { 1467fb4d8502Sjsg t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK) 1468fb4d8502Sjsg >> MEM_ID_SHIFT); 1469fb4d8502Sjsg if (module_index == t_mem_id) { 1470fb4d8502Sjsg reg_table->mc_reg_table_entry[num_ranges].mclk_max = 1471fb4d8502Sjsg (u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK) 1472fb4d8502Sjsg >> CLOCK_RANGE_SHIFT); 1473fb4d8502Sjsg for (i = 0, j = 1; i < reg_table->last; i++) { 1474fb4d8502Sjsg if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) { 1475fb4d8502Sjsg reg_table->mc_reg_table_entry[num_ranges].mc_data[i] = 1476fb4d8502Sjsg (u32)le32_to_cpu(*((u32 *)reg_data + j)); 1477fb4d8502Sjsg j++; 1478fb4d8502Sjsg } else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) { 1479*35f8aaf1Sjsg if (i == 0) 1480*35f8aaf1Sjsg continue; 1481fb4d8502Sjsg reg_table->mc_reg_table_entry[num_ranges].mc_data[i] = 1482fb4d8502Sjsg reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1]; 1483fb4d8502Sjsg } 1484fb4d8502Sjsg } 1485fb4d8502Sjsg num_ranges++; 1486fb4d8502Sjsg } 1487fb4d8502Sjsg reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *) 1488fb4d8502Sjsg ((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)); 1489fb4d8502Sjsg } 1490fb4d8502Sjsg if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) 1491fb4d8502Sjsg return -EINVAL; 1492fb4d8502Sjsg reg_table->num_entries = num_ranges; 1493fb4d8502Sjsg } else 1494fb4d8502Sjsg return -EINVAL; 1495fb4d8502Sjsg break; 1496fb4d8502Sjsg default: 1497fb4d8502Sjsg DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 1498fb4d8502Sjsg return -EINVAL; 1499fb4d8502Sjsg } 1500fb4d8502Sjsg break; 1501fb4d8502Sjsg default: 1502fb4d8502Sjsg DRM_ERROR("Unknown table version %d, %d\n", frev, crev); 1503fb4d8502Sjsg return -EINVAL; 1504fb4d8502Sjsg } 1505fb4d8502Sjsg return 0; 1506fb4d8502Sjsg } 1507fb4d8502Sjsg return -EINVAL; 1508fb4d8502Sjsg } 15091bb76ff1Sjsg #endif 1510fb4d8502Sjsg 1511fb4d8502Sjsg bool amdgpu_atombios_has_gpu_virtualization_table(struct amdgpu_device *adev) 1512fb4d8502Sjsg { 1513fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, GPUVirtualizationInfo); 1514fb4d8502Sjsg u8 frev, crev; 1515fb4d8502Sjsg u16 data_offset, size; 1516fb4d8502Sjsg 1517fb4d8502Sjsg if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size, 1518fb4d8502Sjsg &frev, &crev, &data_offset)) 1519fb4d8502Sjsg return true; 1520fb4d8502Sjsg 1521fb4d8502Sjsg return false; 1522fb4d8502Sjsg } 1523fb4d8502Sjsg 1524fb4d8502Sjsg void amdgpu_atombios_scratch_regs_lock(struct amdgpu_device *adev, bool lock) 1525fb4d8502Sjsg { 1526fb4d8502Sjsg uint32_t bios_6_scratch; 1527fb4d8502Sjsg 1528fb4d8502Sjsg bios_6_scratch = RREG32(adev->bios_scratch_reg_offset + 6); 1529fb4d8502Sjsg 1530fb4d8502Sjsg if (lock) { 1531fb4d8502Sjsg bios_6_scratch |= ATOM_S6_CRITICAL_STATE; 1532fb4d8502Sjsg bios_6_scratch &= ~ATOM_S6_ACC_MODE; 1533fb4d8502Sjsg } else { 1534fb4d8502Sjsg bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE; 1535fb4d8502Sjsg bios_6_scratch |= ATOM_S6_ACC_MODE; 1536fb4d8502Sjsg } 1537fb4d8502Sjsg 1538fb4d8502Sjsg WREG32(adev->bios_scratch_reg_offset + 6, bios_6_scratch); 1539fb4d8502Sjsg } 1540fb4d8502Sjsg 1541fb4d8502Sjsg static void amdgpu_atombios_scratch_regs_init(struct amdgpu_device *adev) 1542fb4d8502Sjsg { 1543fb4d8502Sjsg uint32_t bios_2_scratch, bios_6_scratch; 1544fb4d8502Sjsg 1545fb4d8502Sjsg adev->bios_scratch_reg_offset = mmBIOS_SCRATCH_0; 1546fb4d8502Sjsg 1547fb4d8502Sjsg bios_2_scratch = RREG32(adev->bios_scratch_reg_offset + 2); 1548fb4d8502Sjsg bios_6_scratch = RREG32(adev->bios_scratch_reg_offset + 6); 1549fb4d8502Sjsg 1550fb4d8502Sjsg /* let the bios control the backlight */ 1551fb4d8502Sjsg bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE; 1552fb4d8502Sjsg 1553fb4d8502Sjsg /* tell the bios not to handle mode switching */ 1554fb4d8502Sjsg bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH; 1555fb4d8502Sjsg 1556fb4d8502Sjsg /* clear the vbios dpms state */ 1557fb4d8502Sjsg bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE; 1558fb4d8502Sjsg 1559fb4d8502Sjsg WREG32(adev->bios_scratch_reg_offset + 2, bios_2_scratch); 1560fb4d8502Sjsg WREG32(adev->bios_scratch_reg_offset + 6, bios_6_scratch); 1561fb4d8502Sjsg } 1562fb4d8502Sjsg 1563fb4d8502Sjsg void amdgpu_atombios_scratch_regs_engine_hung(struct amdgpu_device *adev, 1564fb4d8502Sjsg bool hung) 1565fb4d8502Sjsg { 1566fb4d8502Sjsg u32 tmp = RREG32(adev->bios_scratch_reg_offset + 3); 1567fb4d8502Sjsg 1568fb4d8502Sjsg if (hung) 1569fb4d8502Sjsg tmp |= ATOM_S3_ASIC_GUI_ENGINE_HUNG; 1570fb4d8502Sjsg else 1571fb4d8502Sjsg tmp &= ~ATOM_S3_ASIC_GUI_ENGINE_HUNG; 1572fb4d8502Sjsg 1573fb4d8502Sjsg WREG32(adev->bios_scratch_reg_offset + 3, tmp); 1574fb4d8502Sjsg } 1575fb4d8502Sjsg 15761bb76ff1Sjsg void amdgpu_atombios_scratch_regs_set_backlight_level(struct amdgpu_device *adev, 15771bb76ff1Sjsg u32 backlight_level) 15781bb76ff1Sjsg { 15791bb76ff1Sjsg u32 tmp = RREG32(adev->bios_scratch_reg_offset + 2); 15801bb76ff1Sjsg 15811bb76ff1Sjsg tmp &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK; 15821bb76ff1Sjsg tmp |= (backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) & 15831bb76ff1Sjsg ATOM_S2_CURRENT_BL_LEVEL_MASK; 15841bb76ff1Sjsg 15851bb76ff1Sjsg WREG32(adev->bios_scratch_reg_offset + 2, tmp); 15861bb76ff1Sjsg } 15871bb76ff1Sjsg 1588fb4d8502Sjsg bool amdgpu_atombios_scratch_need_asic_init(struct amdgpu_device *adev) 1589fb4d8502Sjsg { 1590fb4d8502Sjsg u32 tmp = RREG32(adev->bios_scratch_reg_offset + 7); 1591fb4d8502Sjsg 1592fb4d8502Sjsg if (tmp & ATOM_S7_ASIC_INIT_COMPLETE_MASK) 1593fb4d8502Sjsg return false; 1594fb4d8502Sjsg else 1595fb4d8502Sjsg return true; 1596fb4d8502Sjsg } 1597fb4d8502Sjsg 1598fb4d8502Sjsg /* Atom needs data in little endian format so swap as appropriate when copying 1599fb4d8502Sjsg * data to or from atom. Note that atom operates on dw units. 1600fb4d8502Sjsg * 1601fb4d8502Sjsg * Use to_le=true when sending data to atom and provide at least 1602f005ef32Sjsg * ALIGN(num_bytes,4) bytes in the dst buffer. 1603fb4d8502Sjsg * 1604f005ef32Sjsg * Use to_le=false when receiving data from atom and provide ALIGN(num_bytes,4) 1605fb4d8502Sjsg * byes in the src buffer. 1606fb4d8502Sjsg */ 1607fb4d8502Sjsg void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le) 1608fb4d8502Sjsg { 1609fb4d8502Sjsg #ifdef __BIG_ENDIAN 1610fb4d8502Sjsg u32 src_tmp[5], dst_tmp[5]; 1611fb4d8502Sjsg int i; 1612f005ef32Sjsg u8 align_num_bytes = ALIGN(num_bytes, 4); 1613fb4d8502Sjsg 1614fb4d8502Sjsg if (to_le) { 1615fb4d8502Sjsg memcpy(src_tmp, src, num_bytes); 1616fb4d8502Sjsg for (i = 0; i < align_num_bytes / 4; i++) 1617fb4d8502Sjsg dst_tmp[i] = cpu_to_le32(src_tmp[i]); 1618fb4d8502Sjsg memcpy(dst, dst_tmp, align_num_bytes); 1619fb4d8502Sjsg } else { 1620fb4d8502Sjsg memcpy(src_tmp, src, align_num_bytes); 1621fb4d8502Sjsg for (i = 0; i < align_num_bytes / 4; i++) 1622fb4d8502Sjsg dst_tmp[i] = le32_to_cpu(src_tmp[i]); 1623fb4d8502Sjsg memcpy(dst, dst_tmp, num_bytes); 1624fb4d8502Sjsg } 1625fb4d8502Sjsg #else 1626fb4d8502Sjsg memcpy(dst, src, num_bytes); 1627fb4d8502Sjsg #endif 1628fb4d8502Sjsg } 1629fb4d8502Sjsg 1630fb4d8502Sjsg static int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev) 1631fb4d8502Sjsg { 1632fb4d8502Sjsg struct atom_context *ctx = adev->mode_info.atom_context; 1633fb4d8502Sjsg int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware); 1634fb4d8502Sjsg uint16_t data_offset; 1635fb4d8502Sjsg int usage_bytes = 0; 1636fb4d8502Sjsg struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage; 1637fb4d8502Sjsg u64 start_addr; 1638fb4d8502Sjsg u64 size; 1639fb4d8502Sjsg 1640fb4d8502Sjsg if (amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) { 1641fb4d8502Sjsg firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset); 1642fb4d8502Sjsg 1643fb4d8502Sjsg DRM_DEBUG("atom firmware requested %08x %dkb\n", 1644fb4d8502Sjsg le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware), 1645fb4d8502Sjsg le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb)); 1646fb4d8502Sjsg 1647fb4d8502Sjsg start_addr = firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware; 1648fb4d8502Sjsg size = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb; 1649fb4d8502Sjsg 1650fb4d8502Sjsg if ((uint32_t)(start_addr & ATOM_VRAM_OPERATION_FLAGS_MASK) == 1651fb4d8502Sjsg (uint32_t)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION << 1652fb4d8502Sjsg ATOM_VRAM_OPERATION_FLAGS_SHIFT)) { 1653fb4d8502Sjsg /* Firmware request VRAM reservation for SR-IOV */ 1654ad8b1aafSjsg adev->mman.fw_vram_usage_start_offset = (start_addr & 1655fb4d8502Sjsg (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10; 1656ad8b1aafSjsg adev->mman.fw_vram_usage_size = size << 10; 1657fb4d8502Sjsg /* Use the default scratch size */ 1658fb4d8502Sjsg usage_bytes = 0; 1659fb4d8502Sjsg } else { 1660fb4d8502Sjsg usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024; 1661fb4d8502Sjsg } 1662fb4d8502Sjsg } 1663fb4d8502Sjsg ctx->scratch_size_bytes = 0; 1664fb4d8502Sjsg if (usage_bytes == 0) 1665fb4d8502Sjsg usage_bytes = 20 * 1024; 1666fb4d8502Sjsg /* allocate some scratch memory */ 1667fb4d8502Sjsg ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL); 1668fb4d8502Sjsg if (!ctx->scratch) 1669fb4d8502Sjsg return -ENOMEM; 1670fb4d8502Sjsg ctx->scratch_size_bytes = usage_bytes; 1671fb4d8502Sjsg return 0; 1672fb4d8502Sjsg } 1673fb4d8502Sjsg 1674fb4d8502Sjsg /* ATOM accessor methods */ 1675fb4d8502Sjsg /* 1676fb4d8502Sjsg * ATOM is an interpreted byte code stored in tables in the vbios. The 1677fb4d8502Sjsg * driver registers callbacks to access registers and the interpreter 1678fb4d8502Sjsg * in the driver parses the tables and executes then to program specific 1679fb4d8502Sjsg * actions (set display modes, asic init, etc.). See amdgpu_atombios.c, 1680fb4d8502Sjsg * atombios.h, and atom.c 1681fb4d8502Sjsg */ 1682fb4d8502Sjsg 1683fb4d8502Sjsg /** 1684fb4d8502Sjsg * cail_pll_read - read PLL register 1685fb4d8502Sjsg * 1686fb4d8502Sjsg * @info: atom card_info pointer 1687fb4d8502Sjsg * @reg: PLL register offset 1688fb4d8502Sjsg * 1689fb4d8502Sjsg * Provides a PLL register accessor for the atom interpreter (r4xx+). 1690fb4d8502Sjsg * Returns the value of the PLL register. 1691fb4d8502Sjsg */ 1692fb4d8502Sjsg static uint32_t cail_pll_read(struct card_info *info, uint32_t reg) 1693fb4d8502Sjsg { 1694fb4d8502Sjsg return 0; 1695fb4d8502Sjsg } 1696fb4d8502Sjsg 1697fb4d8502Sjsg /** 1698fb4d8502Sjsg * cail_pll_write - write PLL register 1699fb4d8502Sjsg * 1700fb4d8502Sjsg * @info: atom card_info pointer 1701fb4d8502Sjsg * @reg: PLL register offset 1702fb4d8502Sjsg * @val: value to write to the pll register 1703fb4d8502Sjsg * 1704fb4d8502Sjsg * Provides a PLL register accessor for the atom interpreter (r4xx+). 1705fb4d8502Sjsg */ 1706fb4d8502Sjsg static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val) 1707fb4d8502Sjsg { 1708fb4d8502Sjsg 1709fb4d8502Sjsg } 1710fb4d8502Sjsg 1711fb4d8502Sjsg /** 1712fb4d8502Sjsg * cail_mc_read - read MC (Memory Controller) register 1713fb4d8502Sjsg * 1714fb4d8502Sjsg * @info: atom card_info pointer 1715fb4d8502Sjsg * @reg: MC register offset 1716fb4d8502Sjsg * 1717fb4d8502Sjsg * Provides an MC register accessor for the atom interpreter (r4xx+). 1718fb4d8502Sjsg * Returns the value of the MC register. 1719fb4d8502Sjsg */ 1720fb4d8502Sjsg static uint32_t cail_mc_read(struct card_info *info, uint32_t reg) 1721fb4d8502Sjsg { 1722fb4d8502Sjsg return 0; 1723fb4d8502Sjsg } 1724fb4d8502Sjsg 1725fb4d8502Sjsg /** 1726fb4d8502Sjsg * cail_mc_write - write MC (Memory Controller) register 1727fb4d8502Sjsg * 1728fb4d8502Sjsg * @info: atom card_info pointer 1729fb4d8502Sjsg * @reg: MC register offset 1730fb4d8502Sjsg * @val: value to write to the pll register 1731fb4d8502Sjsg * 1732fb4d8502Sjsg * Provides a MC register accessor for the atom interpreter (r4xx+). 1733fb4d8502Sjsg */ 1734fb4d8502Sjsg static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val) 1735fb4d8502Sjsg { 1736fb4d8502Sjsg 1737fb4d8502Sjsg } 1738fb4d8502Sjsg 1739fb4d8502Sjsg /** 1740fb4d8502Sjsg * cail_reg_write - write MMIO register 1741fb4d8502Sjsg * 1742fb4d8502Sjsg * @info: atom card_info pointer 1743fb4d8502Sjsg * @reg: MMIO register offset 1744fb4d8502Sjsg * @val: value to write to the pll register 1745fb4d8502Sjsg * 1746fb4d8502Sjsg * Provides a MMIO register accessor for the atom interpreter (r4xx+). 1747fb4d8502Sjsg */ 1748fb4d8502Sjsg static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val) 1749fb4d8502Sjsg { 1750ad8b1aafSjsg struct amdgpu_device *adev = drm_to_adev(info->dev); 1751fb4d8502Sjsg 1752fb4d8502Sjsg WREG32(reg, val); 1753fb4d8502Sjsg } 1754fb4d8502Sjsg 1755fb4d8502Sjsg /** 1756fb4d8502Sjsg * cail_reg_read - read MMIO register 1757fb4d8502Sjsg * 1758fb4d8502Sjsg * @info: atom card_info pointer 1759fb4d8502Sjsg * @reg: MMIO register offset 1760fb4d8502Sjsg * 1761fb4d8502Sjsg * Provides an MMIO register accessor for the atom interpreter (r4xx+). 1762fb4d8502Sjsg * Returns the value of the MMIO register. 1763fb4d8502Sjsg */ 1764fb4d8502Sjsg static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) 1765fb4d8502Sjsg { 1766ad8b1aafSjsg struct amdgpu_device *adev = drm_to_adev(info->dev); 1767fb4d8502Sjsg uint32_t r; 1768fb4d8502Sjsg 1769fb4d8502Sjsg r = RREG32(reg); 1770fb4d8502Sjsg return r; 1771fb4d8502Sjsg } 1772fb4d8502Sjsg 1773fb4d8502Sjsg static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev, 1774fb4d8502Sjsg struct device_attribute *attr, 1775fb4d8502Sjsg char *buf) 1776fb4d8502Sjsg { 1777fb4d8502Sjsg struct drm_device *ddev = dev_get_drvdata(dev); 1778ad8b1aafSjsg struct amdgpu_device *adev = drm_to_adev(ddev); 1779fb4d8502Sjsg struct atom_context *ctx = adev->mode_info.atom_context; 1780fb4d8502Sjsg 1781f005ef32Sjsg return sysfs_emit(buf, "%s\n", ctx->vbios_pn); 1782fb4d8502Sjsg } 1783fb4d8502Sjsg 1784fb4d8502Sjsg static DEVICE_ATTR(vbios_version, 0444, amdgpu_atombios_get_vbios_version, 1785fb4d8502Sjsg NULL); 1786fb4d8502Sjsg 17875ca02815Sjsg static struct attribute *amdgpu_vbios_version_attrs[] = { 17885ca02815Sjsg &dev_attr_vbios_version.attr, 17895ca02815Sjsg NULL 17905ca02815Sjsg }; 17915ca02815Sjsg 17925ca02815Sjsg const struct attribute_group amdgpu_vbios_version_attr_group = { 17935ca02815Sjsg .attrs = amdgpu_vbios_version_attrs 17945ca02815Sjsg }; 17955ca02815Sjsg 1796f005ef32Sjsg int amdgpu_atombios_sysfs_init(struct amdgpu_device *adev) 1797f005ef32Sjsg { 1798f005ef32Sjsg if (adev->mode_info.atom_context) 1799f005ef32Sjsg return devm_device_add_group(adev->dev, 1800f005ef32Sjsg &amdgpu_vbios_version_attr_group); 1801f005ef32Sjsg 1802f005ef32Sjsg return 0; 1803f005ef32Sjsg } 1804f005ef32Sjsg 1805fb4d8502Sjsg /** 1806fb4d8502Sjsg * amdgpu_atombios_fini - free the driver info and callbacks for atombios 1807fb4d8502Sjsg * 1808fb4d8502Sjsg * @adev: amdgpu_device pointer 1809fb4d8502Sjsg * 1810fb4d8502Sjsg * Frees the driver info and register access callbacks for the ATOM 1811fb4d8502Sjsg * interpreter (r4xx+). 1812fb4d8502Sjsg * Called at driver shutdown. 1813fb4d8502Sjsg */ 1814fb4d8502Sjsg void amdgpu_atombios_fini(struct amdgpu_device *adev) 1815fb4d8502Sjsg { 1816fb4d8502Sjsg if (adev->mode_info.atom_context) { 1817fb4d8502Sjsg kfree(adev->mode_info.atom_context->scratch); 1818fb4d8502Sjsg kfree(adev->mode_info.atom_context->iio); 1819fb4d8502Sjsg } 1820fb4d8502Sjsg kfree(adev->mode_info.atom_context); 1821fb4d8502Sjsg adev->mode_info.atom_context = NULL; 1822fb4d8502Sjsg kfree(adev->mode_info.atom_card_info); 1823fb4d8502Sjsg adev->mode_info.atom_card_info = NULL; 1824fb4d8502Sjsg } 1825fb4d8502Sjsg 1826fb4d8502Sjsg /** 1827fb4d8502Sjsg * amdgpu_atombios_init - init the driver info and callbacks for atombios 1828fb4d8502Sjsg * 1829fb4d8502Sjsg * @adev: amdgpu_device pointer 1830fb4d8502Sjsg * 1831fb4d8502Sjsg * Initializes the driver info and register access callbacks for the 1832fb4d8502Sjsg * ATOM interpreter (r4xx+). 1833fb4d8502Sjsg * Returns 0 on sucess, -ENOMEM on failure. 1834fb4d8502Sjsg * Called at driver startup. 1835fb4d8502Sjsg */ 1836fb4d8502Sjsg int amdgpu_atombios_init(struct amdgpu_device *adev) 1837fb4d8502Sjsg { 1838fb4d8502Sjsg struct card_info *atom_card_info = 1839fb4d8502Sjsg kzalloc(sizeof(struct card_info), GFP_KERNEL); 1840fb4d8502Sjsg 1841fb4d8502Sjsg if (!atom_card_info) 1842fb4d8502Sjsg return -ENOMEM; 1843fb4d8502Sjsg 1844fb4d8502Sjsg adev->mode_info.atom_card_info = atom_card_info; 1845ad8b1aafSjsg atom_card_info->dev = adev_to_drm(adev); 1846fb4d8502Sjsg atom_card_info->reg_read = cail_reg_read; 1847fb4d8502Sjsg atom_card_info->reg_write = cail_reg_write; 1848fb4d8502Sjsg atom_card_info->mc_read = cail_mc_read; 1849fb4d8502Sjsg atom_card_info->mc_write = cail_mc_write; 1850fb4d8502Sjsg atom_card_info->pll_read = cail_pll_read; 1851fb4d8502Sjsg atom_card_info->pll_write = cail_pll_write; 1852fb4d8502Sjsg 1853fb4d8502Sjsg adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios); 1854fb4d8502Sjsg if (!adev->mode_info.atom_context) { 1855fb4d8502Sjsg amdgpu_atombios_fini(adev); 1856fb4d8502Sjsg return -ENOMEM; 1857fb4d8502Sjsg } 1858fb4d8502Sjsg 1859fb4d8502Sjsg rw_init(&adev->mode_info.atom_context->mutex, "atomcm"); 1860fb4d8502Sjsg if (adev->is_atom_fw) { 1861fb4d8502Sjsg amdgpu_atomfirmware_scratch_regs_init(adev); 1862fb4d8502Sjsg amdgpu_atomfirmware_allocate_fb_scratch(adev); 18635ca02815Sjsg /* cached firmware_flags for further usage */ 18645ca02815Sjsg adev->mode_info.firmware_flags = 18655ca02815Sjsg amdgpu_atomfirmware_query_firmware_capability(adev); 1866fb4d8502Sjsg } else { 1867fb4d8502Sjsg amdgpu_atombios_scratch_regs_init(adev); 1868fb4d8502Sjsg amdgpu_atombios_allocate_fb_scratch(adev); 1869fb4d8502Sjsg } 1870fb4d8502Sjsg 1871fb4d8502Sjsg return 0; 1872fb4d8502Sjsg } 1873fb4d8502Sjsg 1874ad8b1aafSjsg int amdgpu_atombios_get_data_table(struct amdgpu_device *adev, 1875ad8b1aafSjsg uint32_t table, 1876ad8b1aafSjsg uint16_t *size, 1877ad8b1aafSjsg uint8_t *frev, 1878ad8b1aafSjsg uint8_t *crev, 1879ad8b1aafSjsg uint8_t **addr) 1880ad8b1aafSjsg { 1881ad8b1aafSjsg uint16_t data_start; 1882ad8b1aafSjsg 1883ad8b1aafSjsg if (!amdgpu_atom_parse_data_header(adev->mode_info.atom_context, table, 1884ad8b1aafSjsg size, frev, crev, &data_start)) 1885ad8b1aafSjsg return -EINVAL; 1886ad8b1aafSjsg 1887ad8b1aafSjsg *addr = (uint8_t *)adev->mode_info.atom_context->bios + data_start; 1888ad8b1aafSjsg 1889ad8b1aafSjsg return 0; 1890ad8b1aafSjsg } 1891