Path: blob/master/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
29285 views
/*1* Copyright 2007-8 Advanced Micro Devices, Inc.2* Copyright 2008 Red Hat Inc.3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice shall be included in12* all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20* OTHER DEALINGS IN THE SOFTWARE.21*22* Authors: Dave Airlie23* Alex Deucher24*/2526#include <drm/amdgpu_drm.h>27#include "amdgpu.h"28#include "amdgpu_atombios.h"29#include "amdgpu_atomfirmware.h"30#include "amdgpu_i2c.h"31#include "amdgpu_display.h"3233#include "atom.h"34#include "atom-bits.h"35#include "atombios_encoders.h"36#include "bif/bif_4_1_d.h"3738static struct amdgpu_i2c_bus_rec amdgpu_atombios_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio)39{40struct amdgpu_i2c_bus_rec i2c;4142memset(&i2c, 0, sizeof(struct amdgpu_i2c_bus_rec));4344i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex);45i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex);46i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex);47i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex);48i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex);49i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex);50i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex);51i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex);52i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);53i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);54i2c.en_clk_mask = (1 << gpio->ucClkEnShift);55i2c.en_data_mask = (1 << gpio->ucDataEnShift);56i2c.y_clk_mask = (1 << gpio->ucClkY_Shift);57i2c.y_data_mask = (1 << gpio->ucDataY_Shift);58i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);59i2c.a_data_mask = (1 << gpio->ucDataA_Shift);6061if (gpio->sucI2cId.sbfAccess.bfHW_Capable)62i2c.hw_capable = true;63else64i2c.hw_capable = false;6566if (gpio->sucI2cId.ucAccess == 0xa0)67i2c.mm_i2c = true;68else69i2c.mm_i2c = false;7071i2c.i2c_id = gpio->sucI2cId.ucAccess;7273if (i2c.mask_clk_reg)74i2c.valid = true;75else76i2c.valid = false;7778return i2c;79}8081struct amdgpu_i2c_bus_rec amdgpu_atombios_lookup_i2c_gpio(struct amdgpu_device *adev,82uint8_t id)83{84struct atom_context *ctx = adev->mode_info.atom_context;85ATOM_GPIO_I2C_ASSIGMENT *gpio;86struct amdgpu_i2c_bus_rec i2c;87int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);88struct _ATOM_GPIO_I2C_INFO *i2c_info;89uint16_t data_offset, size;90int i, num_indices;9192memset(&i2c, 0, sizeof(struct amdgpu_i2c_bus_rec));93i2c.valid = false;9495if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {96i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);9798num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /99sizeof(ATOM_GPIO_I2C_ASSIGMENT);100101gpio = &i2c_info->asGPIO_Info[0];102for (i = 0; i < num_indices; i++) {103if (gpio->sucI2cId.ucAccess == id) {104i2c = amdgpu_atombios_get_bus_rec_for_i2c_gpio(gpio);105break;106}107gpio = (ATOM_GPIO_I2C_ASSIGMENT *)108((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT));109}110}111112return i2c;113}114115void amdgpu_atombios_i2c_init(struct amdgpu_device *adev)116{117struct atom_context *ctx = adev->mode_info.atom_context;118ATOM_GPIO_I2C_ASSIGMENT *gpio;119struct amdgpu_i2c_bus_rec i2c;120int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);121struct _ATOM_GPIO_I2C_INFO *i2c_info;122uint16_t data_offset, size;123int i, num_indices;124char stmp[32];125126if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {127i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);128129num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /130sizeof(ATOM_GPIO_I2C_ASSIGMENT);131132gpio = &i2c_info->asGPIO_Info[0];133for (i = 0; i < num_indices; i++) {134i2c = amdgpu_atombios_get_bus_rec_for_i2c_gpio(gpio);135136if (i2c.valid) {137sprintf(stmp, "0x%x", i2c.i2c_id);138adev->i2c_bus[i] = amdgpu_i2c_create(adev_to_drm(adev), &i2c, stmp);139}140gpio = (ATOM_GPIO_I2C_ASSIGMENT *)141((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT));142}143}144}145146void amdgpu_atombios_oem_i2c_init(struct amdgpu_device *adev, u8 i2c_id)147{148struct atom_context *ctx = adev->mode_info.atom_context;149ATOM_GPIO_I2C_ASSIGMENT *gpio;150struct amdgpu_i2c_bus_rec i2c;151int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);152struct _ATOM_GPIO_I2C_INFO *i2c_info;153uint16_t data_offset, size;154int i, num_indices;155char stmp[32];156157if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {158i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);159160num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /161sizeof(ATOM_GPIO_I2C_ASSIGMENT);162163gpio = &i2c_info->asGPIO_Info[0];164for (i = 0; i < num_indices; i++) {165i2c = amdgpu_atombios_get_bus_rec_for_i2c_gpio(gpio);166167if (i2c.valid && i2c.i2c_id == i2c_id) {168sprintf(stmp, "OEM 0x%x", i2c.i2c_id);169adev->i2c_bus[i] = amdgpu_i2c_create(adev_to_drm(adev), &i2c, stmp);170break;171}172gpio = (ATOM_GPIO_I2C_ASSIGMENT *)173((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT));174}175}176}177178struct amdgpu_gpio_rec179amdgpu_atombios_lookup_gpio(struct amdgpu_device *adev,180u8 id)181{182struct atom_context *ctx = adev->mode_info.atom_context;183struct amdgpu_gpio_rec gpio;184int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT);185struct _ATOM_GPIO_PIN_LUT *gpio_info;186ATOM_GPIO_PIN_ASSIGNMENT *pin;187u16 data_offset, size;188int i, num_indices;189190memset(&gpio, 0, sizeof(struct amdgpu_gpio_rec));191gpio.valid = false;192193if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {194gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset);195196num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /197sizeof(ATOM_GPIO_PIN_ASSIGNMENT);198199pin = gpio_info->asGPIO_Pin;200for (i = 0; i < num_indices; i++) {201if (id == pin->ucGPIO_ID) {202gpio.id = pin->ucGPIO_ID;203gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex);204gpio.shift = pin->ucGpioPinBitShift;205gpio.mask = (1 << pin->ucGpioPinBitShift);206gpio.valid = true;207break;208}209pin = (ATOM_GPIO_PIN_ASSIGNMENT *)210((u8 *)pin + sizeof(ATOM_GPIO_PIN_ASSIGNMENT));211}212}213214return gpio;215}216217static struct amdgpu_hpd218amdgpu_atombios_get_hpd_info_from_gpio(struct amdgpu_device *adev,219struct amdgpu_gpio_rec *gpio)220{221struct amdgpu_hpd hpd;222u32 reg;223224memset(&hpd, 0, sizeof(struct amdgpu_hpd));225226reg = amdgpu_display_hpd_get_gpio_reg(adev);227228hpd.gpio = *gpio;229if (gpio->reg == reg) {230switch(gpio->mask) {231case (1 << 0):232hpd.hpd = AMDGPU_HPD_1;233break;234case (1 << 8):235hpd.hpd = AMDGPU_HPD_2;236break;237case (1 << 16):238hpd.hpd = AMDGPU_HPD_3;239break;240case (1 << 24):241hpd.hpd = AMDGPU_HPD_4;242break;243case (1 << 26):244hpd.hpd = AMDGPU_HPD_5;245break;246case (1 << 28):247hpd.hpd = AMDGPU_HPD_6;248break;249default:250hpd.hpd = AMDGPU_HPD_NONE;251break;252}253} else254hpd.hpd = AMDGPU_HPD_NONE;255return hpd;256}257258static const int object_connector_convert[] = {259DRM_MODE_CONNECTOR_Unknown,260DRM_MODE_CONNECTOR_DVII,261DRM_MODE_CONNECTOR_DVII,262DRM_MODE_CONNECTOR_DVID,263DRM_MODE_CONNECTOR_DVID,264DRM_MODE_CONNECTOR_VGA,265DRM_MODE_CONNECTOR_Composite,266DRM_MODE_CONNECTOR_SVIDEO,267DRM_MODE_CONNECTOR_Unknown,268DRM_MODE_CONNECTOR_Unknown,269DRM_MODE_CONNECTOR_9PinDIN,270DRM_MODE_CONNECTOR_Unknown,271DRM_MODE_CONNECTOR_HDMIA,272DRM_MODE_CONNECTOR_HDMIB,273DRM_MODE_CONNECTOR_LVDS,274DRM_MODE_CONNECTOR_9PinDIN,275DRM_MODE_CONNECTOR_Unknown,276DRM_MODE_CONNECTOR_Unknown,277DRM_MODE_CONNECTOR_Unknown,278DRM_MODE_CONNECTOR_DisplayPort,279DRM_MODE_CONNECTOR_eDP,280DRM_MODE_CONNECTOR_Unknown281};282283bool amdgpu_atombios_has_dce_engine_info(struct amdgpu_device *adev)284{285struct amdgpu_mode_info *mode_info = &adev->mode_info;286struct atom_context *ctx = mode_info->atom_context;287int index = GetIndexIntoMasterTable(DATA, Object_Header);288u16 size, data_offset;289u8 frev, crev;290ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;291ATOM_OBJECT_HEADER *obj_header;292293if (!amdgpu_atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))294return false;295296if (crev < 2)297return false;298299obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);300path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)301(ctx->bios + data_offset +302le16_to_cpu(obj_header->usDisplayPathTableOffset));303304if (path_obj->ucNumOfDispPath)305return true;306else307return false;308}309310bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev)311{312struct amdgpu_mode_info *mode_info = &adev->mode_info;313struct atom_context *ctx = mode_info->atom_context;314int index = GetIndexIntoMasterTable(DATA, Object_Header);315u16 size, data_offset;316u8 frev, crev;317ATOM_CONNECTOR_OBJECT_TABLE *con_obj;318ATOM_ENCODER_OBJECT_TABLE *enc_obj;319ATOM_OBJECT_TABLE *router_obj;320ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;321ATOM_OBJECT_HEADER *obj_header;322int i, j, k, path_size, device_support;323int connector_type;324u16 conn_id, connector_object_id;325struct amdgpu_i2c_bus_rec ddc_bus;326struct amdgpu_router router;327struct amdgpu_gpio_rec gpio;328struct amdgpu_hpd hpd;329330if (!amdgpu_atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))331return false;332333if (crev < 2)334return false;335336obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);337path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)338(ctx->bios + data_offset +339le16_to_cpu(obj_header->usDisplayPathTableOffset));340con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)341(ctx->bios + data_offset +342le16_to_cpu(obj_header->usConnectorObjectTableOffset));343enc_obj = (ATOM_ENCODER_OBJECT_TABLE *)344(ctx->bios + data_offset +345le16_to_cpu(obj_header->usEncoderObjectTableOffset));346router_obj = (ATOM_OBJECT_TABLE *)347(ctx->bios + data_offset +348le16_to_cpu(obj_header->usRouterObjectTableOffset));349device_support = le16_to_cpu(obj_header->usDeviceSupport);350351path_size = 0;352for (i = 0; i < path_obj->ucNumOfDispPath; i++) {353uint8_t *addr = (uint8_t *) path_obj->asDispPath;354ATOM_DISPLAY_OBJECT_PATH *path;355addr += path_size;356path = (ATOM_DISPLAY_OBJECT_PATH *) addr;357path_size += le16_to_cpu(path->usSize);358359if (device_support & le16_to_cpu(path->usDeviceTag)) {360uint8_t con_obj_id =361(le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK)362>> OBJECT_ID_SHIFT;363364/* Skip TV/CV support */365if ((le16_to_cpu(path->usDeviceTag) ==366ATOM_DEVICE_TV1_SUPPORT) ||367(le16_to_cpu(path->usDeviceTag) ==368ATOM_DEVICE_CV_SUPPORT))369continue;370371if (con_obj_id >= ARRAY_SIZE(object_connector_convert)) {372DRM_ERROR("invalid con_obj_id %d for device tag 0x%04x\n",373con_obj_id, le16_to_cpu(path->usDeviceTag));374continue;375}376377connector_type =378object_connector_convert[con_obj_id];379connector_object_id = con_obj_id;380381if (connector_type == DRM_MODE_CONNECTOR_Unknown)382continue;383384router.ddc_valid = false;385router.cd_valid = false;386for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {387uint8_t grph_obj_type =388(le16_to_cpu(path->usGraphicObjIds[j]) &389OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;390391if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {392for (k = 0; k < enc_obj->ucNumberOfObjects; k++) {393u16 encoder_obj = le16_to_cpu(enc_obj->asObjects[k].usObjectID);394if (le16_to_cpu(path->usGraphicObjIds[j]) == encoder_obj) {395ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)396(ctx->bios + data_offset +397le16_to_cpu(enc_obj->asObjects[k].usRecordOffset));398ATOM_ENCODER_CAP_RECORD *cap_record;399u16 caps = 0;400401while (record->ucRecordSize > 0 &&402record->ucRecordType > 0 &&403record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {404switch (record->ucRecordType) {405case ATOM_ENCODER_CAP_RECORD_TYPE:406cap_record =(ATOM_ENCODER_CAP_RECORD *)407record;408caps = le16_to_cpu(cap_record->usEncoderCap);409break;410}411record = (ATOM_COMMON_RECORD_HEADER *)412((char *)record + record->ucRecordSize);413}414amdgpu_display_add_encoder(adev, encoder_obj,415le16_to_cpu(path->usDeviceTag),416caps);417}418}419} else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {420for (k = 0; k < router_obj->ucNumberOfObjects; k++) {421u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID);422if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {423ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)424(ctx->bios + data_offset +425le16_to_cpu(router_obj->asObjects[k].usRecordOffset));426ATOM_I2C_RECORD *i2c_record;427ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;428ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;429ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path;430ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =431(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)432(ctx->bios + data_offset +433le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset));434u8 *num_dst_objs = (u8 *)435((u8 *)router_src_dst_table + 1 +436(router_src_dst_table->ucNumberOfSrc * 2));437u16 *dst_objs = (u16 *)(num_dst_objs + 1);438int enum_id;439440router.router_id = router_obj_id;441for (enum_id = 0; enum_id < (*num_dst_objs); enum_id++) {442if (le16_to_cpu(path->usConnObjectId) ==443le16_to_cpu(dst_objs[enum_id]))444break;445}446447while (record->ucRecordSize > 0 &&448record->ucRecordType > 0 &&449record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {450switch (record->ucRecordType) {451case ATOM_I2C_RECORD_TYPE:452i2c_record =453(ATOM_I2C_RECORD *)454record;455i2c_config =456(ATOM_I2C_ID_CONFIG_ACCESS *)457&i2c_record->sucI2cId;458router.i2c_info =459amdgpu_atombios_lookup_i2c_gpio(adev,460i2c_config->461ucAccess);462router.i2c_addr = i2c_record->ucI2CAddr >> 1;463break;464case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:465ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)466record;467router.ddc_valid = true;468router.ddc_mux_type = ddc_path->ucMuxType;469router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;470router.ddc_mux_state = ddc_path->ucMuxState[enum_id];471break;472case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:473cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)474record;475router.cd_valid = true;476router.cd_mux_type = cd_path->ucMuxType;477router.cd_mux_control_pin = cd_path->ucMuxControlPin;478router.cd_mux_state = cd_path->ucMuxState[enum_id];479break;480}481record = (ATOM_COMMON_RECORD_HEADER *)482((char *)record + record->ucRecordSize);483}484}485}486}487}488489/* look up gpio for ddc, hpd */490ddc_bus.valid = false;491hpd.hpd = AMDGPU_HPD_NONE;492if ((le16_to_cpu(path->usDeviceTag) &493(ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {494for (j = 0; j < con_obj->ucNumberOfObjects; j++) {495if (le16_to_cpu(path->usConnObjectId) ==496le16_to_cpu(con_obj->asObjects[j].497usObjectID)) {498ATOM_COMMON_RECORD_HEADER499*record =500(ATOM_COMMON_RECORD_HEADER501*)502(ctx->bios + data_offset +503le16_to_cpu(con_obj->504asObjects[j].505usRecordOffset));506ATOM_I2C_RECORD *i2c_record;507ATOM_HPD_INT_RECORD *hpd_record;508ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;509510while (record->ucRecordSize > 0 &&511record->ucRecordType > 0 &&512record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {513switch (record->ucRecordType) {514case ATOM_I2C_RECORD_TYPE:515i2c_record =516(ATOM_I2C_RECORD *)517record;518i2c_config =519(ATOM_I2C_ID_CONFIG_ACCESS *)520&i2c_record->sucI2cId;521ddc_bus = amdgpu_atombios_lookup_i2c_gpio(adev,522i2c_config->523ucAccess);524break;525case ATOM_HPD_INT_RECORD_TYPE:526hpd_record =527(ATOM_HPD_INT_RECORD *)528record;529gpio = amdgpu_atombios_lookup_gpio(adev,530hpd_record->ucHPDIntGPIOID);531hpd = amdgpu_atombios_get_hpd_info_from_gpio(adev, &gpio);532hpd.plugged_state = hpd_record->ucPlugged_PinState;533break;534}535record =536(ATOM_COMMON_RECORD_HEADER537*) ((char *)record538+539record->540ucRecordSize);541}542break;543}544}545}546547/* needed for aux chan transactions */548ddc_bus.hpd = hpd.hpd;549550conn_id = le16_to_cpu(path->usConnObjectId);551552amdgpu_display_add_connector(adev,553conn_id,554le16_to_cpu(path->usDeviceTag),555connector_type, &ddc_bus,556connector_object_id,557&hpd,558&router);559560}561}562563amdgpu_link_encoder_connector(adev_to_drm(adev));564565return true;566}567568union firmware_info {569ATOM_FIRMWARE_INFO info;570ATOM_FIRMWARE_INFO_V1_2 info_12;571ATOM_FIRMWARE_INFO_V1_3 info_13;572ATOM_FIRMWARE_INFO_V1_4 info_14;573ATOM_FIRMWARE_INFO_V2_1 info_21;574ATOM_FIRMWARE_INFO_V2_2 info_22;575};576577int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev)578{579struct amdgpu_mode_info *mode_info = &adev->mode_info;580int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);581uint8_t frev, crev;582uint16_t data_offset;583int ret = -EINVAL;584585if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,586&frev, &crev, &data_offset)) {587int i;588struct amdgpu_pll *ppll = &adev->clock.ppll[0];589struct amdgpu_pll *spll = &adev->clock.spll;590struct amdgpu_pll *mpll = &adev->clock.mpll;591union firmware_info *firmware_info =592(union firmware_info *)(mode_info->atom_context->bios +593data_offset);594/* pixel clocks */595ppll->reference_freq =596le16_to_cpu(firmware_info->info.usReferenceClock);597ppll->reference_div = 0;598599ppll->pll_out_min =600le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);601ppll->pll_out_max =602le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);603604ppll->lcd_pll_out_min =605le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;606if (ppll->lcd_pll_out_min == 0)607ppll->lcd_pll_out_min = ppll->pll_out_min;608ppll->lcd_pll_out_max =609le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;610if (ppll->lcd_pll_out_max == 0)611ppll->lcd_pll_out_max = ppll->pll_out_max;612613if (ppll->pll_out_min == 0)614ppll->pll_out_min = 64800;615616ppll->pll_in_min =617le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input);618ppll->pll_in_max =619le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input);620621ppll->min_post_div = 2;622ppll->max_post_div = 0x7f;623ppll->min_frac_feedback_div = 0;624ppll->max_frac_feedback_div = 9;625ppll->min_ref_div = 2;626ppll->max_ref_div = 0x3ff;627ppll->min_feedback_div = 4;628ppll->max_feedback_div = 0xfff;629ppll->best_vco = 0;630631for (i = 1; i < AMDGPU_MAX_PPLL; i++)632adev->clock.ppll[i] = *ppll;633634/* system clock */635spll->reference_freq =636le16_to_cpu(firmware_info->info_21.usCoreReferenceClock);637spll->reference_div = 0;638639spll->pll_out_min =640le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output);641spll->pll_out_max =642le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output);643644/* ??? */645if (spll->pll_out_min == 0)646spll->pll_out_min = 64800;647648spll->pll_in_min =649le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input);650spll->pll_in_max =651le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input);652653spll->min_post_div = 1;654spll->max_post_div = 1;655spll->min_ref_div = 2;656spll->max_ref_div = 0xff;657spll->min_feedback_div = 4;658spll->max_feedback_div = 0xff;659spll->best_vco = 0;660661/* memory clock */662mpll->reference_freq =663le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock);664mpll->reference_div = 0;665666mpll->pll_out_min =667le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output);668mpll->pll_out_max =669le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output);670671/* ??? */672if (mpll->pll_out_min == 0)673mpll->pll_out_min = 64800;674675mpll->pll_in_min =676le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input);677mpll->pll_in_max =678le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input);679680adev->clock.default_sclk =681le32_to_cpu(firmware_info->info.ulDefaultEngineClock);682adev->clock.default_mclk =683le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);684685mpll->min_post_div = 1;686mpll->max_post_div = 1;687mpll->min_ref_div = 2;688mpll->max_ref_div = 0xff;689mpll->min_feedback_div = 4;690mpll->max_feedback_div = 0xff;691mpll->best_vco = 0;692693/* disp clock */694adev->clock.default_dispclk =695le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);696/* set a reasonable default for DP */697if (adev->clock.default_dispclk < 53900) {698DRM_DEBUG("Changing default dispclk from %dMhz to 600Mhz\n",699adev->clock.default_dispclk / 100);700adev->clock.default_dispclk = 60000;701} else if (adev->clock.default_dispclk <= 60000) {702DRM_DEBUG("Changing default dispclk from %dMhz to 625Mhz\n",703adev->clock.default_dispclk / 100);704adev->clock.default_dispclk = 62500;705}706adev->clock.dp_extclk =707le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);708709adev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock);710if (adev->clock.max_pixel_clock == 0)711adev->clock.max_pixel_clock = 40000;712713/* not technically a clock, but... */714adev->mode_info.firmware_flags =715le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);716717ret = 0;718}719720adev->pm.current_sclk = adev->clock.default_sclk;721adev->pm.current_mclk = adev->clock.default_mclk;722723return ret;724}725726union gfx_info {727ATOM_GFX_INFO_V2_1 info;728};729730int amdgpu_atombios_get_gfx_info(struct amdgpu_device *adev)731{732struct amdgpu_mode_info *mode_info = &adev->mode_info;733int index = GetIndexIntoMasterTable(DATA, GFX_Info);734uint8_t frev, crev;735uint16_t data_offset;736int ret = -EINVAL;737738if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,739&frev, &crev, &data_offset)) {740union gfx_info *gfx_info = (union gfx_info *)741(mode_info->atom_context->bios + data_offset);742743adev->gfx.config.max_shader_engines = gfx_info->info.max_shader_engines;744adev->gfx.config.max_tile_pipes = gfx_info->info.max_tile_pipes;745adev->gfx.config.max_cu_per_sh = gfx_info->info.max_cu_per_sh;746adev->gfx.config.max_sh_per_se = gfx_info->info.max_sh_per_se;747adev->gfx.config.max_backends_per_se = gfx_info->info.max_backends_per_se;748adev->gfx.config.max_texture_channel_caches =749gfx_info->info.max_texture_channel_caches;750751ret = 0;752}753return ret;754}755756union igp_info {757struct _ATOM_INTEGRATED_SYSTEM_INFO info;758struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;759struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;760struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;761struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;762struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9 info_9;763};764765/*766* Return vram width from integrated system info table, if available,767* or 0 if not.768*/769int amdgpu_atombios_get_vram_width(struct amdgpu_device *adev)770{771struct amdgpu_mode_info *mode_info = &adev->mode_info;772int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);773u16 data_offset, size;774union igp_info *igp_info;775u8 frev, crev;776777/* get any igp specific overrides */778if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size,779&frev, &crev, &data_offset)) {780igp_info = (union igp_info *)781(mode_info->atom_context->bios + data_offset);782switch (crev) {783case 8:784case 9:785return igp_info->info_8.ucUMAChannelNumber * 64;786default:787return 0;788}789}790791return 0;792}793794static void amdgpu_atombios_get_igp_ss_overrides(struct amdgpu_device *adev,795struct amdgpu_atom_ss *ss,796int id)797{798struct amdgpu_mode_info *mode_info = &adev->mode_info;799int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);800u16 data_offset, size;801union igp_info *igp_info;802u8 frev, crev;803u16 percentage = 0, rate = 0;804805/* get any igp specific overrides */806if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size,807&frev, &crev, &data_offset)) {808igp_info = (union igp_info *)809(mode_info->atom_context->bios + data_offset);810switch (crev) {811case 6:812switch (id) {813case ASIC_INTERNAL_SS_ON_TMDS:814percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage);815rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz);816break;817case ASIC_INTERNAL_SS_ON_HDMI:818percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage);819rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz);820break;821case ASIC_INTERNAL_SS_ON_LVDS:822percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage);823rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz);824break;825}826break;827case 7:828switch (id) {829case ASIC_INTERNAL_SS_ON_TMDS:830percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage);831rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz);832break;833case ASIC_INTERNAL_SS_ON_HDMI:834percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage);835rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz);836break;837case ASIC_INTERNAL_SS_ON_LVDS:838percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage);839rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz);840break;841}842break;843case 8:844switch (id) {845case ASIC_INTERNAL_SS_ON_TMDS:846percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage);847rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz);848break;849case ASIC_INTERNAL_SS_ON_HDMI:850percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage);851rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz);852break;853case ASIC_INTERNAL_SS_ON_LVDS:854percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage);855rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz);856break;857}858break;859case 9:860switch (id) {861case ASIC_INTERNAL_SS_ON_TMDS:862percentage = le16_to_cpu(igp_info->info_9.usDVISSPercentage);863rate = le16_to_cpu(igp_info->info_9.usDVISSpreadRateIn10Hz);864break;865case ASIC_INTERNAL_SS_ON_HDMI:866percentage = le16_to_cpu(igp_info->info_9.usHDMISSPercentage);867rate = le16_to_cpu(igp_info->info_9.usHDMISSpreadRateIn10Hz);868break;869case ASIC_INTERNAL_SS_ON_LVDS:870percentage = le16_to_cpu(igp_info->info_9.usLvdsSSPercentage);871rate = le16_to_cpu(igp_info->info_9.usLvdsSSpreadRateIn10Hz);872break;873}874break;875default:876DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);877break;878}879if (percentage)880ss->percentage = percentage;881if (rate)882ss->rate = rate;883}884}885886union asic_ss_info {887struct _ATOM_ASIC_INTERNAL_SS_INFO info;888struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;889struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;890};891892union asic_ss_assignment {893struct _ATOM_ASIC_SS_ASSIGNMENT v1;894struct _ATOM_ASIC_SS_ASSIGNMENT_V2 v2;895struct _ATOM_ASIC_SS_ASSIGNMENT_V3 v3;896};897898bool amdgpu_atombios_get_asic_ss_info(struct amdgpu_device *adev,899struct amdgpu_atom_ss *ss,900int id, u32 clock)901{902struct amdgpu_mode_info *mode_info = &adev->mode_info;903int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);904uint16_t data_offset, size;905union asic_ss_info *ss_info;906union asic_ss_assignment *ss_assign;907uint8_t frev, crev;908int i, num_indices;909910if (id == ASIC_INTERNAL_MEMORY_SS) {911if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT))912return false;913}914if (id == ASIC_INTERNAL_ENGINE_SS) {915if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT))916return false;917}918919memset(ss, 0, sizeof(struct amdgpu_atom_ss));920if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size,921&frev, &crev, &data_offset)) {922923ss_info =924(union asic_ss_info *)(mode_info->atom_context->bios + data_offset);925926switch (frev) {927case 1:928num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /929sizeof(ATOM_ASIC_SS_ASSIGNMENT);930931ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info.asSpreadSpectrum[0]);932for (i = 0; i < num_indices; i++) {933if ((ss_assign->v1.ucClockIndication == id) &&934(clock <= le32_to_cpu(ss_assign->v1.ulTargetClockRange))) {935ss->percentage =936le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage);937ss->type = ss_assign->v1.ucSpreadSpectrumMode;938ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz);939ss->percentage_divider = 100;940return true;941}942ss_assign = (union asic_ss_assignment *)943((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT));944}945break;946case 2:947num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /948sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);949ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_2.asSpreadSpectrum[0]);950for (i = 0; i < num_indices; i++) {951if ((ss_assign->v2.ucClockIndication == id) &&952(clock <= le32_to_cpu(ss_assign->v2.ulTargetClockRange))) {953ss->percentage =954le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage);955ss->type = ss_assign->v2.ucSpreadSpectrumMode;956ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz);957ss->percentage_divider = 100;958if ((crev == 2) &&959((id == ASIC_INTERNAL_ENGINE_SS) ||960(id == ASIC_INTERNAL_MEMORY_SS)))961ss->rate /= 100;962return true;963}964ss_assign = (union asic_ss_assignment *)965((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2));966}967break;968case 3:969num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /970sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);971ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_3.asSpreadSpectrum[0]);972for (i = 0; i < num_indices; i++) {973if ((ss_assign->v3.ucClockIndication == id) &&974(clock <= le32_to_cpu(ss_assign->v3.ulTargetClockRange))) {975ss->percentage =976le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage);977ss->type = ss_assign->v3.ucSpreadSpectrumMode;978ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz);979if (ss_assign->v3.ucSpreadSpectrumMode &980SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK)981ss->percentage_divider = 1000;982else983ss->percentage_divider = 100;984if ((id == ASIC_INTERNAL_ENGINE_SS) ||985(id == ASIC_INTERNAL_MEMORY_SS))986ss->rate /= 100;987if (adev->flags & AMD_IS_APU)988amdgpu_atombios_get_igp_ss_overrides(adev, ss, id);989return true;990}991ss_assign = (union asic_ss_assignment *)992((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3));993}994break;995default:996DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);997break;998}9991000}1001return false;1002}10031004union get_clock_dividers {1005struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1;1006struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2;1007struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3;1008struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4;1009struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5;1010struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in;1011struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out;1012};10131014int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,1015u8 clock_type,1016u32 clock,1017bool strobe_mode,1018struct atom_clock_dividers *dividers)1019{1020union get_clock_dividers args;1021int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL);1022u8 frev, crev;10231024memset(&args, 0, sizeof(args));1025memset(dividers, 0, sizeof(struct atom_clock_dividers));10261027if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))1028return -EINVAL;10291030switch (crev) {1031case 2:1032case 3:1033case 5:1034/* r6xx, r7xx, evergreen, ni, si.1035* TODO: add support for asic_type <= CHIP_RV770*/1036if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {1037args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);10381039if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1040index, (uint32_t *)&args, sizeof(args)))1041return -EINVAL;10421043dividers->post_div = args.v3.ucPostDiv;1044dividers->enable_post_div = (args.v3.ucCntlFlag &1045ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;1046dividers->enable_dithen = (args.v3.ucCntlFlag &1047ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;1048dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);1049dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);1050dividers->ref_div = args.v3.ucRefDiv;1051dividers->vco_mode = (args.v3.ucCntlFlag &1052ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;1053} else {1054/* for SI we use ComputeMemoryClockParam for memory plls */1055if (adev->asic_type >= CHIP_TAHITI)1056return -EINVAL;1057args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);1058if (strobe_mode)1059args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;10601061if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1062index, (uint32_t *)&args, sizeof(args)))1063return -EINVAL;10641065dividers->post_div = args.v5.ucPostDiv;1066dividers->enable_post_div = (args.v5.ucCntlFlag &1067ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;1068dividers->enable_dithen = (args.v5.ucCntlFlag &1069ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;1070dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv);1071dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac);1072dividers->ref_div = args.v5.ucRefDiv;1073dividers->vco_mode = (args.v5.ucCntlFlag &1074ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;1075}1076break;1077case 4:1078/* fusion */1079args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */10801081if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1082index, (uint32_t *)&args, sizeof(args)))1083return -EINVAL;10841085dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;1086dividers->real_clock = le32_to_cpu(args.v4.ulClock);1087break;1088case 6:1089/* CI */1090/* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */1091args.v6_in.ulClock.ulComputeClockFlag = clock_type;1092args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */10931094if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1095index, (uint32_t *)&args, sizeof(args)))1096return -EINVAL;10971098dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);1099dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);1100dividers->ref_div = args.v6_out.ucPllRefDiv;1101dividers->post_div = args.v6_out.ucPllPostDiv;1102dividers->flags = args.v6_out.ucPllCntlFlag;1103dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock);1104dividers->post_divider = args.v6_out.ulClock.ucPostDiv;1105break;1106default:1107return -EINVAL;1108}1109return 0;1110}11111112#ifdef CONFIG_DRM_AMDGPU_SI1113int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev,1114u32 clock,1115bool strobe_mode,1116struct atom_mpll_param *mpll_param)1117{1118COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 args;1119int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam);1120u8 frev, crev;11211122memset(&args, 0, sizeof(args));1123memset(mpll_param, 0, sizeof(struct atom_mpll_param));11241125if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))1126return -EINVAL;11271128switch (frev) {1129case 2:1130switch (crev) {1131case 1:1132/* SI */1133args.ulClock = cpu_to_le32(clock); /* 10 khz */1134args.ucInputFlag = 0;1135if (strobe_mode)1136args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN;11371138if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1139index, (uint32_t *)&args, sizeof(args)))1140return -EINVAL;11411142mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac);1143mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv);1144mpll_param->post_div = args.ucPostDiv;1145mpll_param->dll_speed = args.ucDllSpeed;1146mpll_param->bwcntl = args.ucBWCntl;1147mpll_param->vco_mode =1148(args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK);1149mpll_param->yclk_sel =1150(args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0;1151mpll_param->qdr =1152(args.ucPllCntlFlag & MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0;1153mpll_param->half_rate =1154(args.ucPllCntlFlag & MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0;1155break;1156default:1157return -EINVAL;1158}1159break;1160default:1161return -EINVAL;1162}1163return 0;1164}11651166int amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev,1167u32 eng_clock, u32 mem_clock)1168{1169SET_ENGINE_CLOCK_PS_ALLOCATION args;1170int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);1171u32 tmp;11721173memset(&args, 0, sizeof(args));11741175tmp = eng_clock & SET_CLOCK_FREQ_MASK;1176tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24);11771178args.ulTargetEngineClock = cpu_to_le32(tmp);1179if (mem_clock)1180args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK);11811182return amdgpu_atom_execute_table(adev->mode_info.atom_context, index,1183(uint32_t *)&args, sizeof(args));1184}11851186void amdgpu_atombios_get_default_voltages(struct amdgpu_device *adev,1187u16 *vddc, u16 *vddci, u16 *mvdd)1188{1189struct amdgpu_mode_info *mode_info = &adev->mode_info;1190int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);1191u8 frev, crev;1192u16 data_offset;1193union firmware_info *firmware_info;11941195*vddc = 0;1196*vddci = 0;1197*mvdd = 0;11981199if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,1200&frev, &crev, &data_offset)) {1201firmware_info =1202(union firmware_info *)(mode_info->atom_context->bios +1203data_offset);1204*vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);1205if ((frev == 2) && (crev >= 2)) {1206*vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);1207*mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage);1208}1209}1210}12111212union set_voltage {1213struct _SET_VOLTAGE_PS_ALLOCATION alloc;1214struct _SET_VOLTAGE_PARAMETERS v1;1215struct _SET_VOLTAGE_PARAMETERS_V2 v2;1216struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;1217};12181219int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type,1220u16 voltage_id, u16 *voltage)1221{1222union set_voltage args;1223int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);1224u8 frev, crev;12251226if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))1227return -EINVAL;12281229switch (crev) {1230case 1:1231return -EINVAL;1232case 2:1233args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;1234args.v2.ucVoltageMode = 0;1235args.v2.usVoltageLevel = 0;12361237if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1238index, (uint32_t *)&args, sizeof(args)))1239return -EINVAL;12401241*voltage = le16_to_cpu(args.v2.usVoltageLevel);1242break;1243case 3:1244args.v3.ucVoltageType = voltage_type;1245args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;1246args.v3.usVoltageLevel = cpu_to_le16(voltage_id);12471248if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1249index, (uint32_t *)&args, sizeof(args)))1250return -EINVAL;12511252*voltage = le16_to_cpu(args.v3.usVoltageLevel);1253break;1254default:1255DRM_ERROR("Unknown table version %d, %d\n", frev, crev);1256return -EINVAL;1257}12581259return 0;1260}12611262int amdgpu_atombios_get_leakage_vddc_based_on_leakage_idx(struct amdgpu_device *adev,1263u16 *voltage,1264u16 leakage_idx)1265{1266return amdgpu_atombios_get_max_vddc(adev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage);1267}12681269union voltage_object_info {1270struct _ATOM_VOLTAGE_OBJECT_INFO v1;1271struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;1272struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;1273};12741275union voltage_object {1276struct _ATOM_VOLTAGE_OBJECT v1;1277struct _ATOM_VOLTAGE_OBJECT_V2 v2;1278union _ATOM_VOLTAGE_OBJECT_V3 v3;1279};128012811282static ATOM_VOLTAGE_OBJECT_V3 *amdgpu_atombios_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3,1283u8 voltage_type, u8 voltage_mode)1284{1285u32 size = le16_to_cpu(v3->sHeader.usStructureSize);1286u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);1287u8 *start = (u8 *)v3;12881289while (offset < size) {1290ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);1291if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) &&1292(vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode))1293return vo;1294offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize);1295}1296return NULL;1297}12981299int amdgpu_atombios_get_svi2_info(struct amdgpu_device *adev,1300u8 voltage_type,1301u8 *svd_gpio_id, u8 *svc_gpio_id)1302{1303int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);1304u8 frev, crev;1305u16 data_offset, size;1306union voltage_object_info *voltage_info;1307union voltage_object *voltage_object = NULL;13081309if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1310&frev, &crev, &data_offset)) {1311voltage_info = (union voltage_object_info *)1312(adev->mode_info.atom_context->bios + data_offset);13131314switch (frev) {1315case 3:1316switch (crev) {1317case 1:1318voltage_object = (union voltage_object *)1319amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,1320voltage_type,1321VOLTAGE_OBJ_SVID2);1322if (voltage_object) {1323*svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId;1324*svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId;1325} else {1326return -EINVAL;1327}1328break;1329default:1330DRM_ERROR("unknown voltage object table\n");1331return -EINVAL;1332}1333break;1334default:1335DRM_ERROR("unknown voltage object table\n");1336return -EINVAL;1337}13381339}1340return 0;1341}13421343bool1344amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev,1345u8 voltage_type, u8 voltage_mode)1346{1347int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);1348u8 frev, crev;1349u16 data_offset, size;1350union voltage_object_info *voltage_info;13511352if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1353&frev, &crev, &data_offset)) {1354voltage_info = (union voltage_object_info *)1355(adev->mode_info.atom_context->bios + data_offset);13561357switch (frev) {1358case 3:1359switch (crev) {1360case 1:1361if (amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,1362voltage_type, voltage_mode))1363return true;1364break;1365default:1366DRM_ERROR("unknown voltage object table\n");1367return false;1368}1369break;1370default:1371DRM_ERROR("unknown voltage object table\n");1372return false;1373}13741375}1376return false;1377}13781379int amdgpu_atombios_get_voltage_table(struct amdgpu_device *adev,1380u8 voltage_type, u8 voltage_mode,1381struct atom_voltage_table *voltage_table)1382{1383int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);1384u8 frev, crev;1385u16 data_offset, size;1386int i;1387union voltage_object_info *voltage_info;1388union voltage_object *voltage_object = NULL;13891390if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1391&frev, &crev, &data_offset)) {1392voltage_info = (union voltage_object_info *)1393(adev->mode_info.atom_context->bios + data_offset);13941395switch (frev) {1396case 3:1397switch (crev) {1398case 1:1399voltage_object = (union voltage_object *)1400amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,1401voltage_type, voltage_mode);1402if (voltage_object) {1403ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio =1404&voltage_object->v3.asGpioVoltageObj;1405VOLTAGE_LUT_ENTRY_V2 *lut;1406if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES)1407return -EINVAL;1408lut = &gpio->asVolGpioLut[0];1409for (i = 0; i < gpio->ucGpioEntryNum; i++) {1410voltage_table->entries[i].value =1411le16_to_cpu(lut->usVoltageValue);1412voltage_table->entries[i].smio_low =1413le32_to_cpu(lut->ulVoltageId);1414lut = (VOLTAGE_LUT_ENTRY_V2 *)1415((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY_V2));1416}1417voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal);1418voltage_table->count = gpio->ucGpioEntryNum;1419voltage_table->phase_delay = gpio->ucPhaseDelay;1420return 0;1421}1422break;1423default:1424DRM_ERROR("unknown voltage object table\n");1425return -EINVAL;1426}1427break;1428default:1429DRM_ERROR("unknown voltage object table\n");1430return -EINVAL;1431}1432}1433return -EINVAL;1434}14351436union vram_info {1437struct _ATOM_VRAM_INFO_V3 v1_3;1438struct _ATOM_VRAM_INFO_V4 v1_4;1439struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1;1440};14411442#define MEM_ID_MASK 0xff0000001443#define MEM_ID_SHIFT 241444#define CLOCK_RANGE_MASK 0x00ffffff1445#define CLOCK_RANGE_SHIFT 01446#define LOW_NIBBLE_MASK 0xf1447#define DATA_EQU_PREV 01448#define DATA_FROM_TABLE 414491450int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev,1451u8 module_index,1452struct atom_mc_reg_table *reg_table)1453{1454int index = GetIndexIntoMasterTable(DATA, VRAM_Info);1455u8 frev, crev, num_entries, t_mem_id, num_ranges = 0;1456u32 i = 0, j;1457u16 data_offset, size;1458union vram_info *vram_info;14591460memset(reg_table, 0, sizeof(struct atom_mc_reg_table));14611462if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1463&frev, &crev, &data_offset)) {1464vram_info = (union vram_info *)1465(adev->mode_info.atom_context->bios + data_offset);1466switch (frev) {1467case 1:1468DRM_ERROR("old table version %d, %d\n", frev, crev);1469return -EINVAL;1470case 2:1471switch (crev) {1472case 1:1473if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {1474ATOM_INIT_REG_BLOCK *reg_block =1475(ATOM_INIT_REG_BLOCK *)1476((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset));1477ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data =1478(ATOM_MEMORY_SETTING_DATA_BLOCK *)1479((u8 *)reg_block + (2 * sizeof(u16)) +1480le16_to_cpu(reg_block->usRegIndexTblSize));1481ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0];1482num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) /1483sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1;1484if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE)1485return -EINVAL;1486while (i < num_entries) {1487if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER)1488break;1489reg_table->mc_reg_address[i].s1 =1490(u16)(le16_to_cpu(format->usRegIndex));1491reg_table->mc_reg_address[i].pre_reg_data =1492(u8)(format->ucPreRegDataLength);1493i++;1494format = (ATOM_INIT_REG_INDEX_FORMAT *)1495((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));1496}1497reg_table->last = i;1498while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) &&1499(num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {1500t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK)1501>> MEM_ID_SHIFT);1502if (module_index == t_mem_id) {1503reg_table->mc_reg_table_entry[num_ranges].mclk_max =1504(u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK)1505>> CLOCK_RANGE_SHIFT);1506for (i = 0, j = 1; i < reg_table->last; i++) {1507if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {1508reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =1509(u32)le32_to_cpu(*((u32 *)reg_data + j));1510j++;1511} else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {1512if (i == 0)1513continue;1514reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =1515reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1];1516}1517}1518num_ranges++;1519}1520reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)1521((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));1522}1523if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK)1524return -EINVAL;1525reg_table->num_entries = num_ranges;1526} else1527return -EINVAL;1528break;1529default:1530DRM_ERROR("Unknown table version %d, %d\n", frev, crev);1531return -EINVAL;1532}1533break;1534default:1535DRM_ERROR("Unknown table version %d, %d\n", frev, crev);1536return -EINVAL;1537}1538return 0;1539}1540return -EINVAL;1541}1542#endif15431544bool amdgpu_atombios_has_gpu_virtualization_table(struct amdgpu_device *adev)1545{1546int index = GetIndexIntoMasterTable(DATA, GPUVirtualizationInfo);1547u8 frev, crev;1548u16 data_offset, size;15491550if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1551&frev, &crev, &data_offset))1552return true;15531554return false;1555}15561557void amdgpu_atombios_scratch_regs_lock(struct amdgpu_device *adev, bool lock)1558{1559uint32_t bios_6_scratch;15601561bios_6_scratch = RREG32(adev->bios_scratch_reg_offset + 6);15621563if (lock) {1564bios_6_scratch |= ATOM_S6_CRITICAL_STATE;1565bios_6_scratch &= ~ATOM_S6_ACC_MODE;1566} else {1567bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;1568bios_6_scratch |= ATOM_S6_ACC_MODE;1569}15701571WREG32(adev->bios_scratch_reg_offset + 6, bios_6_scratch);1572}15731574static void amdgpu_atombios_scratch_regs_init(struct amdgpu_device *adev)1575{1576uint32_t bios_2_scratch, bios_6_scratch;15771578adev->bios_scratch_reg_offset = mmBIOS_SCRATCH_0;15791580bios_2_scratch = RREG32(adev->bios_scratch_reg_offset + 2);1581bios_6_scratch = RREG32(adev->bios_scratch_reg_offset + 6);15821583/* let the bios control the backlight */1584bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;15851586/* tell the bios not to handle mode switching */1587bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;15881589/* clear the vbios dpms state */1590bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE;15911592WREG32(adev->bios_scratch_reg_offset + 2, bios_2_scratch);1593WREG32(adev->bios_scratch_reg_offset + 6, bios_6_scratch);1594}15951596void amdgpu_atombios_scratch_regs_engine_hung(struct amdgpu_device *adev,1597bool hung)1598{1599u32 tmp = RREG32(adev->bios_scratch_reg_offset + 3);16001601if (hung)1602tmp |= ATOM_S3_ASIC_GUI_ENGINE_HUNG;1603else1604tmp &= ~ATOM_S3_ASIC_GUI_ENGINE_HUNG;16051606WREG32(adev->bios_scratch_reg_offset + 3, tmp);1607}16081609void amdgpu_atombios_scratch_regs_set_backlight_level(struct amdgpu_device *adev,1610u32 backlight_level)1611{1612u32 tmp = RREG32(adev->bios_scratch_reg_offset + 2);16131614tmp &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;1615tmp |= (backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) &1616ATOM_S2_CURRENT_BL_LEVEL_MASK;16171618WREG32(adev->bios_scratch_reg_offset + 2, tmp);1619}16201621bool amdgpu_atombios_scratch_need_asic_init(struct amdgpu_device *adev)1622{1623u32 tmp = RREG32(adev->bios_scratch_reg_offset + 7);16241625if (tmp & ATOM_S7_ASIC_INIT_COMPLETE_MASK)1626return false;1627else1628return true;1629}16301631/* Atom needs data in little endian format so swap as appropriate when copying1632* data to or from atom. Note that atom operates on dw units.1633*1634* Use to_le=true when sending data to atom and provide at least1635* ALIGN(num_bytes,4) bytes in the dst buffer.1636*1637* Use to_le=false when receiving data from atom and provide ALIGN(num_bytes,4)1638* byes in the src buffer.1639*/1640void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)1641{1642#ifdef __BIG_ENDIAN1643u32 src_tmp[5], dst_tmp[5];1644int i;1645u8 align_num_bytes = ALIGN(num_bytes, 4);16461647if (to_le) {1648memcpy(src_tmp, src, num_bytes);1649for (i = 0; i < align_num_bytes / 4; i++)1650dst_tmp[i] = cpu_to_le32(src_tmp[i]);1651memcpy(dst, dst_tmp, align_num_bytes);1652} else {1653memcpy(src_tmp, src, align_num_bytes);1654for (i = 0; i < align_num_bytes / 4; i++)1655dst_tmp[i] = le32_to_cpu(src_tmp[i]);1656memcpy(dst, dst_tmp, num_bytes);1657}1658#else1659memcpy(dst, src, num_bytes);1660#endif1661}16621663static int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev)1664{1665struct atom_context *ctx = adev->mode_info.atom_context;1666int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);1667uint16_t data_offset;1668int usage_bytes = 0;1669struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;1670u64 start_addr;1671u64 size;16721673if (amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {1674firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);16751676DRM_DEBUG("atom firmware requested %08x %dkb\n",1677le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware),1678le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb));16791680start_addr = firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware;1681size = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb;16821683if ((uint32_t)(start_addr & ATOM_VRAM_OPERATION_FLAGS_MASK) ==1684(uint32_t)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION <<1685ATOM_VRAM_OPERATION_FLAGS_SHIFT)) {1686/* Firmware request VRAM reservation for SR-IOV */1687adev->mman.fw_vram_usage_start_offset = (start_addr &1688(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;1689adev->mman.fw_vram_usage_size = size << 10;1690/* Use the default scratch size */1691usage_bytes = 0;1692} else {1693usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024;1694}1695}1696ctx->scratch_size_bytes = 0;1697if (usage_bytes == 0)1698usage_bytes = 20 * 1024;1699/* allocate some scratch memory */1700ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);1701if (!ctx->scratch)1702return -ENOMEM;1703ctx->scratch_size_bytes = usage_bytes;1704return 0;1705}17061707/* ATOM accessor methods */1708/*1709* ATOM is an interpreted byte code stored in tables in the vbios. The1710* driver registers callbacks to access registers and the interpreter1711* in the driver parses the tables and executes then to program specific1712* actions (set display modes, asic init, etc.). See amdgpu_atombios.c,1713* atombios.h, and atom.c1714*/17151716/**1717* cail_pll_read - read PLL register1718*1719* @info: atom card_info pointer1720* @reg: PLL register offset1721*1722* Provides a PLL register accessor for the atom interpreter (r4xx+).1723* Returns the value of the PLL register.1724*/1725static uint32_t cail_pll_read(struct card_info *info, uint32_t reg)1726{1727return 0;1728}17291730/**1731* cail_pll_write - write PLL register1732*1733* @info: atom card_info pointer1734* @reg: PLL register offset1735* @val: value to write to the pll register1736*1737* Provides a PLL register accessor for the atom interpreter (r4xx+).1738*/1739static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val)1740{17411742}17431744/**1745* cail_mc_read - read MC (Memory Controller) register1746*1747* @info: atom card_info pointer1748* @reg: MC register offset1749*1750* Provides an MC register accessor for the atom interpreter (r4xx+).1751* Returns the value of the MC register.1752*/1753static uint32_t cail_mc_read(struct card_info *info, uint32_t reg)1754{1755return 0;1756}17571758/**1759* cail_mc_write - write MC (Memory Controller) register1760*1761* @info: atom card_info pointer1762* @reg: MC register offset1763* @val: value to write to the pll register1764*1765* Provides a MC register accessor for the atom interpreter (r4xx+).1766*/1767static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val)1768{17691770}17711772/**1773* cail_reg_write - write MMIO register1774*1775* @info: atom card_info pointer1776* @reg: MMIO register offset1777* @val: value to write to the pll register1778*1779* Provides a MMIO register accessor for the atom interpreter (r4xx+).1780*/1781static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val)1782{1783struct amdgpu_device *adev = drm_to_adev(info->dev);17841785WREG32(reg, val);1786}17871788/**1789* cail_reg_read - read MMIO register1790*1791* @info: atom card_info pointer1792* @reg: MMIO register offset1793*1794* Provides an MMIO register accessor for the atom interpreter (r4xx+).1795* Returns the value of the MMIO register.1796*/1797static uint32_t cail_reg_read(struct card_info *info, uint32_t reg)1798{1799struct amdgpu_device *adev = drm_to_adev(info->dev);1800uint32_t r;18011802r = RREG32(reg);1803return r;1804}18051806static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev,1807struct device_attribute *attr,1808char *buf)1809{1810struct drm_device *ddev = dev_get_drvdata(dev);1811struct amdgpu_device *adev = drm_to_adev(ddev);1812struct atom_context *ctx = adev->mode_info.atom_context;18131814return sysfs_emit(buf, "%s\n", ctx->vbios_pn);1815}18161817static ssize_t amdgpu_atombios_get_vbios_build(struct device *dev,1818struct device_attribute *attr,1819char *buf)1820{1821struct drm_device *ddev = dev_get_drvdata(dev);1822struct amdgpu_device *adev = drm_to_adev(ddev);1823struct atom_context *ctx = adev->mode_info.atom_context;18241825return sysfs_emit(buf, "%s\n", ctx->build_num);1826}18271828static DEVICE_ATTR(vbios_version, 0444, amdgpu_atombios_get_vbios_version,1829NULL);1830static DEVICE_ATTR(vbios_build, 0444, amdgpu_atombios_get_vbios_build, NULL);18311832static struct attribute *amdgpu_vbios_version_attrs[] = {1833&dev_attr_vbios_version.attr, &dev_attr_vbios_build.attr, NULL1834};18351836static umode_t amdgpu_vbios_version_attrs_is_visible(struct kobject *kobj,1837struct attribute *attr,1838int index)1839{1840struct device *dev = kobj_to_dev(kobj);1841struct drm_device *ddev = dev_get_drvdata(dev);1842struct amdgpu_device *adev = drm_to_adev(ddev);1843struct atom_context *ctx = adev->mode_info.atom_context;18441845if (attr == &dev_attr_vbios_build.attr && !strlen(ctx->build_num))1846return 0;18471848return attr->mode;1849}18501851const struct attribute_group amdgpu_vbios_version_attr_group = {1852.attrs = amdgpu_vbios_version_attrs,1853.is_visible = amdgpu_vbios_version_attrs_is_visible,1854};18551856int amdgpu_atombios_sysfs_init(struct amdgpu_device *adev)1857{1858if (adev->mode_info.atom_context)1859return devm_device_add_group(adev->dev,1860&amdgpu_vbios_version_attr_group);18611862return 0;1863}18641865/**1866* amdgpu_atombios_fini - free the driver info and callbacks for atombios1867*1868* @adev: amdgpu_device pointer1869*1870* Frees the driver info and register access callbacks for the ATOM1871* interpreter (r4xx+).1872* Called at driver shutdown.1873*/1874void amdgpu_atombios_fini(struct amdgpu_device *adev)1875{1876if (adev->mode_info.atom_context) {1877kfree(adev->mode_info.atom_context->scratch);1878kfree(adev->mode_info.atom_context->iio);1879}1880kfree(adev->mode_info.atom_context);1881adev->mode_info.atom_context = NULL;1882kfree(adev->mode_info.atom_card_info);1883adev->mode_info.atom_card_info = NULL;1884}18851886/**1887* amdgpu_atombios_init - init the driver info and callbacks for atombios1888*1889* @adev: amdgpu_device pointer1890*1891* Initializes the driver info and register access callbacks for the1892* ATOM interpreter (r4xx+).1893* Returns 0 on sucess, -ENOMEM on failure.1894* Called at driver startup.1895*/1896int amdgpu_atombios_init(struct amdgpu_device *adev)1897{1898struct card_info *atom_card_info =1899kzalloc(sizeof(struct card_info), GFP_KERNEL);19001901if (!atom_card_info)1902return -ENOMEM;19031904adev->mode_info.atom_card_info = atom_card_info;1905atom_card_info->dev = adev_to_drm(adev);1906atom_card_info->reg_read = cail_reg_read;1907atom_card_info->reg_write = cail_reg_write;1908atom_card_info->mc_read = cail_mc_read;1909atom_card_info->mc_write = cail_mc_write;1910atom_card_info->pll_read = cail_pll_read;1911atom_card_info->pll_write = cail_pll_write;19121913adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios);1914if (!adev->mode_info.atom_context) {1915amdgpu_atombios_fini(adev);1916return -ENOMEM;1917}19181919mutex_init(&adev->mode_info.atom_context->mutex);1920if (adev->is_atom_fw) {1921amdgpu_atomfirmware_scratch_regs_init(adev);1922amdgpu_atomfirmware_allocate_fb_scratch(adev);1923/* cached firmware_flags for further usage */1924adev->mode_info.firmware_flags =1925amdgpu_atomfirmware_query_firmware_capability(adev);1926} else {1927amdgpu_atombios_scratch_regs_init(adev);1928amdgpu_atombios_allocate_fb_scratch(adev);1929}19301931return 0;1932}19331934int amdgpu_atombios_get_data_table(struct amdgpu_device *adev,1935uint32_t table,1936uint16_t *size,1937uint8_t *frev,1938uint8_t *crev,1939uint8_t **addr)1940{1941uint16_t data_start;19421943if (!amdgpu_atom_parse_data_header(adev->mode_info.atom_context, table,1944size, frev, crev, &data_start))1945return -EINVAL;19461947*addr = (uint8_t *)adev->mode_info.atom_context->bios + data_start;19481949return 0;1950}195119521953