/* * Copyright 2016 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * */ #include "ppatomfwctrl.h" #include "atomfirmware.h" #include "pp_debug.h" static const union atom_voltage_object_v4 *pp_atomfwctrl_lookup_voltage_type_v4( const struct atom_voltage_objects_info_v4_1 *voltage_object_info_table, uint8_t voltage_type, uint8_t voltage_mode) { unsigned int size = le16_to_cpu( voltage_object_info_table->table_header.structuresize); unsigned int offset = offsetof(struct atom_voltage_objects_info_v4_1, voltage_object[0]); unsigned long start = (unsigned long)voltage_object_info_table; while (offset < size) { const union atom_voltage_object_v4 *voltage_object = (const union atom_voltage_object_v4 *)(start + offset); if (voltage_type == voltage_object->gpio_voltage_obj.header.voltage_type && voltage_mode == voltage_object->gpio_voltage_obj.header.voltage_mode) return voltage_object; offset += le16_to_cpu(voltage_object->gpio_voltage_obj.header.object_size); } return NULL; } static struct atom_voltage_objects_info_v4_1 *pp_atomfwctrl_get_voltage_info_table( struct pp_hwmgr *hwmgr) { const void *table_address; uint16_t idx; idx = GetIndexIntoMasterDataTable(voltageobject_info); table_address = cgs_atom_get_data_table(hwmgr->device, idx, NULL, NULL, NULL); PP_ASSERT_WITH_CODE( table_address, "Error retrieving BIOS Table Address!", return NULL); return (struct atom_voltage_objects_info_v4_1 *)table_address; } /** * Returns TRUE if the given voltage type is controlled by GPIO pins. * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC, SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ. * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE */ bool pp_atomfwctrl_is_voltage_controlled_by_gpio_v4(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode) { struct atom_voltage_objects_info_v4_1 *voltage_info = (struct atom_voltage_objects_info_v4_1 *) pp_atomfwctrl_get_voltage_info_table(hwmgr); bool ret; /* If we cannot find the table do NOT try to control this voltage. */ PP_ASSERT_WITH_CODE(voltage_info, "Could not find Voltage Table in BIOS.", return false); ret = (pp_atomfwctrl_lookup_voltage_type_v4(voltage_info, voltage_type, voltage_mode)) ? true : false; return ret; } int pp_atomfwctrl_get_voltage_table_v4(struct pp_hwmgr *hwmgr, uint8_t voltage_type, uint8_t voltage_mode, struct pp_atomfwctrl_voltage_table *voltage_table) { struct atom_voltage_objects_info_v4_1 *voltage_info = (struct atom_voltage_objects_info_v4_1 *) pp_atomfwctrl_get_voltage_info_table(hwmgr); const union atom_voltage_object_v4 *voltage_object; unsigned int i; int result = 0; PP_ASSERT_WITH_CODE(voltage_info, "Could not find Voltage Table in BIOS.", return -1); voltage_object = pp_atomfwctrl_lookup_voltage_type_v4(voltage_info, voltage_type, voltage_mode); if (!voltage_object) return -1; voltage_table->count = 0; if (voltage_mode == VOLTAGE_OBJ_GPIO_LUT) { PP_ASSERT_WITH_CODE( (voltage_object->gpio_voltage_obj.gpio_entry_num <= PP_ATOMFWCTRL_MAX_VOLTAGE_ENTRIES), "Too many voltage entries!", result = -1); if (!result) { for (i = 0; i < voltage_object->gpio_voltage_obj. gpio_entry_num; i++) { voltage_table->entries[i].value = le16_to_cpu(voltage_object->gpio_voltage_obj. voltage_gpio_lut[i].voltage_level_mv); voltage_table->entries[i].smio_low = le32_to_cpu(voltage_object->gpio_voltage_obj. voltage_gpio_lut[i].voltage_gpio_reg_val); } voltage_table->count = voltage_object->gpio_voltage_obj.gpio_entry_num; voltage_table->mask_low = le32_to_cpu( voltage_object->gpio_voltage_obj.gpio_mask_val); voltage_table->phase_delay = voltage_object->gpio_voltage_obj.phase_delay_us; } } else if (voltage_mode == VOLTAGE_OBJ_SVID2) { voltage_table->psi1_enable = (voltage_object->svid2_voltage_obj.loadline_psi1 & 0x20) >> 5; voltage_table->psi0_enable = voltage_object->svid2_voltage_obj.psi0_enable & 0x1; voltage_table->max_vid_step = voltage_object->svid2_voltage_obj.maxvstep; voltage_table->telemetry_offset = voltage_object->svid2_voltage_obj.telemetry_offset; voltage_table->telemetry_slope = voltage_object->svid2_voltage_obj.telemetry_gain; } else PP_ASSERT_WITH_CODE(false, "Unsupported Voltage Object Mode!", result = -1); return result; } static struct atom_gpio_pin_lut_v2_1 *pp_atomfwctrl_get_gpio_lookup_table( struct pp_hwmgr *hwmgr) { const void *table_address; uint16_t idx; idx = GetIndexIntoMasterDataTable(gpio_pin_lut); table_address = cgs_atom_get_data_table(hwmgr->device, idx, NULL, NULL, NULL); PP_ASSERT_WITH_CODE(table_address, "Error retrieving BIOS Table Address!", return NULL); return (struct atom_gpio_pin_lut_v2_1 *)table_address; } static bool pp_atomfwctrl_lookup_gpio_pin( struct atom_gpio_pin_lut_v2_1 *gpio_lookup_table, const uint32_t pin_id, struct pp_atomfwctrl_gpio_pin_assignment *gpio_pin_assignment) { unsigned int size = le16_to_cpu( gpio_lookup_table->table_header.structuresize); unsigned int offset = offsetof(struct atom_gpio_pin_lut_v2_1, gpio_pin[0]); unsigned long start = (unsigned long)gpio_lookup_table; while (offset < size) { const struct atom_gpio_pin_assignment *pin_assignment = (const struct atom_gpio_pin_assignment *)(start + offset); if (pin_id == pin_assignment->gpio_id) { gpio_pin_assignment->uc_gpio_pin_bit_shift = pin_assignment->gpio_bitshift; gpio_pin_assignment->us_gpio_pin_aindex = le16_to_cpu(pin_assignment->data_a_reg_index); return true; } offset += offsetof(struct atom_gpio_pin_assignment, gpio_id) + 1; } return false; } /** * Returns TRUE if the given pin id find in lookup table. */ bool pp_atomfwctrl_get_pp_assign_pin(struct pp_hwmgr *hwmgr, const uint32_t pin_id, struct pp_atomfwctrl_gpio_pin_assignment *gpio_pin_assignment) { bool ret = false; struct atom_gpio_pin_lut_v2_1 *gpio_lookup_table = pp_atomfwctrl_get_gpio_lookup_table(hwmgr); /* If we cannot find the table do NOT try to control this voltage. */ PP_ASSERT_WITH_CODE(gpio_lookup_table, "Could not find GPIO lookup Table in BIOS.", return false); ret = pp_atomfwctrl_lookup_gpio_pin(gpio_lookup_table, pin_id, gpio_pin_assignment); return ret; } /** * Enter to SelfRefresh mode. * @param hwmgr */ int pp_atomfwctrl_enter_self_refresh(struct pp_hwmgr *hwmgr) { /* 0 - no action * 1 - leave power to video memory always on */ return 0; } /** pp_atomfwctrl_get_gpu_pll_dividers_vega10(). * * @param hwmgr input parameter: pointer to HwMgr * @param clock_type input parameter: Clock type: 1 - GFXCLK, 2 - UCLK, 0 - All other clocks * @param clock_value input parameter: Clock * @param dividers output parameter:Clock dividers */ int pp_atomfwctrl_get_gpu_pll_dividers_vega10(struct pp_hwmgr *hwmgr, uint32_t clock_type, uint32_t clock_value, struct pp_atomfwctrl_clock_dividers_soc15 *dividers) { struct compute_gpu_clock_input_parameter_v1_8 pll_parameters; struct compute_gpu_clock_output_parameter_v1_8 *pll_output; int result; uint32_t idx; pll_parameters.gpuclock_10khz = (uint32_t)clock_value; pll_parameters.gpu_clock_type = clock_type; idx = GetIndexIntoMasterCmdTable(computegpuclockparam); result = cgs_atom_exec_cmd_table(hwmgr->device, idx, &pll_parameters); if (!result) { pll_output = (struct compute_gpu_clock_output_parameter_v1_8 *) &pll_parameters; dividers->ulClock = le32_to_cpu(pll_output->gpuclock_10khz); dividers->ulDid = le32_to_cpu(pll_output->dfs_did); dividers->ulPll_fb_mult = le32_to_cpu(pll_output->pll_fb_mult); dividers->ulPll_ss_fbsmult = le32_to_cpu(pll_output->pll_ss_fbsmult); dividers->usPll_ss_slew_frac = le16_to_cpu(pll_output->pll_ss_slew_frac); dividers->ucPll_ss_enable = pll_output->pll_ss_enable; } return result; } int pp_atomfwctrl_get_avfs_information(struct pp_hwmgr *hwmgr, struct pp_atomfwctrl_avfs_parameters *param) { uint16_t idx; uint8_t format_revision, content_revision; struct atom_asic_profiling_info_v4_1 *profile; struct atom_asic_profiling_info_v4_2 *profile_v4_2; idx = GetIndexIntoMasterDataTable(asic_profiling_info); profile = (struct atom_asic_profiling_info_v4_1 *) cgs_atom_get_data_table(hwmgr->device, idx, NULL, NULL, NULL); if (!profile) return -1; format_revision = ((struct atom_common_table_header *)profile)->format_revision; content_revision = ((struct atom_common_table_header *)profile)->content_revision; if (format_revision == 4 && content_revision == 1) { param->ulMaxVddc = le32_to_cpu(profile->maxvddc); param->ulMinVddc = le32_to_cpu(profile->minvddc); param->ulMeanNsigmaAcontant0 = le32_to_cpu(profile->avfs_meannsigma_acontant0); param->ulMeanNsigmaAcontant1 = le32_to_cpu(profile->avfs_meannsigma_acontant1); param->ulMeanNsigmaAcontant2 = le32_to_cpu(profile->avfs_meannsigma_acontant2); param->usMeanNsigmaDcTolSigma = le16_to_cpu(profile->avfs_meannsigma_dc_tol_sigma); param->usMeanNsigmaPlatformMean = le16_to_cpu(profile->avfs_meannsigma_platform_mean); param->usMeanNsigmaPlatformSigma = le16_to_cpu(profile->avfs_meannsigma_platform_sigma); param->ulGbVdroopTableCksoffA0 = le32_to_cpu(profile->gb_vdroop_table_cksoff_a0); param->ulGbVdroopTableCksoffA1 = le32_to_cpu(profile->gb_vdroop_table_cksoff_a1); param->ulGbVdroopTableCksoffA2 = le32_to_cpu(profile->gb_vdroop_table_cksoff_a2); param->ulGbVdroopTableCksonA0 = le32_to_cpu(profile->gb_vdroop_table_ckson_a0); param->ulGbVdroopTableCksonA1 = le32_to_cpu(profile->gb_vdroop_table_ckson_a1); param->ulGbVdroopTableCksonA2 = le32_to_cpu(profile->gb_vdroop_table_ckson_a2); param->ulGbFuseTableCksoffM1 = le32_to_cpu(profile->avfsgb_fuse_table_cksoff_m1); param->ulGbFuseTableCksoffM2 = le32_to_cpu(profile->avfsgb_fuse_table_cksoff_m2); param->ulGbFuseTableCksoffB = le32_to_cpu(profile->avfsgb_fuse_table_cksoff_b); param->ulGbFuseTableCksonM1 = le32_to_cpu(profile->avfsgb_fuse_table_ckson_m1); param->ulGbFuseTableCksonM2 = le32_to_cpu(profile->avfsgb_fuse_table_ckson_m2); param->ulGbFuseTableCksonB = le32_to_cpu(profile->avfsgb_fuse_table_ckson_b); param->ucEnableGbVdroopTableCkson = profile->enable_gb_vdroop_table_ckson; param->ucEnableGbFuseTableCkson = profile->enable_gb_fuse_table_ckson; param->usPsmAgeComfactor = le16_to_cpu(profile->psm_age_comfactor); param->ulDispclk2GfxclkM1 = le32_to_cpu(profile->dispclk2gfxclk_a); param->ulDispclk2GfxclkM2 = le32_to_cpu(profile->dispclk2gfxclk_b); param->ulDispclk2GfxclkB = le32_to_cpu(profile->dispclk2gfxclk_c); param->ulDcefclk2GfxclkM1 = le32_to_cpu(profile->dcefclk2gfxclk_a); param->ulDcefclk2GfxclkM2 = le32_to_cpu(profile->dcefclk2gfxclk_b); param->ulDcefclk2GfxclkB = le32_to_cpu(profile->dcefclk2gfxclk_c); param->ulPixelclk2GfxclkM1 = le32_to_cpu(profile->pixclk2gfxclk_a); param->ulPixelclk2GfxclkM2 = le32_to_cpu(profile->pixclk2gfxclk_b); param->ulPixelclk2GfxclkB = le32_to_cpu(profile->pixclk2gfxclk_c); param->ulPhyclk2GfxclkM1 = le32_to_cpu(profile->phyclk2gfxclk_a); param->ulPhyclk2GfxclkM2 = le32_to_cpu(profile->phyclk2gfxclk_b); param->ulPhyclk2GfxclkB = le32_to_cpu(profile->phyclk2gfxclk_c); param->ulAcgGbVdroopTableA0 = 0; param->ulAcgGbVdroopTableA1 = 0; param->ulAcgGbVdroopTableA2 = 0; param->ulAcgGbFuseTableM1 = 0; param->ulAcgGbFuseTableM2 = 0; param->ulAcgGbFuseTableB = 0; param->ucAcgEnableGbVdroopTable = 0; param->ucAcgEnableGbFuseTable = 0; } else if (format_revision == 4 && content_revision == 2) { profile_v4_2 = (struct atom_asic_profiling_info_v4_2 *)profile; param->ulMaxVddc = le32_to_cpu(profile_v4_2->maxvddc); param->ulMinVddc = le32_to_cpu(profile_v4_2->minvddc); param->ulMeanNsigmaAcontant0 = le32_to_cpu(profile_v4_2->avfs_meannsigma_acontant0); param->ulMeanNsigmaAcontant1 = le32_to_cpu(profile_v4_2->avfs_meannsigma_acontant1); param->ulMeanNsigmaAcontant2 = le32_to_cpu(profile_v4_2->avfs_meannsigma_acontant2); param->usMeanNsigmaDcTolSigma = le16_to_cpu(profile_v4_2->avfs_meannsigma_dc_tol_sigma); param->usMeanNsigmaPlatformMean = le16_to_cpu(profile_v4_2->avfs_meannsigma_platform_mean); param->usMeanNsigmaPlatformSigma = le16_to_cpu(profile_v4_2->avfs_meannsigma_platform_sigma); param->ulGbVdroopTableCksoffA0 = le32_to_cpu(profile_v4_2->gb_vdroop_table_cksoff_a0); param->ulGbVdroopTableCksoffA1 = le32_to_cpu(profile_v4_2->gb_vdroop_table_cksoff_a1); param->ulGbVdroopTableCksoffA2 = le32_to_cpu(profile_v4_2->gb_vdroop_table_cksoff_a2); param->ulGbVdroopTableCksonA0 = le32_to_cpu(profile_v4_2->gb_vdroop_table_ckson_a0); param->ulGbVdroopTableCksonA1 = le32_to_cpu(profile_v4_2->gb_vdroop_table_ckson_a1); param->ulGbVdroopTableCksonA2 = le32_to_cpu(profile_v4_2->gb_vdroop_table_ckson_a2); param->ulGbFuseTableCksoffM1 = le32_to_cpu(profile_v4_2->avfsgb_fuse_table_cksoff_m1); param->ulGbFuseTableCksoffM2 = le32_to_cpu(profile_v4_2->avfsgb_fuse_table_cksoff_m2); param->ulGbFuseTableCksoffB = le32_to_cpu(profile_v4_2->avfsgb_fuse_table_cksoff_b); param->ulGbFuseTableCksonM1 = le32_to_cpu(profile_v4_2->avfsgb_fuse_table_ckson_m1); param->ulGbFuseTableCksonM2 = le32_to_cpu(profile_v4_2->avfsgb_fuse_table_ckson_m2); param->ulGbFuseTableCksonB = le32_to_cpu(profile_v4_2->avfsgb_fuse_table_ckson_b); param->ucEnableGbVdroopTableCkson = profile_v4_2->enable_gb_vdroop_table_ckson; param->ucEnableGbFuseTableCkson = profile_v4_2->enable_gb_fuse_table_ckson; param->usPsmAgeComfactor = le16_to_cpu(profile_v4_2->psm_age_comfactor); param->ulDispclk2GfxclkM1 = le32_to_cpu(profile_v4_2->dispclk2gfxclk_a); param->ulDispclk2GfxclkM2 = le32_to_cpu(profile_v4_2->dispclk2gfxclk_b); param->ulDispclk2GfxclkB = le32_to_cpu(profile_v4_2->dispclk2gfxclk_c); param->ulDcefclk2GfxclkM1 = le32_to_cpu(profile_v4_2->dcefclk2gfxclk_a); param->ulDcefclk2GfxclkM2 = le32_to_cpu(profile_v4_2->dcefclk2gfxclk_b); param->ulDcefclk2GfxclkB = le32_to_cpu(profile_v4_2->dcefclk2gfxclk_c); param->ulPixelclk2GfxclkM1 = le32_to_cpu(profile_v4_2->pixclk2gfxclk_a); param->ulPixelclk2GfxclkM2 = le32_to_cpu(profile_v4_2->pixclk2gfxclk_b); param->ulPixelclk2GfxclkB = le32_to_cpu(profile_v4_2->pixclk2gfxclk_c); param->ulPhyclk2GfxclkM1 = le32_to_cpu(profile->phyclk2gfxclk_a); param->ulPhyclk2GfxclkM2 = le32_to_cpu(profile_v4_2->phyclk2gfxclk_b); param->ulPhyclk2GfxclkB = le32_to_cpu(profile_v4_2->phyclk2gfxclk_c); param->ulAcgGbVdroopTableA0 = le32_to_cpu(profile_v4_2->acg_gb_vdroop_table_a0); param->ulAcgGbVdroopTableA1 = le32_to_cpu(profile_v4_2->acg_gb_vdroop_table_a1); param->ulAcgGbVdroopTableA2 = le32_to_cpu(profile_v4_2->acg_gb_vdroop_table_a2); param->ulAcgGbFuseTableM1 = le32_to_cpu(profile_v4_2->acg_avfsgb_fuse_table_m1); param->ulAcgGbFuseTableM2 = le32_to_cpu(profile_v4_2->acg_avfsgb_fuse_table_m2); param->ulAcgGbFuseTableB = le32_to_cpu(profile_v4_2->acg_avfsgb_fuse_table_b); param->ucAcgEnableGbVdroopTable = le32_to_cpu(profile_v4_2->enable_acg_gb_vdroop_table); param->ucAcgEnableGbFuseTable = le32_to_cpu(profile_v4_2->enable_acg_gb_fuse_table); } else { pr_info("Invalid VBIOS AVFS ProfilingInfo Revision!\n"); return -EINVAL; } return 0; } int pp_atomfwctrl_get_gpio_information(struct pp_hwmgr *hwmgr, struct pp_atomfwctrl_gpio_parameters *param) { struct atom_smu_info_v3_1 *info; uint16_t idx; idx = GetIndexIntoMasterDataTable(smu_info); info = (struct atom_smu_info_v3_1 *) cgs_atom_get_data_table(hwmgr->device, idx, NULL, NULL, NULL); if (!info) { pr_info("Error retrieving BIOS smu_info Table Address!"); return -1; } param->ucAcDcGpio = info->ac_dc_gpio_bit; param->ucAcDcPolarity = info->ac_dc_polarity; param->ucVR0HotGpio = info->vr0hot_gpio_bit; param->ucVR0HotPolarity = info->vr0hot_polarity; param->ucVR1HotGpio = info->vr1hot_gpio_bit; param->ucVR1HotPolarity = info->vr1hot_polarity; param->ucFwCtfGpio = info->fw_ctf_gpio_bit; param->ucFwCtfPolarity = info->fw_ctf_polarity; return 0; } int pp_atomfwctrl__get_clk_information_by_clkid(struct pp_hwmgr *hwmgr, BIOS_CLKID id, uint32_t *frequency) { struct atom_get_smu_clock_info_parameters_v3_1 parameters; struct atom_get_smu_clock_info_output_parameters_v3_1 *output; uint32_t ix; parameters.clk_id = id; parameters.command = GET_SMU_CLOCK_INFO_V3_1_GET_CLOCK_FREQ; ix = GetIndexIntoMasterCmdTable(getsmuclockinfo); if (!cgs_atom_exec_cmd_table(hwmgr->device, ix, ¶meters)) { output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)¶meters; *frequency = output->atom_smu_outputclkfreq.smu_clock_freq_hz / 10000; } else { pr_info("Error execute_table getsmuclockinfo!"); return -1; } return 0; } int pp_atomfwctrl_get_vbios_bootup_values(struct pp_hwmgr *hwmgr, struct pp_atomfwctrl_bios_boot_up_values *boot_values) { struct atom_firmware_info_v3_1 *info = NULL; uint16_t ix; uint32_t frequency = 0; ix = GetIndexIntoMasterDataTable(firmwareinfo); info = (struct atom_firmware_info_v3_1 *) cgs_atom_get_data_table(hwmgr->device, ix, NULL, NULL, NULL); if (!info) { pr_info("Error retrieving BIOS firmwareinfo!"); return -EINVAL; } boot_values->ulRevision = info->firmware_revision; boot_values->ulGfxClk = info->bootup_sclk_in10khz; boot_values->ulUClk = info->bootup_mclk_in10khz; boot_values->usVddc = info->bootup_vddc_mv; boot_values->usVddci = info->bootup_vddci_mv; boot_values->usMvddc = info->bootup_mvddc_mv; boot_values->usVddGfx = info->bootup_vddgfx_mv; boot_values->ucCoolingID = info->coolingsolution_id; boot_values->ulSocClk = 0; boot_values->ulDCEFClk = 0; if (!pp_atomfwctrl__get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_SOCCLK_ID, &frequency)) boot_values->ulSocClk = frequency; if (!pp_atomfwctrl__get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_DCEFCLK_ID, &frequency)) boot_values->ulDCEFClk = frequency; return 0; } int pp_atomfwctrl_get_smc_dpm_information(struct pp_hwmgr *hwmgr, struct pp_atomfwctrl_smc_dpm_parameters *param) { struct atom_smc_dpm_info_v4_1 *info; uint16_t ix; ix = GetIndexIntoMasterDataTable(smc_dpm_info); info = (struct atom_smc_dpm_info_v4_1 *) cgs_atom_get_data_table(hwmgr->device, ix, NULL, NULL, NULL); if (!info) { pr_info("Error retrieving BIOS Table Address!"); return -EINVAL; } param->liquid1_i2c_address = info->liquid1_i2c_address; param->liquid2_i2c_address = info->liquid2_i2c_address; param->vr_i2c_address = info->vr_i2c_address; param->plx_i2c_address = info->plx_i2c_address; param->liquid_i2c_linescl = info->liquid_i2c_linescl; param->liquid_i2c_linesda = info->liquid_i2c_linesda; param->vr_i2c_linescl = info->vr_i2c_linescl; param->vr_i2c_linesda = info->vr_i2c_linesda; param->plx_i2c_linescl = info->plx_i2c_linescl; param->plx_i2c_linesda = info->plx_i2c_linesda; param->vrsensorpresent = info->vrsensorpresent; param->liquidsensorpresent = info->liquidsensorpresent; param->maxvoltagestepgfx = info->maxvoltagestepgfx; param->maxvoltagestepsoc = info->maxvoltagestepsoc; param->vddgfxvrmapping = info->vddgfxvrmapping; param->vddsocvrmapping = info->vddsocvrmapping; param->vddmem0vrmapping = info->vddmem0vrmapping; param->vddmem1vrmapping = info->vddmem1vrmapping; param->gfxulvphasesheddingmask = info->gfxulvphasesheddingmask; param->soculvphasesheddingmask = info->soculvphasesheddingmask; param->gfxmaxcurrent = info->gfxmaxcurrent; param->gfxoffset = info->gfxoffset; param->padding_telemetrygfx = info->padding_telemetrygfx; param->socmaxcurrent = info->socmaxcurrent; param->socoffset = info->socoffset; param->padding_telemetrysoc = info->padding_telemetrysoc; param->mem0maxcurrent = info->mem0maxcurrent; param->mem0offset = info->mem0offset; param->padding_telemetrymem0 = info->padding_telemetrymem0; param->mem1maxcurrent = info->mem1maxcurrent; param->mem1offset = info->mem1offset; param->padding_telemetrymem1 = info->padding_telemetrymem1; param->acdcgpio = info->acdcgpio; param->acdcpolarity = info->acdcpolarity; param->vr0hotgpio = info->vr0hotgpio; param->vr0hotpolarity = info->vr0hotpolarity; param->vr1hotgpio = info->vr1hotgpio; param->vr1hotpolarity = info->vr1hotpolarity; param->padding1 = info->padding1; param->padding2 = info->padding2; param->ledpin0 = info->ledpin0; param->ledpin1 = info->ledpin1; param->ledpin2 = info->ledpin2; param->gfxclkspreadenabled = info->gfxclkspreadenabled; param->gfxclkspreadpercent = info->gfxclkspreadpercent; param->gfxclkspreadfreq = info->gfxclkspreadfreq; param->uclkspreadenabled = info->uclkspreadenabled; param->uclkspreadpercent = info->uclkspreadpercent; param->uclkspreadfreq = info->uclkspreadfreq; param->socclkspreadenabled = info->socclkspreadenabled; param->socclkspreadpercent = info->socclkspreadpercent; param->socclkspreadfreq = info->socclkspreadfreq; return 0; }