|
@@ -978,6 +978,48 @@ int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
|
|
|
return -EINVAL;
|
|
|
|
|
|
switch (crev) {
|
|
|
+ case 2:
|
|
|
+ case 3:
|
|
|
+ case 5:
|
|
|
+ /* r6xx, r7xx, evergreen, ni, si.
|
|
|
+ * TODO: add support for asic_type <= CHIP_RV770*/
|
|
|
+ if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {
|
|
|
+ args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
|
|
|
+
|
|
|
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
|
|
|
+
|
|
|
+ dividers->post_div = args.v3.ucPostDiv;
|
|
|
+ dividers->enable_post_div = (args.v3.ucCntlFlag &
|
|
|
+ ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
|
|
|
+ dividers->enable_dithen = (args.v3.ucCntlFlag &
|
|
|
+ ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
|
|
|
+ dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
|
|
|
+ dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
|
|
|
+ dividers->ref_div = args.v3.ucRefDiv;
|
|
|
+ dividers->vco_mode = (args.v3.ucCntlFlag &
|
|
|
+ ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
|
|
|
+ } else {
|
|
|
+ /* for SI we use ComputeMemoryClockParam for memory plls */
|
|
|
+ if (adev->asic_type >= CHIP_TAHITI)
|
|
|
+ return -EINVAL;
|
|
|
+ args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
|
|
|
+ if (strobe_mode)
|
|
|
+ args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
|
|
|
+
|
|
|
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
|
|
|
+
|
|
|
+ dividers->post_div = args.v5.ucPostDiv;
|
|
|
+ dividers->enable_post_div = (args.v5.ucCntlFlag &
|
|
|
+ ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
|
|
|
+ dividers->enable_dithen = (args.v5.ucCntlFlag &
|
|
|
+ ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
|
|
|
+ dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv);
|
|
|
+ dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac);
|
|
|
+ dividers->ref_div = args.v5.ucRefDiv;
|
|
|
+ dividers->vco_mode = (args.v5.ucCntlFlag &
|
|
|
+ ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
|
|
|
+ }
|
|
|
+ break;
|
|
|
case 4:
|
|
|
/* fusion */
|
|
|
args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */
|
|
@@ -1122,6 +1164,32 @@ void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev,
|
|
|
amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
|
|
|
}
|
|
|
|
|
|
+void amdgpu_atombios_get_default_voltages(struct amdgpu_device *adev,
|
|
|
+ u16 *vddc, u16 *vddci, u16 *mvdd)
|
|
|
+{
|
|
|
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
|
|
|
+ int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
|
|
|
+ u8 frev, crev;
|
|
|
+ u16 data_offset;
|
|
|
+ union firmware_info *firmware_info;
|
|
|
+
|
|
|
+ *vddc = 0;
|
|
|
+ *vddci = 0;
|
|
|
+ *mvdd = 0;
|
|
|
+
|
|
|
+ if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
|
|
|
+ &frev, &crev, &data_offset)) {
|
|
|
+ firmware_info =
|
|
|
+ (union firmware_info *)(mode_info->atom_context->bios +
|
|
|
+ data_offset);
|
|
|
+ *vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
|
|
|
+ if ((frev == 2) && (crev >= 2)) {
|
|
|
+ *vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);
|
|
|
+ *mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
union set_voltage {
|
|
|
struct _SET_VOLTAGE_PS_ALLOCATION alloc;
|
|
|
struct _SET_VOLTAGE_PARAMETERS v1;
|
|
@@ -1129,6 +1197,52 @@ union set_voltage {
|
|
|
struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;
|
|
|
};
|
|
|
|
|
|
+int amdgpu_atombios_get_max_vddc(struct amdgpu_device *adev, u8 voltage_type,
|
|
|
+ u16 voltage_id, u16 *voltage)
|
|
|
+{
|
|
|
+ union set_voltage args;
|
|
|
+ int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
|
|
|
+ u8 frev, crev;
|
|
|
+
|
|
|
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ switch (crev) {
|
|
|
+ case 1:
|
|
|
+ return -EINVAL;
|
|
|
+ case 2:
|
|
|
+ args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;
|
|
|
+ args.v2.ucVoltageMode = 0;
|
|
|
+ args.v2.usVoltageLevel = 0;
|
|
|
+
|
|
|
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
|
|
|
+
|
|
|
+ *voltage = le16_to_cpu(args.v2.usVoltageLevel);
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ args.v3.ucVoltageType = voltage_type;
|
|
|
+ args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;
|
|
|
+ args.v3.usVoltageLevel = cpu_to_le16(voltage_id);
|
|
|
+
|
|
|
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
|
|
|
+
|
|
|
+ *voltage = le16_to_cpu(args.v3.usVoltageLevel);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int amdgpu_atombios_get_leakage_vddc_based_on_leakage_idx(struct amdgpu_device *adev,
|
|
|
+ u16 *voltage,
|
|
|
+ u16 leakage_idx)
|
|
|
+{
|
|
|
+ return amdgpu_atombios_get_max_vddc(adev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage);
|
|
|
+}
|
|
|
+
|
|
|
void amdgpu_atombios_set_voltage(struct amdgpu_device *adev,
|
|
|
u16 voltage_level,
|
|
|
u8 voltage_type)
|
|
@@ -1349,6 +1463,50 @@ static ATOM_VOLTAGE_OBJECT_V3 *amdgpu_atombios_lookup_voltage_object_v3(ATOM_VOL
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+int amdgpu_atombios_get_svi2_info(struct amdgpu_device *adev,
|
|
|
+ u8 voltage_type,
|
|
|
+ u8 *svd_gpio_id, u8 *svc_gpio_id)
|
|
|
+{
|
|
|
+ int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
|
|
|
+ u8 frev, crev;
|
|
|
+ u16 data_offset, size;
|
|
|
+ union voltage_object_info *voltage_info;
|
|
|
+ union voltage_object *voltage_object = NULL;
|
|
|
+
|
|
|
+ if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,
|
|
|
+ &frev, &crev, &data_offset)) {
|
|
|
+ voltage_info = (union voltage_object_info *)
|
|
|
+ (adev->mode_info.atom_context->bios + data_offset);
|
|
|
+
|
|
|
+ switch (frev) {
|
|
|
+ case 3:
|
|
|
+ switch (crev) {
|
|
|
+ case 1:
|
|
|
+ voltage_object = (union voltage_object *)
|
|
|
+ amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,
|
|
|
+ voltage_type,
|
|
|
+ VOLTAGE_OBJ_SVID2);
|
|
|
+ if (voltage_object) {
|
|
|
+ *svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId;
|
|
|
+ *svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId;
|
|
|
+ } else {
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ DRM_ERROR("unknown voltage object table\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ DRM_ERROR("unknown voltage object table\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
bool
|
|
|
amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev,
|
|
|
u8 voltage_type, u8 voltage_mode)
|