Path: blob/master/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
26517 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);708adev->clock.current_dispclk = adev->clock.default_dispclk;709710adev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock);711if (adev->clock.max_pixel_clock == 0)712adev->clock.max_pixel_clock = 40000;713714/* not technically a clock, but... */715adev->mode_info.firmware_flags =716le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);717718ret = 0;719}720721adev->pm.current_sclk = adev->clock.default_sclk;722adev->pm.current_mclk = adev->clock.default_mclk;723724return ret;725}726727union gfx_info {728ATOM_GFX_INFO_V2_1 info;729};730731int amdgpu_atombios_get_gfx_info(struct amdgpu_device *adev)732{733struct amdgpu_mode_info *mode_info = &adev->mode_info;734int index = GetIndexIntoMasterTable(DATA, GFX_Info);735uint8_t frev, crev;736uint16_t data_offset;737int ret = -EINVAL;738739if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,740&frev, &crev, &data_offset)) {741union gfx_info *gfx_info = (union gfx_info *)742(mode_info->atom_context->bios + data_offset);743744adev->gfx.config.max_shader_engines = gfx_info->info.max_shader_engines;745adev->gfx.config.max_tile_pipes = gfx_info->info.max_tile_pipes;746adev->gfx.config.max_cu_per_sh = gfx_info->info.max_cu_per_sh;747adev->gfx.config.max_sh_per_se = gfx_info->info.max_sh_per_se;748adev->gfx.config.max_backends_per_se = gfx_info->info.max_backends_per_se;749adev->gfx.config.max_texture_channel_caches =750gfx_info->info.max_texture_channel_caches;751752ret = 0;753}754return ret;755}756757union igp_info {758struct _ATOM_INTEGRATED_SYSTEM_INFO info;759struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;760struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;761struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;762struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;763struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9 info_9;764};765766/*767* Return vram width from integrated system info table, if available,768* or 0 if not.769*/770int amdgpu_atombios_get_vram_width(struct amdgpu_device *adev)771{772struct amdgpu_mode_info *mode_info = &adev->mode_info;773int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);774u16 data_offset, size;775union igp_info *igp_info;776u8 frev, crev;777778/* get any igp specific overrides */779if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size,780&frev, &crev, &data_offset)) {781igp_info = (union igp_info *)782(mode_info->atom_context->bios + data_offset);783switch (crev) {784case 8:785case 9:786return igp_info->info_8.ucUMAChannelNumber * 64;787default:788return 0;789}790}791792return 0;793}794795static void amdgpu_atombios_get_igp_ss_overrides(struct amdgpu_device *adev,796struct amdgpu_atom_ss *ss,797int id)798{799struct amdgpu_mode_info *mode_info = &adev->mode_info;800int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);801u16 data_offset, size;802union igp_info *igp_info;803u8 frev, crev;804u16 percentage = 0, rate = 0;805806/* get any igp specific overrides */807if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size,808&frev, &crev, &data_offset)) {809igp_info = (union igp_info *)810(mode_info->atom_context->bios + data_offset);811switch (crev) {812case 6:813switch (id) {814case ASIC_INTERNAL_SS_ON_TMDS:815percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage);816rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz);817break;818case ASIC_INTERNAL_SS_ON_HDMI:819percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage);820rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz);821break;822case ASIC_INTERNAL_SS_ON_LVDS:823percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage);824rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz);825break;826}827break;828case 7:829switch (id) {830case ASIC_INTERNAL_SS_ON_TMDS:831percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage);832rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz);833break;834case ASIC_INTERNAL_SS_ON_HDMI:835percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage);836rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz);837break;838case ASIC_INTERNAL_SS_ON_LVDS:839percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage);840rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz);841break;842}843break;844case 8:845switch (id) {846case ASIC_INTERNAL_SS_ON_TMDS:847percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage);848rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz);849break;850case ASIC_INTERNAL_SS_ON_HDMI:851percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage);852rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz);853break;854case ASIC_INTERNAL_SS_ON_LVDS:855percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage);856rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz);857break;858}859break;860case 9:861switch (id) {862case ASIC_INTERNAL_SS_ON_TMDS:863percentage = le16_to_cpu(igp_info->info_9.usDVISSPercentage);864rate = le16_to_cpu(igp_info->info_9.usDVISSpreadRateIn10Hz);865break;866case ASIC_INTERNAL_SS_ON_HDMI:867percentage = le16_to_cpu(igp_info->info_9.usHDMISSPercentage);868rate = le16_to_cpu(igp_info->info_9.usHDMISSpreadRateIn10Hz);869break;870case ASIC_INTERNAL_SS_ON_LVDS:871percentage = le16_to_cpu(igp_info->info_9.usLvdsSSPercentage);872rate = le16_to_cpu(igp_info->info_9.usLvdsSSpreadRateIn10Hz);873break;874}875break;876default:877DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);878break;879}880if (percentage)881ss->percentage = percentage;882if (rate)883ss->rate = rate;884}885}886887union asic_ss_info {888struct _ATOM_ASIC_INTERNAL_SS_INFO info;889struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;890struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;891};892893union asic_ss_assignment {894struct _ATOM_ASIC_SS_ASSIGNMENT v1;895struct _ATOM_ASIC_SS_ASSIGNMENT_V2 v2;896struct _ATOM_ASIC_SS_ASSIGNMENT_V3 v3;897};898899bool amdgpu_atombios_get_asic_ss_info(struct amdgpu_device *adev,900struct amdgpu_atom_ss *ss,901int id, u32 clock)902{903struct amdgpu_mode_info *mode_info = &adev->mode_info;904int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);905uint16_t data_offset, size;906union asic_ss_info *ss_info;907union asic_ss_assignment *ss_assign;908uint8_t frev, crev;909int i, num_indices;910911if (id == ASIC_INTERNAL_MEMORY_SS) {912if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT))913return false;914}915if (id == ASIC_INTERNAL_ENGINE_SS) {916if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT))917return false;918}919920memset(ss, 0, sizeof(struct amdgpu_atom_ss));921if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size,922&frev, &crev, &data_offset)) {923924ss_info =925(union asic_ss_info *)(mode_info->atom_context->bios + data_offset);926927switch (frev) {928case 1:929num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /930sizeof(ATOM_ASIC_SS_ASSIGNMENT);931932ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info.asSpreadSpectrum[0]);933for (i = 0; i < num_indices; i++) {934if ((ss_assign->v1.ucClockIndication == id) &&935(clock <= le32_to_cpu(ss_assign->v1.ulTargetClockRange))) {936ss->percentage =937le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage);938ss->type = ss_assign->v1.ucSpreadSpectrumMode;939ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz);940ss->percentage_divider = 100;941return true;942}943ss_assign = (union asic_ss_assignment *)944((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT));945}946break;947case 2:948num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /949sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);950ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_2.asSpreadSpectrum[0]);951for (i = 0; i < num_indices; i++) {952if ((ss_assign->v2.ucClockIndication == id) &&953(clock <= le32_to_cpu(ss_assign->v2.ulTargetClockRange))) {954ss->percentage =955le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage);956ss->type = ss_assign->v2.ucSpreadSpectrumMode;957ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz);958ss->percentage_divider = 100;959if ((crev == 2) &&960((id == ASIC_INTERNAL_ENGINE_SS) ||961(id == ASIC_INTERNAL_MEMORY_SS)))962ss->rate /= 100;963return true;964}965ss_assign = (union asic_ss_assignment *)966((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2));967}968break;969case 3:970num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /971sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);972ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_3.asSpreadSpectrum[0]);973for (i = 0; i < num_indices; i++) {974if ((ss_assign->v3.ucClockIndication == id) &&975(clock <= le32_to_cpu(ss_assign->v3.ulTargetClockRange))) {976ss->percentage =977le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage);978ss->type = ss_assign->v3.ucSpreadSpectrumMode;979ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz);980if (ss_assign->v3.ucSpreadSpectrumMode &981SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK)982ss->percentage_divider = 1000;983else984ss->percentage_divider = 100;985if ((id == ASIC_INTERNAL_ENGINE_SS) ||986(id == ASIC_INTERNAL_MEMORY_SS))987ss->rate /= 100;988if (adev->flags & AMD_IS_APU)989amdgpu_atombios_get_igp_ss_overrides(adev, ss, id);990return true;991}992ss_assign = (union asic_ss_assignment *)993((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3));994}995break;996default:997DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);998break;999}10001001}1002return false;1003}10041005union get_clock_dividers {1006struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1;1007struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2;1008struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3;1009struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4;1010struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5;1011struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in;1012struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out;1013};10141015int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,1016u8 clock_type,1017u32 clock,1018bool strobe_mode,1019struct atom_clock_dividers *dividers)1020{1021union get_clock_dividers args;1022int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL);1023u8 frev, crev;10241025memset(&args, 0, sizeof(args));1026memset(dividers, 0, sizeof(struct atom_clock_dividers));10271028if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))1029return -EINVAL;10301031switch (crev) {1032case 2:1033case 3:1034case 5:1035/* r6xx, r7xx, evergreen, ni, si.1036* TODO: add support for asic_type <= CHIP_RV770*/1037if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {1038args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);10391040if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1041index, (uint32_t *)&args, sizeof(args)))1042return -EINVAL;10431044dividers->post_div = args.v3.ucPostDiv;1045dividers->enable_post_div = (args.v3.ucCntlFlag &1046ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;1047dividers->enable_dithen = (args.v3.ucCntlFlag &1048ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;1049dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);1050dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);1051dividers->ref_div = args.v3.ucRefDiv;1052dividers->vco_mode = (args.v3.ucCntlFlag &1053ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;1054} else {1055/* for SI we use ComputeMemoryClockParam for memory plls */1056if (adev->asic_type >= CHIP_TAHITI)1057return -EINVAL;1058args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);1059if (strobe_mode)1060args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;10611062if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1063index, (uint32_t *)&args, sizeof(args)))1064return -EINVAL;10651066dividers->post_div = args.v5.ucPostDiv;1067dividers->enable_post_div = (args.v5.ucCntlFlag &1068ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;1069dividers->enable_dithen = (args.v5.ucCntlFlag &1070ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;1071dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv);1072dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac);1073dividers->ref_div = args.v5.ucRefDiv;1074dividers->vco_mode = (args.v5.ucCntlFlag &1075ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;1076}1077break;1078case 4:1079/* fusion */1080args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */10811082if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1083index, (uint32_t *)&args, sizeof(args)))1084return -EINVAL;10851086dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;1087dividers->real_clock = le32_to_cpu(args.v4.ulClock);1088break;1089case 6:1090/* CI */1091/* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */1092args.v6_in.ulClock.ulComputeClockFlag = clock_type;1093args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */10941095if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1096index, (uint32_t *)&args, sizeof(args)))1097return -EINVAL;10981099dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);1100dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);1101dividers->ref_div = args.v6_out.ucPllRefDiv;1102dividers->post_div = args.v6_out.ucPllPostDiv;1103dividers->flags = args.v6_out.ucPllCntlFlag;1104dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock);1105dividers->post_divider = args.v6_out.ulClock.ucPostDiv;1106break;1107default:1108return -EINVAL;1109}1110return 0;1111}11121113#ifdef CONFIG_DRM_AMDGPU_SI1114int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev,1115u32 clock,1116bool strobe_mode,1117struct atom_mpll_param *mpll_param)1118{1119COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 args;1120int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam);1121u8 frev, crev;11221123memset(&args, 0, sizeof(args));1124memset(mpll_param, 0, sizeof(struct atom_mpll_param));11251126if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))1127return -EINVAL;11281129switch (frev) {1130case 2:1131switch (crev) {1132case 1:1133/* SI */1134args.ulClock = cpu_to_le32(clock); /* 10 khz */1135args.ucInputFlag = 0;1136if (strobe_mode)1137args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN;11381139if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1140index, (uint32_t *)&args, sizeof(args)))1141return -EINVAL;11421143mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac);1144mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv);1145mpll_param->post_div = args.ucPostDiv;1146mpll_param->dll_speed = args.ucDllSpeed;1147mpll_param->bwcntl = args.ucBWCntl;1148mpll_param->vco_mode =1149(args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK);1150mpll_param->yclk_sel =1151(args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0;1152mpll_param->qdr =1153(args.ucPllCntlFlag & MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0;1154mpll_param->half_rate =1155(args.ucPllCntlFlag & MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0;1156break;1157default:1158return -EINVAL;1159}1160break;1161default:1162return -EINVAL;1163}1164return 0;1165}11661167int amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev,1168u32 eng_clock, u32 mem_clock)1169{1170SET_ENGINE_CLOCK_PS_ALLOCATION args;1171int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);1172u32 tmp;11731174memset(&args, 0, sizeof(args));11751176tmp = eng_clock & SET_CLOCK_FREQ_MASK;1177tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24);11781179args.ulTargetEngineClock = cpu_to_le32(tmp);1180if (mem_clock)1181args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK);11821183return amdgpu_atom_execute_table(adev->mode_info.atom_context, index,1184(uint32_t *)&args, sizeof(args));1185}11861187void amdgpu_atombios_get_default_voltages(struct amdgpu_device *adev,1188u16 *vddc, u16 *vddci, u16 *mvdd)1189{1190struct amdgpu_mode_info *mode_info = &adev->mode_info;1191int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);1192u8 frev, crev;1193u16 data_offset;1194union firmware_info *firmware_info;11951196*vddc = 0;1197*vddci = 0;1198*mvdd = 0;11991200if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,1201&frev, &crev, &data_offset)) {1202firmware_info =1203(union firmware_info *)(mode_info->atom_context->bios +1204data_offset);1205*vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);1206if ((frev == 2) && (crev >= 2)) {1207*vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);1208*mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage);1209}1210}1211}12121213union set_voltage {1214struct _SET_VOLTAGE_PS_ALLOCATION alloc;1215struct _SET_VOLTAGE_PARAMETERS v1;1216struct _SET_VOLTAGE_PARAMETERS_V2 v2;1217struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;1218};12191220int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type,1221u16 voltage_id, u16 *voltage)1222{1223union set_voltage args;1224int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);1225u8 frev, crev;12261227if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))1228return -EINVAL;12291230switch (crev) {1231case 1:1232return -EINVAL;1233case 2:1234args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;1235args.v2.ucVoltageMode = 0;1236args.v2.usVoltageLevel = 0;12371238if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1239index, (uint32_t *)&args, sizeof(args)))1240return -EINVAL;12411242*voltage = le16_to_cpu(args.v2.usVoltageLevel);1243break;1244case 3:1245args.v3.ucVoltageType = voltage_type;1246args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;1247args.v3.usVoltageLevel = cpu_to_le16(voltage_id);12481249if (amdgpu_atom_execute_table(adev->mode_info.atom_context,1250index, (uint32_t *)&args, sizeof(args)))1251return -EINVAL;12521253*voltage = le16_to_cpu(args.v3.usVoltageLevel);1254break;1255default:1256DRM_ERROR("Unknown table version %d, %d\n", frev, crev);1257return -EINVAL;1258}12591260return 0;1261}12621263int amdgpu_atombios_get_leakage_vddc_based_on_leakage_idx(struct amdgpu_device *adev,1264u16 *voltage,1265u16 leakage_idx)1266{1267return amdgpu_atombios_get_max_vddc(adev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage);1268}12691270union voltage_object_info {1271struct _ATOM_VOLTAGE_OBJECT_INFO v1;1272struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;1273struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;1274};12751276union voltage_object {1277struct _ATOM_VOLTAGE_OBJECT v1;1278struct _ATOM_VOLTAGE_OBJECT_V2 v2;1279union _ATOM_VOLTAGE_OBJECT_V3 v3;1280};128112821283static ATOM_VOLTAGE_OBJECT_V3 *amdgpu_atombios_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3,1284u8 voltage_type, u8 voltage_mode)1285{1286u32 size = le16_to_cpu(v3->sHeader.usStructureSize);1287u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);1288u8 *start = (u8 *)v3;12891290while (offset < size) {1291ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);1292if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) &&1293(vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode))1294return vo;1295offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize);1296}1297return NULL;1298}12991300int amdgpu_atombios_get_svi2_info(struct amdgpu_device *adev,1301u8 voltage_type,1302u8 *svd_gpio_id, u8 *svc_gpio_id)1303{1304int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);1305u8 frev, crev;1306u16 data_offset, size;1307union voltage_object_info *voltage_info;1308union voltage_object *voltage_object = NULL;13091310if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1311&frev, &crev, &data_offset)) {1312voltage_info = (union voltage_object_info *)1313(adev->mode_info.atom_context->bios + data_offset);13141315switch (frev) {1316case 3:1317switch (crev) {1318case 1:1319voltage_object = (union voltage_object *)1320amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,1321voltage_type,1322VOLTAGE_OBJ_SVID2);1323if (voltage_object) {1324*svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId;1325*svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId;1326} else {1327return -EINVAL;1328}1329break;1330default:1331DRM_ERROR("unknown voltage object table\n");1332return -EINVAL;1333}1334break;1335default:1336DRM_ERROR("unknown voltage object table\n");1337return -EINVAL;1338}13391340}1341return 0;1342}13431344bool1345amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev,1346u8 voltage_type, u8 voltage_mode)1347{1348int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);1349u8 frev, crev;1350u16 data_offset, size;1351union voltage_object_info *voltage_info;13521353if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1354&frev, &crev, &data_offset)) {1355voltage_info = (union voltage_object_info *)1356(adev->mode_info.atom_context->bios + data_offset);13571358switch (frev) {1359case 3:1360switch (crev) {1361case 1:1362if (amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,1363voltage_type, voltage_mode))1364return true;1365break;1366default:1367DRM_ERROR("unknown voltage object table\n");1368return false;1369}1370break;1371default:1372DRM_ERROR("unknown voltage object table\n");1373return false;1374}13751376}1377return false;1378}13791380int amdgpu_atombios_get_voltage_table(struct amdgpu_device *adev,1381u8 voltage_type, u8 voltage_mode,1382struct atom_voltage_table *voltage_table)1383{1384int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);1385u8 frev, crev;1386u16 data_offset, size;1387int i;1388union voltage_object_info *voltage_info;1389union voltage_object *voltage_object = NULL;13901391if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1392&frev, &crev, &data_offset)) {1393voltage_info = (union voltage_object_info *)1394(adev->mode_info.atom_context->bios + data_offset);13951396switch (frev) {1397case 3:1398switch (crev) {1399case 1:1400voltage_object = (union voltage_object *)1401amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,1402voltage_type, voltage_mode);1403if (voltage_object) {1404ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio =1405&voltage_object->v3.asGpioVoltageObj;1406VOLTAGE_LUT_ENTRY_V2 *lut;1407if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES)1408return -EINVAL;1409lut = &gpio->asVolGpioLut[0];1410for (i = 0; i < gpio->ucGpioEntryNum; i++) {1411voltage_table->entries[i].value =1412le16_to_cpu(lut->usVoltageValue);1413voltage_table->entries[i].smio_low =1414le32_to_cpu(lut->ulVoltageId);1415lut = (VOLTAGE_LUT_ENTRY_V2 *)1416((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY_V2));1417}1418voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal);1419voltage_table->count = gpio->ucGpioEntryNum;1420voltage_table->phase_delay = gpio->ucPhaseDelay;1421return 0;1422}1423break;1424default:1425DRM_ERROR("unknown voltage object table\n");1426return -EINVAL;1427}1428break;1429default:1430DRM_ERROR("unknown voltage object table\n");1431return -EINVAL;1432}1433}1434return -EINVAL;1435}14361437union vram_info {1438struct _ATOM_VRAM_INFO_V3 v1_3;1439struct _ATOM_VRAM_INFO_V4 v1_4;1440struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1;1441};14421443#define MEM_ID_MASK 0xff0000001444#define MEM_ID_SHIFT 241445#define CLOCK_RANGE_MASK 0x00ffffff1446#define CLOCK_RANGE_SHIFT 01447#define LOW_NIBBLE_MASK 0xf1448#define DATA_EQU_PREV 01449#define DATA_FROM_TABLE 414501451int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev,1452u8 module_index,1453struct atom_mc_reg_table *reg_table)1454{1455int index = GetIndexIntoMasterTable(DATA, VRAM_Info);1456u8 frev, crev, num_entries, t_mem_id, num_ranges = 0;1457u32 i = 0, j;1458u16 data_offset, size;1459union vram_info *vram_info;14601461memset(reg_table, 0, sizeof(struct atom_mc_reg_table));14621463if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1464&frev, &crev, &data_offset)) {1465vram_info = (union vram_info *)1466(adev->mode_info.atom_context->bios + data_offset);1467switch (frev) {1468case 1:1469DRM_ERROR("old table version %d, %d\n", frev, crev);1470return -EINVAL;1471case 2:1472switch (crev) {1473case 1:1474if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {1475ATOM_INIT_REG_BLOCK *reg_block =1476(ATOM_INIT_REG_BLOCK *)1477((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset));1478ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data =1479(ATOM_MEMORY_SETTING_DATA_BLOCK *)1480((u8 *)reg_block + (2 * sizeof(u16)) +1481le16_to_cpu(reg_block->usRegIndexTblSize));1482ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0];1483num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) /1484sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1;1485if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE)1486return -EINVAL;1487while (i < num_entries) {1488if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER)1489break;1490reg_table->mc_reg_address[i].s1 =1491(u16)(le16_to_cpu(format->usRegIndex));1492reg_table->mc_reg_address[i].pre_reg_data =1493(u8)(format->ucPreRegDataLength);1494i++;1495format = (ATOM_INIT_REG_INDEX_FORMAT *)1496((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));1497}1498reg_table->last = i;1499while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) &&1500(num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {1501t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK)1502>> MEM_ID_SHIFT);1503if (module_index == t_mem_id) {1504reg_table->mc_reg_table_entry[num_ranges].mclk_max =1505(u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK)1506>> CLOCK_RANGE_SHIFT);1507for (i = 0, j = 1; i < reg_table->last; i++) {1508if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {1509reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =1510(u32)le32_to_cpu(*((u32 *)reg_data + j));1511j++;1512} else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {1513if (i == 0)1514continue;1515reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =1516reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1];1517}1518}1519num_ranges++;1520}1521reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)1522((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));1523}1524if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK)1525return -EINVAL;1526reg_table->num_entries = num_ranges;1527} else1528return -EINVAL;1529break;1530default:1531DRM_ERROR("Unknown table version %d, %d\n", frev, crev);1532return -EINVAL;1533}1534break;1535default:1536DRM_ERROR("Unknown table version %d, %d\n", frev, crev);1537return -EINVAL;1538}1539return 0;1540}1541return -EINVAL;1542}1543#endif15441545bool amdgpu_atombios_has_gpu_virtualization_table(struct amdgpu_device *adev)1546{1547int index = GetIndexIntoMasterTable(DATA, GPUVirtualizationInfo);1548u8 frev, crev;1549u16 data_offset, size;15501551if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,1552&frev, &crev, &data_offset))1553return true;15541555return false;1556}15571558void amdgpu_atombios_scratch_regs_lock(struct amdgpu_device *adev, bool lock)1559{1560uint32_t bios_6_scratch;15611562bios_6_scratch = RREG32(adev->bios_scratch_reg_offset + 6);15631564if (lock) {1565bios_6_scratch |= ATOM_S6_CRITICAL_STATE;1566bios_6_scratch &= ~ATOM_S6_ACC_MODE;1567} else {1568bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;1569bios_6_scratch |= ATOM_S6_ACC_MODE;1570}15711572WREG32(adev->bios_scratch_reg_offset + 6, bios_6_scratch);1573}15741575static void amdgpu_atombios_scratch_regs_init(struct amdgpu_device *adev)1576{1577uint32_t bios_2_scratch, bios_6_scratch;15781579adev->bios_scratch_reg_offset = mmBIOS_SCRATCH_0;15801581bios_2_scratch = RREG32(adev->bios_scratch_reg_offset + 2);1582bios_6_scratch = RREG32(adev->bios_scratch_reg_offset + 6);15831584/* let the bios control the backlight */1585bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;15861587/* tell the bios not to handle mode switching */1588bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;15891590/* clear the vbios dpms state */1591bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE;15921593WREG32(adev->bios_scratch_reg_offset + 2, bios_2_scratch);1594WREG32(adev->bios_scratch_reg_offset + 6, bios_6_scratch);1595}15961597void amdgpu_atombios_scratch_regs_engine_hung(struct amdgpu_device *adev,1598bool hung)1599{1600u32 tmp = RREG32(adev->bios_scratch_reg_offset + 3);16011602if (hung)1603tmp |= ATOM_S3_ASIC_GUI_ENGINE_HUNG;1604else1605tmp &= ~ATOM_S3_ASIC_GUI_ENGINE_HUNG;16061607WREG32(adev->bios_scratch_reg_offset + 3, tmp);1608}16091610void amdgpu_atombios_scratch_regs_set_backlight_level(struct amdgpu_device *adev,1611u32 backlight_level)1612{1613u32 tmp = RREG32(adev->bios_scratch_reg_offset + 2);16141615tmp &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;1616tmp |= (backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) &1617ATOM_S2_CURRENT_BL_LEVEL_MASK;16181619WREG32(adev->bios_scratch_reg_offset + 2, tmp);1620}16211622bool amdgpu_atombios_scratch_need_asic_init(struct amdgpu_device *adev)1623{1624u32 tmp = RREG32(adev->bios_scratch_reg_offset + 7);16251626if (tmp & ATOM_S7_ASIC_INIT_COMPLETE_MASK)1627return false;1628else1629return true;1630}16311632/* Atom needs data in little endian format so swap as appropriate when copying1633* data to or from atom. Note that atom operates on dw units.1634*1635* Use to_le=true when sending data to atom and provide at least1636* ALIGN(num_bytes,4) bytes in the dst buffer.1637*1638* Use to_le=false when receiving data from atom and provide ALIGN(num_bytes,4)1639* byes in the src buffer.1640*/1641void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)1642{1643#ifdef __BIG_ENDIAN1644u32 src_tmp[5], dst_tmp[5];1645int i;1646u8 align_num_bytes = ALIGN(num_bytes, 4);16471648if (to_le) {1649memcpy(src_tmp, src, num_bytes);1650for (i = 0; i < align_num_bytes / 4; i++)1651dst_tmp[i] = cpu_to_le32(src_tmp[i]);1652memcpy(dst, dst_tmp, align_num_bytes);1653} else {1654memcpy(src_tmp, src, align_num_bytes);1655for (i = 0; i < align_num_bytes / 4; i++)1656dst_tmp[i] = le32_to_cpu(src_tmp[i]);1657memcpy(dst, dst_tmp, num_bytes);1658}1659#else1660memcpy(dst, src, num_bytes);1661#endif1662}16631664static int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev)1665{1666struct atom_context *ctx = adev->mode_info.atom_context;1667int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);1668uint16_t data_offset;1669int usage_bytes = 0;1670struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;1671u64 start_addr;1672u64 size;16731674if (amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {1675firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);16761677DRM_DEBUG("atom firmware requested %08x %dkb\n",1678le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware),1679le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb));16801681start_addr = firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware;1682size = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb;16831684if ((uint32_t)(start_addr & ATOM_VRAM_OPERATION_FLAGS_MASK) ==1685(uint32_t)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION <<1686ATOM_VRAM_OPERATION_FLAGS_SHIFT)) {1687/* Firmware request VRAM reservation for SR-IOV */1688adev->mman.fw_vram_usage_start_offset = (start_addr &1689(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;1690adev->mman.fw_vram_usage_size = size << 10;1691/* Use the default scratch size */1692usage_bytes = 0;1693} else {1694usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024;1695}1696}1697ctx->scratch_size_bytes = 0;1698if (usage_bytes == 0)1699usage_bytes = 20 * 1024;1700/* allocate some scratch memory */1701ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);1702if (!ctx->scratch)1703return -ENOMEM;1704ctx->scratch_size_bytes = usage_bytes;1705return 0;1706}17071708/* ATOM accessor methods */1709/*1710* ATOM is an interpreted byte code stored in tables in the vbios. The1711* driver registers callbacks to access registers and the interpreter1712* in the driver parses the tables and executes then to program specific1713* actions (set display modes, asic init, etc.). See amdgpu_atombios.c,1714* atombios.h, and atom.c1715*/17161717/**1718* cail_pll_read - read PLL register1719*1720* @info: atom card_info pointer1721* @reg: PLL register offset1722*1723* Provides a PLL register accessor for the atom interpreter (r4xx+).1724* Returns the value of the PLL register.1725*/1726static uint32_t cail_pll_read(struct card_info *info, uint32_t reg)1727{1728return 0;1729}17301731/**1732* cail_pll_write - write PLL register1733*1734* @info: atom card_info pointer1735* @reg: PLL register offset1736* @val: value to write to the pll register1737*1738* Provides a PLL register accessor for the atom interpreter (r4xx+).1739*/1740static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val)1741{17421743}17441745/**1746* cail_mc_read - read MC (Memory Controller) register1747*1748* @info: atom card_info pointer1749* @reg: MC register offset1750*1751* Provides an MC register accessor for the atom interpreter (r4xx+).1752* Returns the value of the MC register.1753*/1754static uint32_t cail_mc_read(struct card_info *info, uint32_t reg)1755{1756return 0;1757}17581759/**1760* cail_mc_write - write MC (Memory Controller) register1761*1762* @info: atom card_info pointer1763* @reg: MC register offset1764* @val: value to write to the pll register1765*1766* Provides a MC register accessor for the atom interpreter (r4xx+).1767*/1768static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val)1769{17701771}17721773/**1774* cail_reg_write - write MMIO register1775*1776* @info: atom card_info pointer1777* @reg: MMIO register offset1778* @val: value to write to the pll register1779*1780* Provides a MMIO register accessor for the atom interpreter (r4xx+).1781*/1782static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val)1783{1784struct amdgpu_device *adev = drm_to_adev(info->dev);17851786WREG32(reg, val);1787}17881789/**1790* cail_reg_read - read MMIO register1791*1792* @info: atom card_info pointer1793* @reg: MMIO register offset1794*1795* Provides an MMIO register accessor for the atom interpreter (r4xx+).1796* Returns the value of the MMIO register.1797*/1798static uint32_t cail_reg_read(struct card_info *info, uint32_t reg)1799{1800struct amdgpu_device *adev = drm_to_adev(info->dev);1801uint32_t r;18021803r = RREG32(reg);1804return r;1805}18061807static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev,1808struct device_attribute *attr,1809char *buf)1810{1811struct drm_device *ddev = dev_get_drvdata(dev);1812struct amdgpu_device *adev = drm_to_adev(ddev);1813struct atom_context *ctx = adev->mode_info.atom_context;18141815return sysfs_emit(buf, "%s\n", ctx->vbios_pn);1816}18171818static DEVICE_ATTR(vbios_version, 0444, amdgpu_atombios_get_vbios_version,1819NULL);18201821static struct attribute *amdgpu_vbios_version_attrs[] = {1822&dev_attr_vbios_version.attr,1823NULL1824};18251826const struct attribute_group amdgpu_vbios_version_attr_group = {1827.attrs = amdgpu_vbios_version_attrs1828};18291830int amdgpu_atombios_sysfs_init(struct amdgpu_device *adev)1831{1832if (adev->mode_info.atom_context)1833return devm_device_add_group(adev->dev,1834&amdgpu_vbios_version_attr_group);18351836return 0;1837}18381839/**1840* amdgpu_atombios_fini - free the driver info and callbacks for atombios1841*1842* @adev: amdgpu_device pointer1843*1844* Frees the driver info and register access callbacks for the ATOM1845* interpreter (r4xx+).1846* Called at driver shutdown.1847*/1848void amdgpu_atombios_fini(struct amdgpu_device *adev)1849{1850if (adev->mode_info.atom_context) {1851kfree(adev->mode_info.atom_context->scratch);1852kfree(adev->mode_info.atom_context->iio);1853}1854kfree(adev->mode_info.atom_context);1855adev->mode_info.atom_context = NULL;1856kfree(adev->mode_info.atom_card_info);1857adev->mode_info.atom_card_info = NULL;1858}18591860/**1861* amdgpu_atombios_init - init the driver info and callbacks for atombios1862*1863* @adev: amdgpu_device pointer1864*1865* Initializes the driver info and register access callbacks for the1866* ATOM interpreter (r4xx+).1867* Returns 0 on sucess, -ENOMEM on failure.1868* Called at driver startup.1869*/1870int amdgpu_atombios_init(struct amdgpu_device *adev)1871{1872struct card_info *atom_card_info =1873kzalloc(sizeof(struct card_info), GFP_KERNEL);18741875if (!atom_card_info)1876return -ENOMEM;18771878adev->mode_info.atom_card_info = atom_card_info;1879atom_card_info->dev = adev_to_drm(adev);1880atom_card_info->reg_read = cail_reg_read;1881atom_card_info->reg_write = cail_reg_write;1882atom_card_info->mc_read = cail_mc_read;1883atom_card_info->mc_write = cail_mc_write;1884atom_card_info->pll_read = cail_pll_read;1885atom_card_info->pll_write = cail_pll_write;18861887adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios);1888if (!adev->mode_info.atom_context) {1889amdgpu_atombios_fini(adev);1890return -ENOMEM;1891}18921893mutex_init(&adev->mode_info.atom_context->mutex);1894if (adev->is_atom_fw) {1895amdgpu_atomfirmware_scratch_regs_init(adev);1896amdgpu_atomfirmware_allocate_fb_scratch(adev);1897/* cached firmware_flags for further usage */1898adev->mode_info.firmware_flags =1899amdgpu_atomfirmware_query_firmware_capability(adev);1900} else {1901amdgpu_atombios_scratch_regs_init(adev);1902amdgpu_atombios_allocate_fb_scratch(adev);1903}19041905return 0;1906}19071908int amdgpu_atombios_get_data_table(struct amdgpu_device *adev,1909uint32_t table,1910uint16_t *size,1911uint8_t *frev,1912uint8_t *crev,1913uint8_t **addr)1914{1915uint16_t data_start;19161917if (!amdgpu_atom_parse_data_header(adev->mode_info.atom_context, table,1918size, frev, crev, &data_start))1919return -EINVAL;19201921*addr = (uint8_t *)adev->mode_info.atom_context->bios + data_start;19221923return 0;1924}192519261927