162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
662306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
762306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
862306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
962306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
1062306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1362306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1862306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1962306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2062306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2162306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Authors: Dave Airlie
2462306a36Sopenharmony_ci *          Alex Deucher
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <linux/pci.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <drm/drm_device.h>
3062306a36Sopenharmony_ci#include <drm/radeon_drm.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include "radeon.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include "atom.h"
3562306a36Sopenharmony_ci#include "atom-bits.h"
3662306a36Sopenharmony_ci#include "radeon_asic.h"
3762306a36Sopenharmony_ci#include "radeon_atombios.h"
3862306a36Sopenharmony_ci#include "radeon_legacy_encoders.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciunion atom_supported_devices {
4162306a36Sopenharmony_ci	struct _ATOM_SUPPORTED_DEVICES_INFO info;
4262306a36Sopenharmony_ci	struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
4362306a36Sopenharmony_ci	struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1;
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic void radeon_lookup_i2c_gpio_quirks(struct radeon_device *rdev,
4762306a36Sopenharmony_ci					  ATOM_GPIO_I2C_ASSIGMENT *gpio,
4862306a36Sopenharmony_ci					  u8 index)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	/* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */
5162306a36Sopenharmony_ci	if ((rdev->family == CHIP_R420) ||
5262306a36Sopenharmony_ci	    (rdev->family == CHIP_R423) ||
5362306a36Sopenharmony_ci	    (rdev->family == CHIP_RV410)) {
5462306a36Sopenharmony_ci		if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) ||
5562306a36Sopenharmony_ci		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) ||
5662306a36Sopenharmony_ci		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) {
5762306a36Sopenharmony_ci			gpio->ucClkMaskShift = 0x19;
5862306a36Sopenharmony_ci			gpio->ucDataMaskShift = 0x18;
5962306a36Sopenharmony_ci		}
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* some evergreen boards have bad data for this entry */
6362306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
6462306a36Sopenharmony_ci		if ((index == 7) &&
6562306a36Sopenharmony_ci		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) &&
6662306a36Sopenharmony_ci		    (gpio->sucI2cId.ucAccess == 0)) {
6762306a36Sopenharmony_ci			gpio->sucI2cId.ucAccess = 0x97;
6862306a36Sopenharmony_ci			gpio->ucDataMaskShift = 8;
6962306a36Sopenharmony_ci			gpio->ucDataEnShift = 8;
7062306a36Sopenharmony_ci			gpio->ucDataY_Shift = 8;
7162306a36Sopenharmony_ci			gpio->ucDataA_Shift = 8;
7262306a36Sopenharmony_ci		}
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* some DCE3 boards have bad data for this entry */
7662306a36Sopenharmony_ci	if (ASIC_IS_DCE3(rdev)) {
7762306a36Sopenharmony_ci		if ((index == 4) &&
7862306a36Sopenharmony_ci		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) &&
7962306a36Sopenharmony_ci		    (gpio->sucI2cId.ucAccess == 0x94))
8062306a36Sopenharmony_ci			gpio->sucI2cId.ucAccess = 0x14;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic struct radeon_i2c_bus_rec radeon_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct radeon_i2c_bus_rec i2c;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
9162306a36Sopenharmony_ci	i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
9262306a36Sopenharmony_ci	i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
9362306a36Sopenharmony_ci	i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
9462306a36Sopenharmony_ci	i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
9562306a36Sopenharmony_ci	i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
9662306a36Sopenharmony_ci	i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
9762306a36Sopenharmony_ci	i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
9862306a36Sopenharmony_ci	i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
9962306a36Sopenharmony_ci	i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
10062306a36Sopenharmony_ci	i2c.en_clk_mask = (1 << gpio->ucClkEnShift);
10162306a36Sopenharmony_ci	i2c.en_data_mask = (1 << gpio->ucDataEnShift);
10262306a36Sopenharmony_ci	i2c.y_clk_mask = (1 << gpio->ucClkY_Shift);
10362306a36Sopenharmony_ci	i2c.y_data_mask = (1 << gpio->ucDataY_Shift);
10462306a36Sopenharmony_ci	i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
10562306a36Sopenharmony_ci	i2c.a_data_mask = (1 << gpio->ucDataA_Shift);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (gpio->sucI2cId.sbfAccess.bfHW_Capable)
10862306a36Sopenharmony_ci		i2c.hw_capable = true;
10962306a36Sopenharmony_ci	else
11062306a36Sopenharmony_ci		i2c.hw_capable = false;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (gpio->sucI2cId.ucAccess == 0xa0)
11362306a36Sopenharmony_ci		i2c.mm_i2c = true;
11462306a36Sopenharmony_ci	else
11562306a36Sopenharmony_ci		i2c.mm_i2c = false;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	i2c.i2c_id = gpio->sucI2cId.ucAccess;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (i2c.mask_clk_reg)
12062306a36Sopenharmony_ci		i2c.valid = true;
12162306a36Sopenharmony_ci	else
12262306a36Sopenharmony_ci		i2c.valid = false;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return i2c;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rdev,
12862306a36Sopenharmony_ci							       uint8_t id)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct atom_context *ctx = rdev->mode_info.atom_context;
13162306a36Sopenharmony_ci	ATOM_GPIO_I2C_ASSIGMENT *gpio;
13262306a36Sopenharmony_ci	struct radeon_i2c_bus_rec i2c;
13362306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
13462306a36Sopenharmony_ci	struct _ATOM_GPIO_I2C_INFO *i2c_info;
13562306a36Sopenharmony_ci	uint16_t data_offset, size;
13662306a36Sopenharmony_ci	int i, num_indices;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
13962306a36Sopenharmony_ci	i2c.valid = false;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
14262306a36Sopenharmony_ci		i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
14562306a36Sopenharmony_ci			sizeof(ATOM_GPIO_I2C_ASSIGMENT);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		gpio = &i2c_info->asGPIO_Info[0];
14862306a36Sopenharmony_ci		for (i = 0; i < num_indices; i++) {
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci			radeon_lookup_i2c_gpio_quirks(rdev, gpio, i);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci			if (gpio->sucI2cId.ucAccess == id) {
15362306a36Sopenharmony_ci				i2c = radeon_get_bus_rec_for_i2c_gpio(gpio);
15462306a36Sopenharmony_ci				break;
15562306a36Sopenharmony_ci			}
15662306a36Sopenharmony_ci			gpio = (ATOM_GPIO_I2C_ASSIGMENT *)
15762306a36Sopenharmony_ci				((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT));
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	return i2c;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_civoid radeon_atombios_i2c_init(struct radeon_device *rdev)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct atom_context *ctx = rdev->mode_info.atom_context;
16762306a36Sopenharmony_ci	ATOM_GPIO_I2C_ASSIGMENT *gpio;
16862306a36Sopenharmony_ci	struct radeon_i2c_bus_rec i2c;
16962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
17062306a36Sopenharmony_ci	struct _ATOM_GPIO_I2C_INFO *i2c_info;
17162306a36Sopenharmony_ci	uint16_t data_offset, size;
17262306a36Sopenharmony_ci	int i, num_indices;
17362306a36Sopenharmony_ci	char stmp[32];
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
17662306a36Sopenharmony_ci		i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
17962306a36Sopenharmony_ci			sizeof(ATOM_GPIO_I2C_ASSIGMENT);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		gpio = &i2c_info->asGPIO_Info[0];
18262306a36Sopenharmony_ci		for (i = 0; i < num_indices; i++) {
18362306a36Sopenharmony_ci			radeon_lookup_i2c_gpio_quirks(rdev, gpio, i);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci			i2c = radeon_get_bus_rec_for_i2c_gpio(gpio);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci			if (i2c.valid) {
18862306a36Sopenharmony_ci				sprintf(stmp, "0x%x", i2c.i2c_id);
18962306a36Sopenharmony_ci				rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp);
19062306a36Sopenharmony_ci			}
19162306a36Sopenharmony_ci			gpio = (ATOM_GPIO_I2C_ASSIGMENT *)
19262306a36Sopenharmony_ci				((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT));
19362306a36Sopenharmony_ci		}
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistruct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev,
19862306a36Sopenharmony_ci						   u8 id)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	struct atom_context *ctx = rdev->mode_info.atom_context;
20162306a36Sopenharmony_ci	struct radeon_gpio_rec gpio;
20262306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT);
20362306a36Sopenharmony_ci	struct _ATOM_GPIO_PIN_LUT *gpio_info;
20462306a36Sopenharmony_ci	ATOM_GPIO_PIN_ASSIGNMENT *pin;
20562306a36Sopenharmony_ci	u16 data_offset, size;
20662306a36Sopenharmony_ci	int i, num_indices;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	memset(&gpio, 0, sizeof(struct radeon_gpio_rec));
20962306a36Sopenharmony_ci	gpio.valid = false;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
21262306a36Sopenharmony_ci		gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
21562306a36Sopenharmony_ci			sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		pin = gpio_info->asGPIO_Pin;
21862306a36Sopenharmony_ci		for (i = 0; i < num_indices; i++) {
21962306a36Sopenharmony_ci			if (id == pin->ucGPIO_ID) {
22062306a36Sopenharmony_ci				gpio.id = pin->ucGPIO_ID;
22162306a36Sopenharmony_ci				gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4;
22262306a36Sopenharmony_ci				gpio.shift = pin->ucGpioPinBitShift;
22362306a36Sopenharmony_ci				gpio.mask = (1 << pin->ucGpioPinBitShift);
22462306a36Sopenharmony_ci				gpio.valid = true;
22562306a36Sopenharmony_ci				break;
22662306a36Sopenharmony_ci			}
22762306a36Sopenharmony_ci			pin = (ATOM_GPIO_PIN_ASSIGNMENT *)
22862306a36Sopenharmony_ci				((u8 *)pin + sizeof(ATOM_GPIO_PIN_ASSIGNMENT));
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return gpio;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device *rdev,
23662306a36Sopenharmony_ci							    struct radeon_gpio_rec *gpio)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct radeon_hpd hpd;
23962306a36Sopenharmony_ci	u32 reg;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	memset(&hpd, 0, sizeof(struct radeon_hpd));
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (ASIC_IS_DCE6(rdev))
24462306a36Sopenharmony_ci		reg = SI_DC_GPIO_HPD_A;
24562306a36Sopenharmony_ci	else if (ASIC_IS_DCE4(rdev))
24662306a36Sopenharmony_ci		reg = EVERGREEN_DC_GPIO_HPD_A;
24762306a36Sopenharmony_ci	else
24862306a36Sopenharmony_ci		reg = AVIVO_DC_GPIO_HPD_A;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	hpd.gpio = *gpio;
25162306a36Sopenharmony_ci	if (gpio->reg == reg) {
25262306a36Sopenharmony_ci		switch(gpio->mask) {
25362306a36Sopenharmony_ci		case (1 << 0):
25462306a36Sopenharmony_ci			hpd.hpd = RADEON_HPD_1;
25562306a36Sopenharmony_ci			break;
25662306a36Sopenharmony_ci		case (1 << 8):
25762306a36Sopenharmony_ci			hpd.hpd = RADEON_HPD_2;
25862306a36Sopenharmony_ci			break;
25962306a36Sopenharmony_ci		case (1 << 16):
26062306a36Sopenharmony_ci			hpd.hpd = RADEON_HPD_3;
26162306a36Sopenharmony_ci			break;
26262306a36Sopenharmony_ci		case (1 << 24):
26362306a36Sopenharmony_ci			hpd.hpd = RADEON_HPD_4;
26462306a36Sopenharmony_ci			break;
26562306a36Sopenharmony_ci		case (1 << 26):
26662306a36Sopenharmony_ci			hpd.hpd = RADEON_HPD_5;
26762306a36Sopenharmony_ci			break;
26862306a36Sopenharmony_ci		case (1 << 28):
26962306a36Sopenharmony_ci			hpd.hpd = RADEON_HPD_6;
27062306a36Sopenharmony_ci			break;
27162306a36Sopenharmony_ci		default:
27262306a36Sopenharmony_ci			hpd.hpd = RADEON_HPD_NONE;
27362306a36Sopenharmony_ci			break;
27462306a36Sopenharmony_ci		}
27562306a36Sopenharmony_ci	} else
27662306a36Sopenharmony_ci		hpd.hpd = RADEON_HPD_NONE;
27762306a36Sopenharmony_ci	return hpd;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic bool radeon_atom_apply_quirks(struct drm_device *dev,
28162306a36Sopenharmony_ci				     uint32_t supported_device,
28262306a36Sopenharmony_ci				     int *connector_type,
28362306a36Sopenharmony_ci				     struct radeon_i2c_bus_rec *i2c_bus,
28462306a36Sopenharmony_ci				     uint16_t *line_mux,
28562306a36Sopenharmony_ci				     struct radeon_hpd *hpd)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev->dev);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* Asus M2A-VM HDMI board lists the DVI port as HDMI */
29062306a36Sopenharmony_ci	if ((pdev->device == 0x791e) &&
29162306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1043) &&
29262306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x826d)) {
29362306a36Sopenharmony_ci		if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
29462306a36Sopenharmony_ci		    (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
29562306a36Sopenharmony_ci			*connector_type = DRM_MODE_CONNECTOR_DVID;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* Asrock RS600 board lists the DVI port as HDMI */
29962306a36Sopenharmony_ci	if ((pdev->device == 0x7941) &&
30062306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1849) &&
30162306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x7941)) {
30262306a36Sopenharmony_ci		if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
30362306a36Sopenharmony_ci		    (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
30462306a36Sopenharmony_ci			*connector_type = DRM_MODE_CONNECTOR_DVID;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* MSI K9A2GM V2/V3 board has no HDMI or DVI */
30862306a36Sopenharmony_ci	if ((pdev->device == 0x796e) &&
30962306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1462) &&
31062306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x7302)) {
31162306a36Sopenharmony_ci		if ((supported_device == ATOM_DEVICE_DFP2_SUPPORT) ||
31262306a36Sopenharmony_ci		    (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
31362306a36Sopenharmony_ci			return false;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
31762306a36Sopenharmony_ci	if ((pdev->device == 0x7941) &&
31862306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x147b) &&
31962306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x2412)) {
32062306a36Sopenharmony_ci		if (*connector_type == DRM_MODE_CONNECTOR_DVII)
32162306a36Sopenharmony_ci			return false;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Falcon NW laptop lists vga ddc line for LVDS */
32562306a36Sopenharmony_ci	if ((pdev->device == 0x5653) &&
32662306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1462) &&
32762306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x0291)) {
32862306a36Sopenharmony_ci		if (*connector_type == DRM_MODE_CONNECTOR_LVDS) {
32962306a36Sopenharmony_ci			i2c_bus->valid = false;
33062306a36Sopenharmony_ci			*line_mux = 53;
33162306a36Sopenharmony_ci		}
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* HIS X1300 is DVI+VGA, not DVI+DVI */
33562306a36Sopenharmony_ci	if ((pdev->device == 0x7146) &&
33662306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x17af) &&
33762306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x2058)) {
33862306a36Sopenharmony_ci		if (supported_device == ATOM_DEVICE_DFP1_SUPPORT)
33962306a36Sopenharmony_ci			return false;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Gigabyte X1300 is DVI+VGA, not DVI+DVI */
34362306a36Sopenharmony_ci	if ((pdev->device == 0x7142) &&
34462306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1458) &&
34562306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x2134)) {
34662306a36Sopenharmony_ci		if (supported_device == ATOM_DEVICE_DFP1_SUPPORT)
34762306a36Sopenharmony_ci			return false;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Funky macbooks */
35262306a36Sopenharmony_ci	if ((pdev->device == 0x71C5) &&
35362306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x106b) &&
35462306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x0080)) {
35562306a36Sopenharmony_ci		if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) ||
35662306a36Sopenharmony_ci		    (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
35762306a36Sopenharmony_ci			return false;
35862306a36Sopenharmony_ci		if (supported_device == ATOM_DEVICE_CRT2_SUPPORT)
35962306a36Sopenharmony_ci			*line_mux = 0x90;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* mac rv630, rv730, others */
36362306a36Sopenharmony_ci	if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) &&
36462306a36Sopenharmony_ci	    (*connector_type == DRM_MODE_CONNECTOR_DVII)) {
36562306a36Sopenharmony_ci		*connector_type = DRM_MODE_CONNECTOR_9PinDIN;
36662306a36Sopenharmony_ci		*line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/* ASUS HD 3600 XT board lists the DVI port as HDMI */
37062306a36Sopenharmony_ci	if ((pdev->device == 0x9598) &&
37162306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1043) &&
37262306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x01da)) {
37362306a36Sopenharmony_ci		if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
37462306a36Sopenharmony_ci			*connector_type = DRM_MODE_CONNECTOR_DVII;
37562306a36Sopenharmony_ci		}
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* ASUS HD 3600 board lists the DVI port as HDMI */
37962306a36Sopenharmony_ci	if ((pdev->device == 0x9598) &&
38062306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1043) &&
38162306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x01e4)) {
38262306a36Sopenharmony_ci		if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
38362306a36Sopenharmony_ci			*connector_type = DRM_MODE_CONNECTOR_DVII;
38462306a36Sopenharmony_ci		}
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* ASUS HD 3450 board lists the DVI port as HDMI */
38862306a36Sopenharmony_ci	if ((pdev->device == 0x95C5) &&
38962306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1043) &&
39062306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x01e2)) {
39162306a36Sopenharmony_ci		if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
39262306a36Sopenharmony_ci			*connector_type = DRM_MODE_CONNECTOR_DVII;
39362306a36Sopenharmony_ci		}
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* some BIOSes seem to report DAC on HDMI - usually this is a board with
39762306a36Sopenharmony_ci	 * HDMI + VGA reporting as HDMI
39862306a36Sopenharmony_ci	 */
39962306a36Sopenharmony_ci	if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
40062306a36Sopenharmony_ci		if (supported_device & (ATOM_DEVICE_CRT_SUPPORT)) {
40162306a36Sopenharmony_ci			*connector_type = DRM_MODE_CONNECTOR_VGA;
40262306a36Sopenharmony_ci			*line_mux = 0;
40362306a36Sopenharmony_ci		}
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* Acer laptop (Acer TravelMate 5730/5730G) has an HDMI port
40762306a36Sopenharmony_ci	 * on the laptop and a DVI port on the docking station and
40862306a36Sopenharmony_ci	 * both share the same encoder, hpd pin, and ddc line.
40962306a36Sopenharmony_ci	 * So while the bios table is technically correct,
41062306a36Sopenharmony_ci	 * we drop the DVI port here since xrandr has no concept of
41162306a36Sopenharmony_ci	 * encoders and will try and drive both connectors
41262306a36Sopenharmony_ci	 * with different crtcs which isn't possible on the hardware
41362306a36Sopenharmony_ci	 * side and leaves no crtcs for LVDS or VGA.
41462306a36Sopenharmony_ci	 */
41562306a36Sopenharmony_ci	if (((pdev->device == 0x95c4) || (pdev->device == 0x9591)) &&
41662306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1025) &&
41762306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x013c)) {
41862306a36Sopenharmony_ci		if ((*connector_type == DRM_MODE_CONNECTOR_DVII) &&
41962306a36Sopenharmony_ci		    (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) {
42062306a36Sopenharmony_ci			/* actually it's a DVI-D port not DVI-I */
42162306a36Sopenharmony_ci			*connector_type = DRM_MODE_CONNECTOR_DVID;
42262306a36Sopenharmony_ci			return false;
42362306a36Sopenharmony_ci		}
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* XFX Pine Group device rv730 reports no VGA DDC lines
42762306a36Sopenharmony_ci	 * even though they are wired up to record 0x93
42862306a36Sopenharmony_ci	 */
42962306a36Sopenharmony_ci	if ((pdev->device == 0x9498) &&
43062306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1682) &&
43162306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x2452) &&
43262306a36Sopenharmony_ci	    (i2c_bus->valid == false) &&
43362306a36Sopenharmony_ci	    !(supported_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))) {
43462306a36Sopenharmony_ci		struct radeon_device *rdev = dev->dev_private;
43562306a36Sopenharmony_ci		*i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93);
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */
43962306a36Sopenharmony_ci	if (((pdev->device == 0x9802) ||
44062306a36Sopenharmony_ci	     (pdev->device == 0x9805) ||
44162306a36Sopenharmony_ci	     (pdev->device == 0x9806)) &&
44262306a36Sopenharmony_ci	    (pdev->subsystem_vendor == 0x1734) &&
44362306a36Sopenharmony_ci	    (pdev->subsystem_device == 0x11bd)) {
44462306a36Sopenharmony_ci		if (*connector_type == DRM_MODE_CONNECTOR_VGA) {
44562306a36Sopenharmony_ci			*connector_type = DRM_MODE_CONNECTOR_DVII;
44662306a36Sopenharmony_ci			*line_mux = 0x3103;
44762306a36Sopenharmony_ci		} else if (*connector_type == DRM_MODE_CONNECTOR_DVID) {
44862306a36Sopenharmony_ci			*connector_type = DRM_MODE_CONNECTOR_DVII;
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	return true;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic const int supported_devices_connector_convert[] = {
45662306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
45762306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_VGA,
45862306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_DVII,
45962306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_DVID,
46062306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_DVIA,
46162306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_SVIDEO,
46262306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Composite,
46362306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_LVDS,
46462306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
46562306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
46662306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_HDMIA,
46762306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_HDMIB,
46862306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
46962306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
47062306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_9PinDIN,
47162306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_DisplayPort
47262306a36Sopenharmony_ci};
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic const uint16_t supported_devices_connector_object_id_convert[] = {
47562306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_NONE,
47662306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_VGA,
47762306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, /* not all boards support DL */
47862306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D, /* not all boards support DL */
47962306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_VGA, /* technically DVI-A */
48062306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_COMPOSITE,
48162306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_SVIDEO,
48262306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_LVDS,
48362306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_9PIN_DIN,
48462306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_9PIN_DIN,
48562306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_DISPLAYPORT,
48662306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_HDMI_TYPE_A,
48762306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_HDMI_TYPE_B,
48862306a36Sopenharmony_ci	CONNECTOR_OBJECT_ID_SVIDEO
48962306a36Sopenharmony_ci};
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic const int object_connector_convert[] = {
49262306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
49362306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_DVII,
49462306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_DVII,
49562306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_DVID,
49662306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_DVID,
49762306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_VGA,
49862306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Composite,
49962306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_SVIDEO,
50062306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
50162306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
50262306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_9PinDIN,
50362306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
50462306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_HDMIA,
50562306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_HDMIB,
50662306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_LVDS,
50762306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_9PinDIN,
50862306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
50962306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
51062306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown,
51162306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_DisplayPort,
51262306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_eDP,
51362306a36Sopenharmony_ci	DRM_MODE_CONNECTOR_Unknown
51462306a36Sopenharmony_ci};
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cibool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
51962306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
52062306a36Sopenharmony_ci	struct atom_context *ctx = mode_info->atom_context;
52162306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, Object_Header);
52262306a36Sopenharmony_ci	u16 size, data_offset;
52362306a36Sopenharmony_ci	u8 frev, crev;
52462306a36Sopenharmony_ci	ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
52562306a36Sopenharmony_ci	ATOM_ENCODER_OBJECT_TABLE *enc_obj;
52662306a36Sopenharmony_ci	ATOM_OBJECT_TABLE *router_obj;
52762306a36Sopenharmony_ci	ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
52862306a36Sopenharmony_ci	ATOM_OBJECT_HEADER *obj_header;
52962306a36Sopenharmony_ci	int i, j, k, path_size, device_support;
53062306a36Sopenharmony_ci	int connector_type;
53162306a36Sopenharmony_ci	u16 igp_lane_info, conn_id, connector_object_id;
53262306a36Sopenharmony_ci	struct radeon_i2c_bus_rec ddc_bus;
53362306a36Sopenharmony_ci	struct radeon_router router;
53462306a36Sopenharmony_ci	struct radeon_gpio_rec gpio;
53562306a36Sopenharmony_ci	struct radeon_hpd hpd;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))
53862306a36Sopenharmony_ci		return false;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (crev < 2)
54162306a36Sopenharmony_ci		return false;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
54462306a36Sopenharmony_ci	path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
54562306a36Sopenharmony_ci	    (ctx->bios + data_offset +
54662306a36Sopenharmony_ci	     le16_to_cpu(obj_header->usDisplayPathTableOffset));
54762306a36Sopenharmony_ci	con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
54862306a36Sopenharmony_ci	    (ctx->bios + data_offset +
54962306a36Sopenharmony_ci	     le16_to_cpu(obj_header->usConnectorObjectTableOffset));
55062306a36Sopenharmony_ci	enc_obj = (ATOM_ENCODER_OBJECT_TABLE *)
55162306a36Sopenharmony_ci	    (ctx->bios + data_offset +
55262306a36Sopenharmony_ci	     le16_to_cpu(obj_header->usEncoderObjectTableOffset));
55362306a36Sopenharmony_ci	router_obj = (ATOM_OBJECT_TABLE *)
55462306a36Sopenharmony_ci		(ctx->bios + data_offset +
55562306a36Sopenharmony_ci		 le16_to_cpu(obj_header->usRouterObjectTableOffset));
55662306a36Sopenharmony_ci	device_support = le16_to_cpu(obj_header->usDeviceSupport);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	path_size = 0;
55962306a36Sopenharmony_ci	for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
56062306a36Sopenharmony_ci		uint8_t *addr = (uint8_t *) path_obj->asDispPath;
56162306a36Sopenharmony_ci		ATOM_DISPLAY_OBJECT_PATH *path;
56262306a36Sopenharmony_ci		addr += path_size;
56362306a36Sopenharmony_ci		path = (ATOM_DISPLAY_OBJECT_PATH *) addr;
56462306a36Sopenharmony_ci		path_size += le16_to_cpu(path->usSize);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci		if (device_support & le16_to_cpu(path->usDeviceTag)) {
56762306a36Sopenharmony_ci			uint8_t con_obj_id, con_obj_num;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci			con_obj_id =
57062306a36Sopenharmony_ci			    (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK)
57162306a36Sopenharmony_ci			    >> OBJECT_ID_SHIFT;
57262306a36Sopenharmony_ci			con_obj_num =
57362306a36Sopenharmony_ci			    (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK)
57462306a36Sopenharmony_ci			    >> ENUM_ID_SHIFT;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci			/* TODO CV support */
57762306a36Sopenharmony_ci			if (le16_to_cpu(path->usDeviceTag) ==
57862306a36Sopenharmony_ci				ATOM_DEVICE_CV_SUPPORT)
57962306a36Sopenharmony_ci				continue;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci			/* IGP chips */
58262306a36Sopenharmony_ci			if ((rdev->flags & RADEON_IS_IGP) &&
58362306a36Sopenharmony_ci			    (con_obj_id ==
58462306a36Sopenharmony_ci			     CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
58562306a36Sopenharmony_ci				uint16_t igp_offset = 0;
58662306a36Sopenharmony_ci				ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci				index =
58962306a36Sopenharmony_ci				    GetIndexIntoMasterTable(DATA,
59062306a36Sopenharmony_ci							    IntegratedSystemInfo);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci				if (atom_parse_data_header(ctx, index, &size, &frev,
59362306a36Sopenharmony_ci							   &crev, &igp_offset)) {
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci					if (crev >= 2) {
59662306a36Sopenharmony_ci						igp_obj =
59762306a36Sopenharmony_ci							(ATOM_INTEGRATED_SYSTEM_INFO_V2
59862306a36Sopenharmony_ci							 *) (ctx->bios + igp_offset);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci						if (igp_obj) {
60162306a36Sopenharmony_ci							uint32_t slot_config, ct;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci							if (con_obj_num == 1)
60462306a36Sopenharmony_ci								slot_config =
60562306a36Sopenharmony_ci									igp_obj->
60662306a36Sopenharmony_ci									ulDDISlot1Config;
60762306a36Sopenharmony_ci							else
60862306a36Sopenharmony_ci								slot_config =
60962306a36Sopenharmony_ci									igp_obj->
61062306a36Sopenharmony_ci									ulDDISlot2Config;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci							ct = (slot_config >> 16) & 0xff;
61362306a36Sopenharmony_ci							connector_type =
61462306a36Sopenharmony_ci								object_connector_convert
61562306a36Sopenharmony_ci								[ct];
61662306a36Sopenharmony_ci							connector_object_id = ct;
61762306a36Sopenharmony_ci							igp_lane_info =
61862306a36Sopenharmony_ci								slot_config & 0xffff;
61962306a36Sopenharmony_ci						} else
62062306a36Sopenharmony_ci							continue;
62162306a36Sopenharmony_ci					} else
62262306a36Sopenharmony_ci						continue;
62362306a36Sopenharmony_ci				} else {
62462306a36Sopenharmony_ci					igp_lane_info = 0;
62562306a36Sopenharmony_ci					connector_type =
62662306a36Sopenharmony_ci						object_connector_convert[con_obj_id];
62762306a36Sopenharmony_ci					connector_object_id = con_obj_id;
62862306a36Sopenharmony_ci				}
62962306a36Sopenharmony_ci			} else {
63062306a36Sopenharmony_ci				igp_lane_info = 0;
63162306a36Sopenharmony_ci				connector_type =
63262306a36Sopenharmony_ci				    object_connector_convert[con_obj_id];
63362306a36Sopenharmony_ci				connector_object_id = con_obj_id;
63462306a36Sopenharmony_ci			}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci			if (connector_type == DRM_MODE_CONNECTOR_Unknown)
63762306a36Sopenharmony_ci				continue;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci			router.ddc_valid = false;
64062306a36Sopenharmony_ci			router.cd_valid = false;
64162306a36Sopenharmony_ci			for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
64262306a36Sopenharmony_ci				uint8_t grph_obj_type =
64362306a36Sopenharmony_ci				    (le16_to_cpu(path->usGraphicObjIds[j]) &
64462306a36Sopenharmony_ci				     OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci				if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
64762306a36Sopenharmony_ci					for (k = 0; k < enc_obj->ucNumberOfObjects; k++) {
64862306a36Sopenharmony_ci						u16 encoder_obj = le16_to_cpu(enc_obj->asObjects[k].usObjectID);
64962306a36Sopenharmony_ci						if (le16_to_cpu(path->usGraphicObjIds[j]) == encoder_obj) {
65062306a36Sopenharmony_ci							ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
65162306a36Sopenharmony_ci								(ctx->bios + data_offset +
65262306a36Sopenharmony_ci								 le16_to_cpu(enc_obj->asObjects[k].usRecordOffset));
65362306a36Sopenharmony_ci							ATOM_ENCODER_CAP_RECORD *cap_record;
65462306a36Sopenharmony_ci							u16 caps = 0;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci							while (record->ucRecordSize > 0 &&
65762306a36Sopenharmony_ci							       record->ucRecordType > 0 &&
65862306a36Sopenharmony_ci							       record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
65962306a36Sopenharmony_ci								switch (record->ucRecordType) {
66062306a36Sopenharmony_ci								case ATOM_ENCODER_CAP_RECORD_TYPE:
66162306a36Sopenharmony_ci									cap_record =(ATOM_ENCODER_CAP_RECORD *)
66262306a36Sopenharmony_ci										record;
66362306a36Sopenharmony_ci									caps = le16_to_cpu(cap_record->usEncoderCap);
66462306a36Sopenharmony_ci									break;
66562306a36Sopenharmony_ci								}
66662306a36Sopenharmony_ci								record = (ATOM_COMMON_RECORD_HEADER *)
66762306a36Sopenharmony_ci									((char *)record + record->ucRecordSize);
66862306a36Sopenharmony_ci							}
66962306a36Sopenharmony_ci							radeon_add_atom_encoder(dev,
67062306a36Sopenharmony_ci										encoder_obj,
67162306a36Sopenharmony_ci										le16_to_cpu
67262306a36Sopenharmony_ci										(path->
67362306a36Sopenharmony_ci										 usDeviceTag),
67462306a36Sopenharmony_ci										caps);
67562306a36Sopenharmony_ci						}
67662306a36Sopenharmony_ci					}
67762306a36Sopenharmony_ci				} else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
67862306a36Sopenharmony_ci					for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
67962306a36Sopenharmony_ci						u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID);
68062306a36Sopenharmony_ci						if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
68162306a36Sopenharmony_ci							ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
68262306a36Sopenharmony_ci								(ctx->bios + data_offset +
68362306a36Sopenharmony_ci								 le16_to_cpu(router_obj->asObjects[k].usRecordOffset));
68462306a36Sopenharmony_ci							ATOM_I2C_RECORD *i2c_record;
68562306a36Sopenharmony_ci							ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
68662306a36Sopenharmony_ci							ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
68762306a36Sopenharmony_ci							ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path;
68862306a36Sopenharmony_ci							ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
68962306a36Sopenharmony_ci								(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
69062306a36Sopenharmony_ci								(ctx->bios + data_offset +
69162306a36Sopenharmony_ci								 le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset));
69262306a36Sopenharmony_ci							u8 *num_dst_objs = (u8 *)
69362306a36Sopenharmony_ci								((u8 *)router_src_dst_table + 1 +
69462306a36Sopenharmony_ci								 (router_src_dst_table->ucNumberOfSrc * 2));
69562306a36Sopenharmony_ci							u16 *dst_objs = (u16 *)(num_dst_objs + 1);
69662306a36Sopenharmony_ci							int enum_id;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci							router.router_id = router_obj_id;
69962306a36Sopenharmony_ci							for (enum_id = 0; enum_id < (*num_dst_objs); enum_id++) {
70062306a36Sopenharmony_ci								if (le16_to_cpu(path->usConnObjectId) ==
70162306a36Sopenharmony_ci								    le16_to_cpu(dst_objs[enum_id]))
70262306a36Sopenharmony_ci									break;
70362306a36Sopenharmony_ci							}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci							while (record->ucRecordSize > 0 &&
70662306a36Sopenharmony_ci							       record->ucRecordType > 0 &&
70762306a36Sopenharmony_ci							       record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
70862306a36Sopenharmony_ci								switch (record->ucRecordType) {
70962306a36Sopenharmony_ci								case ATOM_I2C_RECORD_TYPE:
71062306a36Sopenharmony_ci									i2c_record =
71162306a36Sopenharmony_ci										(ATOM_I2C_RECORD *)
71262306a36Sopenharmony_ci										record;
71362306a36Sopenharmony_ci									i2c_config =
71462306a36Sopenharmony_ci										(ATOM_I2C_ID_CONFIG_ACCESS *)
71562306a36Sopenharmony_ci										&i2c_record->sucI2cId;
71662306a36Sopenharmony_ci									router.i2c_info =
71762306a36Sopenharmony_ci										radeon_lookup_i2c_gpio(rdev,
71862306a36Sopenharmony_ci												       i2c_config->
71962306a36Sopenharmony_ci												       ucAccess);
72062306a36Sopenharmony_ci									router.i2c_addr = i2c_record->ucI2CAddr >> 1;
72162306a36Sopenharmony_ci									break;
72262306a36Sopenharmony_ci								case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
72362306a36Sopenharmony_ci									ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
72462306a36Sopenharmony_ci										record;
72562306a36Sopenharmony_ci									router.ddc_valid = true;
72662306a36Sopenharmony_ci									router.ddc_mux_type = ddc_path->ucMuxType;
72762306a36Sopenharmony_ci									router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;
72862306a36Sopenharmony_ci									router.ddc_mux_state = ddc_path->ucMuxState[enum_id];
72962306a36Sopenharmony_ci									break;
73062306a36Sopenharmony_ci								case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
73162306a36Sopenharmony_ci									cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)
73262306a36Sopenharmony_ci										record;
73362306a36Sopenharmony_ci									router.cd_valid = true;
73462306a36Sopenharmony_ci									router.cd_mux_type = cd_path->ucMuxType;
73562306a36Sopenharmony_ci									router.cd_mux_control_pin = cd_path->ucMuxControlPin;
73662306a36Sopenharmony_ci									router.cd_mux_state = cd_path->ucMuxState[enum_id];
73762306a36Sopenharmony_ci									break;
73862306a36Sopenharmony_ci								}
73962306a36Sopenharmony_ci								record = (ATOM_COMMON_RECORD_HEADER *)
74062306a36Sopenharmony_ci									((char *)record + record->ucRecordSize);
74162306a36Sopenharmony_ci							}
74262306a36Sopenharmony_ci						}
74362306a36Sopenharmony_ci					}
74462306a36Sopenharmony_ci				}
74562306a36Sopenharmony_ci			}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci			/* look up gpio for ddc, hpd */
74862306a36Sopenharmony_ci			ddc_bus.valid = false;
74962306a36Sopenharmony_ci			hpd.hpd = RADEON_HPD_NONE;
75062306a36Sopenharmony_ci			if ((le16_to_cpu(path->usDeviceTag) &
75162306a36Sopenharmony_ci			     (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
75262306a36Sopenharmony_ci				for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
75362306a36Sopenharmony_ci					if (le16_to_cpu(path->usConnObjectId) ==
75462306a36Sopenharmony_ci					    le16_to_cpu(con_obj->asObjects[j].
75562306a36Sopenharmony_ci							usObjectID)) {
75662306a36Sopenharmony_ci						ATOM_COMMON_RECORD_HEADER
75762306a36Sopenharmony_ci						    *record =
75862306a36Sopenharmony_ci						    (ATOM_COMMON_RECORD_HEADER
75962306a36Sopenharmony_ci						     *)
76062306a36Sopenharmony_ci						    (ctx->bios + data_offset +
76162306a36Sopenharmony_ci						     le16_to_cpu(con_obj->
76262306a36Sopenharmony_ci								 asObjects[j].
76362306a36Sopenharmony_ci								 usRecordOffset));
76462306a36Sopenharmony_ci						ATOM_I2C_RECORD *i2c_record;
76562306a36Sopenharmony_ci						ATOM_HPD_INT_RECORD *hpd_record;
76662306a36Sopenharmony_ci						ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci						while (record->ucRecordSize > 0 &&
76962306a36Sopenharmony_ci						       record->ucRecordType > 0 &&
77062306a36Sopenharmony_ci						       record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
77162306a36Sopenharmony_ci							switch (record->ucRecordType) {
77262306a36Sopenharmony_ci							case ATOM_I2C_RECORD_TYPE:
77362306a36Sopenharmony_ci								i2c_record =
77462306a36Sopenharmony_ci								    (ATOM_I2C_RECORD *)
77562306a36Sopenharmony_ci									record;
77662306a36Sopenharmony_ci								i2c_config =
77762306a36Sopenharmony_ci									(ATOM_I2C_ID_CONFIG_ACCESS *)
77862306a36Sopenharmony_ci									&i2c_record->sucI2cId;
77962306a36Sopenharmony_ci								ddc_bus = radeon_lookup_i2c_gpio(rdev,
78062306a36Sopenharmony_ci												 i2c_config->
78162306a36Sopenharmony_ci												 ucAccess);
78262306a36Sopenharmony_ci								break;
78362306a36Sopenharmony_ci							case ATOM_HPD_INT_RECORD_TYPE:
78462306a36Sopenharmony_ci								hpd_record =
78562306a36Sopenharmony_ci									(ATOM_HPD_INT_RECORD *)
78662306a36Sopenharmony_ci									record;
78762306a36Sopenharmony_ci								gpio = radeon_atombios_lookup_gpio(rdev,
78862306a36Sopenharmony_ci											  hpd_record->ucHPDIntGPIOID);
78962306a36Sopenharmony_ci								hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
79062306a36Sopenharmony_ci								hpd.plugged_state = hpd_record->ucPlugged_PinState;
79162306a36Sopenharmony_ci								break;
79262306a36Sopenharmony_ci							}
79362306a36Sopenharmony_ci							record =
79462306a36Sopenharmony_ci							    (ATOM_COMMON_RECORD_HEADER
79562306a36Sopenharmony_ci							     *) ((char *)record
79662306a36Sopenharmony_ci								 +
79762306a36Sopenharmony_ci								 record->
79862306a36Sopenharmony_ci								 ucRecordSize);
79962306a36Sopenharmony_ci						}
80062306a36Sopenharmony_ci						break;
80162306a36Sopenharmony_ci					}
80262306a36Sopenharmony_ci				}
80362306a36Sopenharmony_ci			}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci			/* needed for aux chan transactions */
80662306a36Sopenharmony_ci			ddc_bus.hpd = hpd.hpd;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci			conn_id = le16_to_cpu(path->usConnObjectId);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci			if (!radeon_atom_apply_quirks
81162306a36Sopenharmony_ci			    (dev, le16_to_cpu(path->usDeviceTag), &connector_type,
81262306a36Sopenharmony_ci			     &ddc_bus, &conn_id, &hpd))
81362306a36Sopenharmony_ci				continue;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci			radeon_add_atom_connector(dev,
81662306a36Sopenharmony_ci						  conn_id,
81762306a36Sopenharmony_ci						  le16_to_cpu(path->
81862306a36Sopenharmony_ci							      usDeviceTag),
81962306a36Sopenharmony_ci						  connector_type, &ddc_bus,
82062306a36Sopenharmony_ci						  igp_lane_info,
82162306a36Sopenharmony_ci						  connector_object_id,
82262306a36Sopenharmony_ci						  &hpd,
82362306a36Sopenharmony_ci						  &router);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		}
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	radeon_link_encoder_connector(dev);
82962306a36Sopenharmony_ci	return true;
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic uint16_t atombios_get_connector_object_id(struct drm_device *dev,
83362306a36Sopenharmony_ci						 int connector_type,
83462306a36Sopenharmony_ci						 uint16_t devices)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_IGP) {
83962306a36Sopenharmony_ci		return supported_devices_connector_object_id_convert
84062306a36Sopenharmony_ci			[connector_type];
84162306a36Sopenharmony_ci	} else if (((connector_type == DRM_MODE_CONNECTOR_DVII) ||
84262306a36Sopenharmony_ci		    (connector_type == DRM_MODE_CONNECTOR_DVID)) &&
84362306a36Sopenharmony_ci		   (devices & ATOM_DEVICE_DFP2_SUPPORT))  {
84462306a36Sopenharmony_ci		struct radeon_mode_info *mode_info = &rdev->mode_info;
84562306a36Sopenharmony_ci		struct atom_context *ctx = mode_info->atom_context;
84662306a36Sopenharmony_ci		int index = GetIndexIntoMasterTable(DATA, XTMDS_Info);
84762306a36Sopenharmony_ci		uint16_t size, data_offset;
84862306a36Sopenharmony_ci		uint8_t frev, crev;
84962306a36Sopenharmony_ci		ATOM_XTMDS_INFO *xtmds;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci		if (atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) {
85262306a36Sopenharmony_ci			xtmds = (ATOM_XTMDS_INFO *)(ctx->bios + data_offset);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci			if (xtmds->ucSupportedLink & ATOM_XTMDS_SUPPORTED_DUALLINK) {
85562306a36Sopenharmony_ci				if (connector_type == DRM_MODE_CONNECTOR_DVII)
85662306a36Sopenharmony_ci					return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I;
85762306a36Sopenharmony_ci				else
85862306a36Sopenharmony_ci					return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D;
85962306a36Sopenharmony_ci			} else {
86062306a36Sopenharmony_ci				if (connector_type == DRM_MODE_CONNECTOR_DVII)
86162306a36Sopenharmony_ci					return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I;
86262306a36Sopenharmony_ci				else
86362306a36Sopenharmony_ci					return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D;
86462306a36Sopenharmony_ci			}
86562306a36Sopenharmony_ci		} else
86662306a36Sopenharmony_ci			return supported_devices_connector_object_id_convert
86762306a36Sopenharmony_ci				[connector_type];
86862306a36Sopenharmony_ci	} else {
86962306a36Sopenharmony_ci		return supported_devices_connector_object_id_convert
87062306a36Sopenharmony_ci			[connector_type];
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_cistruct bios_connector {
87562306a36Sopenharmony_ci	bool valid;
87662306a36Sopenharmony_ci	uint16_t line_mux;
87762306a36Sopenharmony_ci	uint16_t devices;
87862306a36Sopenharmony_ci	int connector_type;
87962306a36Sopenharmony_ci	struct radeon_i2c_bus_rec ddc_bus;
88062306a36Sopenharmony_ci	struct radeon_hpd hpd;
88162306a36Sopenharmony_ci};
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cibool radeon_get_atom_connector_info_from_supported_devices_table(struct
88462306a36Sopenharmony_ci								 drm_device
88562306a36Sopenharmony_ci								 *dev)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
88862306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
88962306a36Sopenharmony_ci	struct atom_context *ctx = mode_info->atom_context;
89062306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo);
89162306a36Sopenharmony_ci	uint16_t size, data_offset;
89262306a36Sopenharmony_ci	uint8_t frev, crev;
89362306a36Sopenharmony_ci	uint16_t device_support;
89462306a36Sopenharmony_ci	uint8_t dac;
89562306a36Sopenharmony_ci	union atom_supported_devices *supported_devices;
89662306a36Sopenharmony_ci	int i, j, max_device;
89762306a36Sopenharmony_ci	struct bios_connector *bios_connectors;
89862306a36Sopenharmony_ci	size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
89962306a36Sopenharmony_ci	struct radeon_router router;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	router.ddc_valid = false;
90262306a36Sopenharmony_ci	router.cd_valid = false;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	bios_connectors = kzalloc(bc_size, GFP_KERNEL);
90562306a36Sopenharmony_ci	if (!bios_connectors)
90662306a36Sopenharmony_ci		return false;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	if (!atom_parse_data_header(ctx, index, &size, &frev, &crev,
90962306a36Sopenharmony_ci				    &data_offset)) {
91062306a36Sopenharmony_ci		kfree(bios_connectors);
91162306a36Sopenharmony_ci		return false;
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	supported_devices =
91562306a36Sopenharmony_ci	    (union atom_supported_devices *)(ctx->bios + data_offset);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	device_support = le16_to_cpu(supported_devices->info.usDeviceSupport);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	if (frev > 1)
92062306a36Sopenharmony_ci		max_device = ATOM_MAX_SUPPORTED_DEVICE;
92162306a36Sopenharmony_ci	else
92262306a36Sopenharmony_ci		max_device = ATOM_MAX_SUPPORTED_DEVICE_INFO;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	for (i = 0; i < max_device; i++) {
92562306a36Sopenharmony_ci		ATOM_CONNECTOR_INFO_I2C ci =
92662306a36Sopenharmony_ci		    supported_devices->info.asConnInfo[i];
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci		bios_connectors[i].valid = false;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci		if (!(device_support & (1 << i))) {
93162306a36Sopenharmony_ci			continue;
93262306a36Sopenharmony_ci		}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci		if (i == ATOM_DEVICE_CV_INDEX) {
93562306a36Sopenharmony_ci			DRM_DEBUG_KMS("Skipping Component Video\n");
93662306a36Sopenharmony_ci			continue;
93762306a36Sopenharmony_ci		}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		bios_connectors[i].connector_type =
94062306a36Sopenharmony_ci		    supported_devices_connector_convert[ci.sucConnectorInfo.
94162306a36Sopenharmony_ci							sbfAccess.
94262306a36Sopenharmony_ci							bfConnectorType];
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		if (bios_connectors[i].connector_type ==
94562306a36Sopenharmony_ci		    DRM_MODE_CONNECTOR_Unknown)
94662306a36Sopenharmony_ci			continue;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci		dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		bios_connectors[i].line_mux =
95162306a36Sopenharmony_ci			ci.sucI2cId.ucAccess;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci		/* give tv unique connector ids */
95462306a36Sopenharmony_ci		if (i == ATOM_DEVICE_TV1_INDEX) {
95562306a36Sopenharmony_ci			bios_connectors[i].ddc_bus.valid = false;
95662306a36Sopenharmony_ci			bios_connectors[i].line_mux = 50;
95762306a36Sopenharmony_ci		} else if (i == ATOM_DEVICE_TV2_INDEX) {
95862306a36Sopenharmony_ci			bios_connectors[i].ddc_bus.valid = false;
95962306a36Sopenharmony_ci			bios_connectors[i].line_mux = 51;
96062306a36Sopenharmony_ci		} else if (i == ATOM_DEVICE_CV_INDEX) {
96162306a36Sopenharmony_ci			bios_connectors[i].ddc_bus.valid = false;
96262306a36Sopenharmony_ci			bios_connectors[i].line_mux = 52;
96362306a36Sopenharmony_ci		} else
96462306a36Sopenharmony_ci			bios_connectors[i].ddc_bus =
96562306a36Sopenharmony_ci			    radeon_lookup_i2c_gpio(rdev,
96662306a36Sopenharmony_ci						   bios_connectors[i].line_mux);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci		if ((crev > 1) && (frev > 1)) {
96962306a36Sopenharmony_ci			u8 isb = supported_devices->info_2d1.asIntSrcInfo[i].ucIntSrcBitmap;
97062306a36Sopenharmony_ci			switch (isb) {
97162306a36Sopenharmony_ci			case 0x4:
97262306a36Sopenharmony_ci				bios_connectors[i].hpd.hpd = RADEON_HPD_1;
97362306a36Sopenharmony_ci				break;
97462306a36Sopenharmony_ci			case 0xa:
97562306a36Sopenharmony_ci				bios_connectors[i].hpd.hpd = RADEON_HPD_2;
97662306a36Sopenharmony_ci				break;
97762306a36Sopenharmony_ci			default:
97862306a36Sopenharmony_ci				bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
97962306a36Sopenharmony_ci				break;
98062306a36Sopenharmony_ci			}
98162306a36Sopenharmony_ci		} else {
98262306a36Sopenharmony_ci			if (i == ATOM_DEVICE_DFP1_INDEX)
98362306a36Sopenharmony_ci				bios_connectors[i].hpd.hpd = RADEON_HPD_1;
98462306a36Sopenharmony_ci			else if (i == ATOM_DEVICE_DFP2_INDEX)
98562306a36Sopenharmony_ci				bios_connectors[i].hpd.hpd = RADEON_HPD_2;
98662306a36Sopenharmony_ci			else
98762306a36Sopenharmony_ci				bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
98862306a36Sopenharmony_ci		}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci		/* Always set the connector type to VGA for CRT1/CRT2. if they are
99162306a36Sopenharmony_ci		 * shared with a DVI port, we'll pick up the DVI connector when we
99262306a36Sopenharmony_ci		 * merge the outputs.  Some bioses incorrectly list VGA ports as DVI.
99362306a36Sopenharmony_ci		 */
99462306a36Sopenharmony_ci		if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX)
99562306a36Sopenharmony_ci			bios_connectors[i].connector_type =
99662306a36Sopenharmony_ci			    DRM_MODE_CONNECTOR_VGA;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci		if (!radeon_atom_apply_quirks
99962306a36Sopenharmony_ci		    (dev, (1 << i), &bios_connectors[i].connector_type,
100062306a36Sopenharmony_ci		     &bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux,
100162306a36Sopenharmony_ci		     &bios_connectors[i].hpd))
100262306a36Sopenharmony_ci			continue;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		bios_connectors[i].valid = true;
100562306a36Sopenharmony_ci		bios_connectors[i].devices = (1 << i);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci		if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom)
100862306a36Sopenharmony_ci			radeon_add_atom_encoder(dev,
100962306a36Sopenharmony_ci						radeon_get_encoder_enum(dev,
101062306a36Sopenharmony_ci								      (1 << i),
101162306a36Sopenharmony_ci								      dac),
101262306a36Sopenharmony_ci						(1 << i),
101362306a36Sopenharmony_ci						0);
101462306a36Sopenharmony_ci		else
101562306a36Sopenharmony_ci			radeon_add_legacy_encoder(dev,
101662306a36Sopenharmony_ci						  radeon_get_encoder_enum(dev,
101762306a36Sopenharmony_ci									(1 << i),
101862306a36Sopenharmony_ci									dac),
101962306a36Sopenharmony_ci						  (1 << i));
102062306a36Sopenharmony_ci	}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	/* combine shared connectors */
102362306a36Sopenharmony_ci	for (i = 0; i < max_device; i++) {
102462306a36Sopenharmony_ci		if (bios_connectors[i].valid) {
102562306a36Sopenharmony_ci			for (j = 0; j < max_device; j++) {
102662306a36Sopenharmony_ci				if (bios_connectors[j].valid && (i != j)) {
102762306a36Sopenharmony_ci					if (bios_connectors[i].line_mux ==
102862306a36Sopenharmony_ci					    bios_connectors[j].line_mux) {
102962306a36Sopenharmony_ci						/* make sure not to combine LVDS */
103062306a36Sopenharmony_ci						if (bios_connectors[i].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
103162306a36Sopenharmony_ci							bios_connectors[i].line_mux = 53;
103262306a36Sopenharmony_ci							bios_connectors[i].ddc_bus.valid = false;
103362306a36Sopenharmony_ci							continue;
103462306a36Sopenharmony_ci						}
103562306a36Sopenharmony_ci						if (bios_connectors[j].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
103662306a36Sopenharmony_ci							bios_connectors[j].line_mux = 53;
103762306a36Sopenharmony_ci							bios_connectors[j].ddc_bus.valid = false;
103862306a36Sopenharmony_ci							continue;
103962306a36Sopenharmony_ci						}
104062306a36Sopenharmony_ci						/* combine analog and digital for DVI-I */
104162306a36Sopenharmony_ci						if (((bios_connectors[i].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
104262306a36Sopenharmony_ci						     (bios_connectors[j].devices & (ATOM_DEVICE_CRT_SUPPORT))) ||
104362306a36Sopenharmony_ci						    ((bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
104462306a36Sopenharmony_ci						     (bios_connectors[i].devices & (ATOM_DEVICE_CRT_SUPPORT)))) {
104562306a36Sopenharmony_ci							bios_connectors[i].devices |=
104662306a36Sopenharmony_ci								bios_connectors[j].devices;
104762306a36Sopenharmony_ci							bios_connectors[i].connector_type =
104862306a36Sopenharmony_ci								DRM_MODE_CONNECTOR_DVII;
104962306a36Sopenharmony_ci							if (bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT))
105062306a36Sopenharmony_ci								bios_connectors[i].hpd =
105162306a36Sopenharmony_ci									bios_connectors[j].hpd;
105262306a36Sopenharmony_ci							bios_connectors[j].valid = false;
105362306a36Sopenharmony_ci						}
105462306a36Sopenharmony_ci					}
105562306a36Sopenharmony_ci				}
105662306a36Sopenharmony_ci			}
105762306a36Sopenharmony_ci		}
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	/* add the connectors */
106162306a36Sopenharmony_ci	for (i = 0; i < max_device; i++) {
106262306a36Sopenharmony_ci		if (bios_connectors[i].valid) {
106362306a36Sopenharmony_ci			uint16_t connector_object_id =
106462306a36Sopenharmony_ci				atombios_get_connector_object_id(dev,
106562306a36Sopenharmony_ci						      bios_connectors[i].connector_type,
106662306a36Sopenharmony_ci						      bios_connectors[i].devices);
106762306a36Sopenharmony_ci			radeon_add_atom_connector(dev,
106862306a36Sopenharmony_ci						  bios_connectors[i].line_mux,
106962306a36Sopenharmony_ci						  bios_connectors[i].devices,
107062306a36Sopenharmony_ci						  bios_connectors[i].
107162306a36Sopenharmony_ci						  connector_type,
107262306a36Sopenharmony_ci						  &bios_connectors[i].ddc_bus,
107362306a36Sopenharmony_ci						  0,
107462306a36Sopenharmony_ci						  connector_object_id,
107562306a36Sopenharmony_ci						  &bios_connectors[i].hpd,
107662306a36Sopenharmony_ci						  &router);
107762306a36Sopenharmony_ci		}
107862306a36Sopenharmony_ci	}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	radeon_link_encoder_connector(dev);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	kfree(bios_connectors);
108362306a36Sopenharmony_ci	return true;
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ciunion firmware_info {
108762306a36Sopenharmony_ci	ATOM_FIRMWARE_INFO info;
108862306a36Sopenharmony_ci	ATOM_FIRMWARE_INFO_V1_2 info_12;
108962306a36Sopenharmony_ci	ATOM_FIRMWARE_INFO_V1_3 info_13;
109062306a36Sopenharmony_ci	ATOM_FIRMWARE_INFO_V1_4 info_14;
109162306a36Sopenharmony_ci	ATOM_FIRMWARE_INFO_V2_1 info_21;
109262306a36Sopenharmony_ci	ATOM_FIRMWARE_INFO_V2_2 info_22;
109362306a36Sopenharmony_ci};
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ciunion igp_info {
109662306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
109762306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
109862306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
109962306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
110062306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
110162306a36Sopenharmony_ci};
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic void radeon_atombios_get_dentist_vco_freq(struct radeon_device *rdev)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
110662306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
110762306a36Sopenharmony_ci	union igp_info *igp_info;
110862306a36Sopenharmony_ci	u8 frev, crev;
110962306a36Sopenharmony_ci	u16 data_offset;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
111262306a36Sopenharmony_ci			&frev, &crev, &data_offset)) {
111362306a36Sopenharmony_ci		igp_info = (union igp_info *)(mode_info->atom_context->bios +
111462306a36Sopenharmony_ci			data_offset);
111562306a36Sopenharmony_ci		rdev->clock.vco_freq =
111662306a36Sopenharmony_ci			le32_to_cpu(igp_info->info_6.ulDentistVCOFreq);
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_cibool radeon_atom_get_clock_info(struct drm_device *dev)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
112362306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
112462306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
112562306a36Sopenharmony_ci	union firmware_info *firmware_info;
112662306a36Sopenharmony_ci	uint8_t frev, crev;
112762306a36Sopenharmony_ci	struct radeon_pll *p1pll = &rdev->clock.p1pll;
112862306a36Sopenharmony_ci	struct radeon_pll *p2pll = &rdev->clock.p2pll;
112962306a36Sopenharmony_ci	struct radeon_pll *dcpll = &rdev->clock.dcpll;
113062306a36Sopenharmony_ci	struct radeon_pll *spll = &rdev->clock.spll;
113162306a36Sopenharmony_ci	struct radeon_pll *mpll = &rdev->clock.mpll;
113262306a36Sopenharmony_ci	uint16_t data_offset;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
113562306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
113662306a36Sopenharmony_ci		firmware_info =
113762306a36Sopenharmony_ci			(union firmware_info *)(mode_info->atom_context->bios +
113862306a36Sopenharmony_ci						data_offset);
113962306a36Sopenharmony_ci		/* pixel clocks */
114062306a36Sopenharmony_ci		p1pll->reference_freq =
114162306a36Sopenharmony_ci		    le16_to_cpu(firmware_info->info.usReferenceClock);
114262306a36Sopenharmony_ci		p1pll->reference_div = 0;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci		if ((frev < 2) && (crev < 2))
114562306a36Sopenharmony_ci			p1pll->pll_out_min =
114662306a36Sopenharmony_ci				le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
114762306a36Sopenharmony_ci		else
114862306a36Sopenharmony_ci			p1pll->pll_out_min =
114962306a36Sopenharmony_ci				le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
115062306a36Sopenharmony_ci		p1pll->pll_out_max =
115162306a36Sopenharmony_ci		    le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci		if (((frev < 2) && (crev >= 4)) || (frev >= 2)) {
115462306a36Sopenharmony_ci			p1pll->lcd_pll_out_min =
115562306a36Sopenharmony_ci				le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
115662306a36Sopenharmony_ci			if (p1pll->lcd_pll_out_min == 0)
115762306a36Sopenharmony_ci				p1pll->lcd_pll_out_min = p1pll->pll_out_min;
115862306a36Sopenharmony_ci			p1pll->lcd_pll_out_max =
115962306a36Sopenharmony_ci				le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
116062306a36Sopenharmony_ci			if (p1pll->lcd_pll_out_max == 0)
116162306a36Sopenharmony_ci				p1pll->lcd_pll_out_max = p1pll->pll_out_max;
116262306a36Sopenharmony_ci		} else {
116362306a36Sopenharmony_ci			p1pll->lcd_pll_out_min = p1pll->pll_out_min;
116462306a36Sopenharmony_ci			p1pll->lcd_pll_out_max = p1pll->pll_out_max;
116562306a36Sopenharmony_ci		}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci		if (p1pll->pll_out_min == 0) {
116862306a36Sopenharmony_ci			if (ASIC_IS_AVIVO(rdev))
116962306a36Sopenharmony_ci				p1pll->pll_out_min = 64800;
117062306a36Sopenharmony_ci			else
117162306a36Sopenharmony_ci				p1pll->pll_out_min = 20000;
117262306a36Sopenharmony_ci		}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci		p1pll->pll_in_min =
117562306a36Sopenharmony_ci		    le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input);
117662306a36Sopenharmony_ci		p1pll->pll_in_max =
117762306a36Sopenharmony_ci		    le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci		*p2pll = *p1pll;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci		/* system clock */
118262306a36Sopenharmony_ci		if (ASIC_IS_DCE4(rdev))
118362306a36Sopenharmony_ci			spll->reference_freq =
118462306a36Sopenharmony_ci				le16_to_cpu(firmware_info->info_21.usCoreReferenceClock);
118562306a36Sopenharmony_ci		else
118662306a36Sopenharmony_ci			spll->reference_freq =
118762306a36Sopenharmony_ci				le16_to_cpu(firmware_info->info.usReferenceClock);
118862306a36Sopenharmony_ci		spll->reference_div = 0;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci		spll->pll_out_min =
119162306a36Sopenharmony_ci		    le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output);
119262306a36Sopenharmony_ci		spll->pll_out_max =
119362306a36Sopenharmony_ci		    le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci		/* ??? */
119662306a36Sopenharmony_ci		if (spll->pll_out_min == 0) {
119762306a36Sopenharmony_ci			if (ASIC_IS_AVIVO(rdev))
119862306a36Sopenharmony_ci				spll->pll_out_min = 64800;
119962306a36Sopenharmony_ci			else
120062306a36Sopenharmony_ci				spll->pll_out_min = 20000;
120162306a36Sopenharmony_ci		}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci		spll->pll_in_min =
120462306a36Sopenharmony_ci		    le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input);
120562306a36Sopenharmony_ci		spll->pll_in_max =
120662306a36Sopenharmony_ci		    le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci		/* memory clock */
120962306a36Sopenharmony_ci		if (ASIC_IS_DCE4(rdev))
121062306a36Sopenharmony_ci			mpll->reference_freq =
121162306a36Sopenharmony_ci				le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock);
121262306a36Sopenharmony_ci		else
121362306a36Sopenharmony_ci			mpll->reference_freq =
121462306a36Sopenharmony_ci				le16_to_cpu(firmware_info->info.usReferenceClock);
121562306a36Sopenharmony_ci		mpll->reference_div = 0;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci		mpll->pll_out_min =
121862306a36Sopenharmony_ci		    le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output);
121962306a36Sopenharmony_ci		mpll->pll_out_max =
122062306a36Sopenharmony_ci		    le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci		/* ??? */
122362306a36Sopenharmony_ci		if (mpll->pll_out_min == 0) {
122462306a36Sopenharmony_ci			if (ASIC_IS_AVIVO(rdev))
122562306a36Sopenharmony_ci				mpll->pll_out_min = 64800;
122662306a36Sopenharmony_ci			else
122762306a36Sopenharmony_ci				mpll->pll_out_min = 20000;
122862306a36Sopenharmony_ci		}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci		mpll->pll_in_min =
123162306a36Sopenharmony_ci		    le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input);
123262306a36Sopenharmony_ci		mpll->pll_in_max =
123362306a36Sopenharmony_ci		    le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		rdev->clock.default_sclk =
123662306a36Sopenharmony_ci		    le32_to_cpu(firmware_info->info.ulDefaultEngineClock);
123762306a36Sopenharmony_ci		rdev->clock.default_mclk =
123862306a36Sopenharmony_ci		    le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci		if (ASIC_IS_DCE4(rdev)) {
124162306a36Sopenharmony_ci			rdev->clock.default_dispclk =
124262306a36Sopenharmony_ci				le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);
124362306a36Sopenharmony_ci			if (rdev->clock.default_dispclk == 0) {
124462306a36Sopenharmony_ci				if (ASIC_IS_DCE6(rdev))
124562306a36Sopenharmony_ci					rdev->clock.default_dispclk = 60000; /* 600 Mhz */
124662306a36Sopenharmony_ci				else if (ASIC_IS_DCE5(rdev))
124762306a36Sopenharmony_ci					rdev->clock.default_dispclk = 54000; /* 540 Mhz */
124862306a36Sopenharmony_ci				else
124962306a36Sopenharmony_ci					rdev->clock.default_dispclk = 60000; /* 600 Mhz */
125062306a36Sopenharmony_ci			}
125162306a36Sopenharmony_ci			/* set a reasonable default for DP */
125262306a36Sopenharmony_ci			if (ASIC_IS_DCE6(rdev) && (rdev->clock.default_dispclk < 53900)) {
125362306a36Sopenharmony_ci				DRM_INFO("Changing default dispclk from %dMhz to 600Mhz\n",
125462306a36Sopenharmony_ci					 rdev->clock.default_dispclk / 100);
125562306a36Sopenharmony_ci				rdev->clock.default_dispclk = 60000;
125662306a36Sopenharmony_ci			}
125762306a36Sopenharmony_ci			rdev->clock.dp_extclk =
125862306a36Sopenharmony_ci				le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
125962306a36Sopenharmony_ci			rdev->clock.current_dispclk = rdev->clock.default_dispclk;
126062306a36Sopenharmony_ci		}
126162306a36Sopenharmony_ci		*dcpll = *p1pll;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci		rdev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock);
126462306a36Sopenharmony_ci		if (rdev->clock.max_pixel_clock == 0)
126562306a36Sopenharmony_ci			rdev->clock.max_pixel_clock = 40000;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci		/* not technically a clock, but... */
126862306a36Sopenharmony_ci		rdev->mode_info.firmware_flags =
126962306a36Sopenharmony_ci			le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci		if (ASIC_IS_DCE8(rdev))
127262306a36Sopenharmony_ci			rdev->clock.vco_freq =
127362306a36Sopenharmony_ci				le32_to_cpu(firmware_info->info_22.ulGPUPLL_OutputFreq);
127462306a36Sopenharmony_ci		else if (ASIC_IS_DCE5(rdev))
127562306a36Sopenharmony_ci			rdev->clock.vco_freq = rdev->clock.current_dispclk;
127662306a36Sopenharmony_ci		else if (ASIC_IS_DCE41(rdev))
127762306a36Sopenharmony_ci			radeon_atombios_get_dentist_vco_freq(rdev);
127862306a36Sopenharmony_ci		else
127962306a36Sopenharmony_ci			rdev->clock.vco_freq = rdev->clock.current_dispclk;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci		if (rdev->clock.vco_freq == 0)
128262306a36Sopenharmony_ci			rdev->clock.vco_freq = 360000;	/* 3.6 GHz */
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci		return true;
128562306a36Sopenharmony_ci	}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	return false;
128862306a36Sopenharmony_ci}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_cibool radeon_atombios_sideport_present(struct radeon_device *rdev)
129162306a36Sopenharmony_ci{
129262306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
129362306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
129462306a36Sopenharmony_ci	union igp_info *igp_info;
129562306a36Sopenharmony_ci	u8 frev, crev;
129662306a36Sopenharmony_ci	u16 data_offset;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	/* sideport is AMD only */
129962306a36Sopenharmony_ci	if (rdev->family == CHIP_RS600)
130062306a36Sopenharmony_ci		return false;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
130362306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
130462306a36Sopenharmony_ci		igp_info = (union igp_info *)(mode_info->atom_context->bios +
130562306a36Sopenharmony_ci				      data_offset);
130662306a36Sopenharmony_ci		switch (crev) {
130762306a36Sopenharmony_ci		case 1:
130862306a36Sopenharmony_ci			if (le32_to_cpu(igp_info->info.ulBootUpMemoryClock))
130962306a36Sopenharmony_ci				return true;
131062306a36Sopenharmony_ci			break;
131162306a36Sopenharmony_ci		case 2:
131262306a36Sopenharmony_ci			if (le32_to_cpu(igp_info->info_2.ulBootUpSidePortClock))
131362306a36Sopenharmony_ci				return true;
131462306a36Sopenharmony_ci			break;
131562306a36Sopenharmony_ci		default:
131662306a36Sopenharmony_ci			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
131762306a36Sopenharmony_ci			break;
131862306a36Sopenharmony_ci		}
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci	return false;
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_cibool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,
132462306a36Sopenharmony_ci				   struct radeon_encoder_int_tmds *tmds)
132562306a36Sopenharmony_ci{
132662306a36Sopenharmony_ci	struct drm_device *dev = encoder->base.dev;
132762306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
132862306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
132962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, TMDS_Info);
133062306a36Sopenharmony_ci	uint16_t data_offset;
133162306a36Sopenharmony_ci	struct _ATOM_TMDS_INFO *tmds_info;
133262306a36Sopenharmony_ci	uint8_t frev, crev;
133362306a36Sopenharmony_ci	uint16_t maxfreq;
133462306a36Sopenharmony_ci	int i;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
133762306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
133862306a36Sopenharmony_ci		tmds_info =
133962306a36Sopenharmony_ci			(struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios +
134062306a36Sopenharmony_ci						   data_offset);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci		maxfreq = le16_to_cpu(tmds_info->usMaxFrequency);
134362306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
134462306a36Sopenharmony_ci			tmds->tmds_pll[i].freq =
134562306a36Sopenharmony_ci			    le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency);
134662306a36Sopenharmony_ci			tmds->tmds_pll[i].value =
134762306a36Sopenharmony_ci			    tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f;
134862306a36Sopenharmony_ci			tmds->tmds_pll[i].value |=
134962306a36Sopenharmony_ci			    (tmds_info->asMiscInfo[i].
135062306a36Sopenharmony_ci			     ucPLL_VCO_Gain & 0x3f) << 6;
135162306a36Sopenharmony_ci			tmds->tmds_pll[i].value |=
135262306a36Sopenharmony_ci			    (tmds_info->asMiscInfo[i].
135362306a36Sopenharmony_ci			     ucPLL_DutyCycle & 0xf) << 12;
135462306a36Sopenharmony_ci			tmds->tmds_pll[i].value |=
135562306a36Sopenharmony_ci			    (tmds_info->asMiscInfo[i].
135662306a36Sopenharmony_ci			     ucPLL_VoltageSwing & 0xf) << 16;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci			DRM_DEBUG_KMS("TMDS PLL From ATOMBIOS %u %x\n",
135962306a36Sopenharmony_ci				  tmds->tmds_pll[i].freq,
136062306a36Sopenharmony_ci				  tmds->tmds_pll[i].value);
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci			if (maxfreq == tmds->tmds_pll[i].freq) {
136362306a36Sopenharmony_ci				tmds->tmds_pll[i].freq = 0xffffffff;
136462306a36Sopenharmony_ci				break;
136562306a36Sopenharmony_ci			}
136662306a36Sopenharmony_ci		}
136762306a36Sopenharmony_ci		return true;
136862306a36Sopenharmony_ci	}
136962306a36Sopenharmony_ci	return false;
137062306a36Sopenharmony_ci}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_cibool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
137362306a36Sopenharmony_ci				      struct radeon_atom_ss *ss,
137462306a36Sopenharmony_ci				      int id)
137562306a36Sopenharmony_ci{
137662306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
137762306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
137862306a36Sopenharmony_ci	uint16_t data_offset, size;
137962306a36Sopenharmony_ci	struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
138062306a36Sopenharmony_ci	struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT *ss_assign;
138162306a36Sopenharmony_ci	uint8_t frev, crev;
138262306a36Sopenharmony_ci	int i, num_indices;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	memset(ss, 0, sizeof(struct radeon_atom_ss));
138562306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, &size,
138662306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
138762306a36Sopenharmony_ci		ss_info =
138862306a36Sopenharmony_ci			(struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
139162306a36Sopenharmony_ci			sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
139262306a36Sopenharmony_ci		ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT *)
139362306a36Sopenharmony_ci			((u8 *)&ss_info->asSS_Info[0]);
139462306a36Sopenharmony_ci		for (i = 0; i < num_indices; i++) {
139562306a36Sopenharmony_ci			if (ss_assign->ucSS_Id == id) {
139662306a36Sopenharmony_ci				ss->percentage =
139762306a36Sopenharmony_ci					le16_to_cpu(ss_assign->usSpreadSpectrumPercentage);
139862306a36Sopenharmony_ci				ss->type = ss_assign->ucSpreadSpectrumType;
139962306a36Sopenharmony_ci				ss->step = ss_assign->ucSS_Step;
140062306a36Sopenharmony_ci				ss->delay = ss_assign->ucSS_Delay;
140162306a36Sopenharmony_ci				ss->range = ss_assign->ucSS_Range;
140262306a36Sopenharmony_ci				ss->refdiv = ss_assign->ucRecommendedRef_Div;
140362306a36Sopenharmony_ci				return true;
140462306a36Sopenharmony_ci			}
140562306a36Sopenharmony_ci			ss_assign = (struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT *)
140662306a36Sopenharmony_ci				((u8 *)ss_assign + sizeof(struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT));
140762306a36Sopenharmony_ci		}
140862306a36Sopenharmony_ci	}
140962306a36Sopenharmony_ci	return false;
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_cistatic void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
141362306a36Sopenharmony_ci						 struct radeon_atom_ss *ss,
141462306a36Sopenharmony_ci						 int id)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
141762306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
141862306a36Sopenharmony_ci	u16 data_offset, size;
141962306a36Sopenharmony_ci	union igp_info *igp_info;
142062306a36Sopenharmony_ci	u8 frev, crev;
142162306a36Sopenharmony_ci	u16 percentage = 0, rate = 0;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	/* get any igp specific overrides */
142462306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, &size,
142562306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
142662306a36Sopenharmony_ci		igp_info = (union igp_info *)
142762306a36Sopenharmony_ci			(mode_info->atom_context->bios + data_offset);
142862306a36Sopenharmony_ci		switch (crev) {
142962306a36Sopenharmony_ci		case 6:
143062306a36Sopenharmony_ci			switch (id) {
143162306a36Sopenharmony_ci			case ASIC_INTERNAL_SS_ON_TMDS:
143262306a36Sopenharmony_ci				percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage);
143362306a36Sopenharmony_ci				rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz);
143462306a36Sopenharmony_ci				break;
143562306a36Sopenharmony_ci			case ASIC_INTERNAL_SS_ON_HDMI:
143662306a36Sopenharmony_ci				percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage);
143762306a36Sopenharmony_ci				rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz);
143862306a36Sopenharmony_ci				break;
143962306a36Sopenharmony_ci			case ASIC_INTERNAL_SS_ON_LVDS:
144062306a36Sopenharmony_ci				percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage);
144162306a36Sopenharmony_ci				rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz);
144262306a36Sopenharmony_ci				break;
144362306a36Sopenharmony_ci			}
144462306a36Sopenharmony_ci			break;
144562306a36Sopenharmony_ci		case 7:
144662306a36Sopenharmony_ci			switch (id) {
144762306a36Sopenharmony_ci			case ASIC_INTERNAL_SS_ON_TMDS:
144862306a36Sopenharmony_ci				percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage);
144962306a36Sopenharmony_ci				rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz);
145062306a36Sopenharmony_ci				break;
145162306a36Sopenharmony_ci			case ASIC_INTERNAL_SS_ON_HDMI:
145262306a36Sopenharmony_ci				percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage);
145362306a36Sopenharmony_ci				rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz);
145462306a36Sopenharmony_ci				break;
145562306a36Sopenharmony_ci			case ASIC_INTERNAL_SS_ON_LVDS:
145662306a36Sopenharmony_ci				percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage);
145762306a36Sopenharmony_ci				rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz);
145862306a36Sopenharmony_ci				break;
145962306a36Sopenharmony_ci			}
146062306a36Sopenharmony_ci			break;
146162306a36Sopenharmony_ci		case 8:
146262306a36Sopenharmony_ci			switch (id) {
146362306a36Sopenharmony_ci			case ASIC_INTERNAL_SS_ON_TMDS:
146462306a36Sopenharmony_ci				percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage);
146562306a36Sopenharmony_ci				rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz);
146662306a36Sopenharmony_ci				break;
146762306a36Sopenharmony_ci			case ASIC_INTERNAL_SS_ON_HDMI:
146862306a36Sopenharmony_ci				percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage);
146962306a36Sopenharmony_ci				rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz);
147062306a36Sopenharmony_ci				break;
147162306a36Sopenharmony_ci			case ASIC_INTERNAL_SS_ON_LVDS:
147262306a36Sopenharmony_ci				percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage);
147362306a36Sopenharmony_ci				rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz);
147462306a36Sopenharmony_ci				break;
147562306a36Sopenharmony_ci			}
147662306a36Sopenharmony_ci			break;
147762306a36Sopenharmony_ci		default:
147862306a36Sopenharmony_ci			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
147962306a36Sopenharmony_ci			break;
148062306a36Sopenharmony_ci		}
148162306a36Sopenharmony_ci		if (percentage)
148262306a36Sopenharmony_ci			ss->percentage = percentage;
148362306a36Sopenharmony_ci		if (rate)
148462306a36Sopenharmony_ci			ss->rate = rate;
148562306a36Sopenharmony_ci	}
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ciunion asic_ss_info {
148962306a36Sopenharmony_ci	struct _ATOM_ASIC_INTERNAL_SS_INFO info;
149062306a36Sopenharmony_ci	struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
149162306a36Sopenharmony_ci	struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
149262306a36Sopenharmony_ci};
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ciunion asic_ss_assignment {
149562306a36Sopenharmony_ci	struct _ATOM_ASIC_SS_ASSIGNMENT v1;
149662306a36Sopenharmony_ci	struct _ATOM_ASIC_SS_ASSIGNMENT_V2 v2;
149762306a36Sopenharmony_ci	struct _ATOM_ASIC_SS_ASSIGNMENT_V3 v3;
149862306a36Sopenharmony_ci};
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_cibool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
150162306a36Sopenharmony_ci				      struct radeon_atom_ss *ss,
150262306a36Sopenharmony_ci				      int id, u32 clock)
150362306a36Sopenharmony_ci{
150462306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
150562306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
150662306a36Sopenharmony_ci	uint16_t data_offset, size;
150762306a36Sopenharmony_ci	union asic_ss_info *ss_info;
150862306a36Sopenharmony_ci	union asic_ss_assignment *ss_assign;
150962306a36Sopenharmony_ci	uint8_t frev, crev;
151062306a36Sopenharmony_ci	int i, num_indices;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	if (id == ASIC_INTERNAL_MEMORY_SS) {
151362306a36Sopenharmony_ci		if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT))
151462306a36Sopenharmony_ci			return false;
151562306a36Sopenharmony_ci	}
151662306a36Sopenharmony_ci	if (id == ASIC_INTERNAL_ENGINE_SS) {
151762306a36Sopenharmony_ci		if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT))
151862306a36Sopenharmony_ci			return false;
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	memset(ss, 0, sizeof(struct radeon_atom_ss));
152262306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, &size,
152362306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci		ss_info =
152662306a36Sopenharmony_ci			(union asic_ss_info *)(mode_info->atom_context->bios + data_offset);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci		switch (frev) {
152962306a36Sopenharmony_ci		case 1:
153062306a36Sopenharmony_ci			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
153162306a36Sopenharmony_ci				sizeof(ATOM_ASIC_SS_ASSIGNMENT);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci			ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info.asSpreadSpectrum[0]);
153462306a36Sopenharmony_ci			for (i = 0; i < num_indices; i++) {
153562306a36Sopenharmony_ci				if ((ss_assign->v1.ucClockIndication == id) &&
153662306a36Sopenharmony_ci				    (clock <= le32_to_cpu(ss_assign->v1.ulTargetClockRange))) {
153762306a36Sopenharmony_ci					ss->percentage =
153862306a36Sopenharmony_ci						le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage);
153962306a36Sopenharmony_ci					ss->type = ss_assign->v1.ucSpreadSpectrumMode;
154062306a36Sopenharmony_ci					ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz);
154162306a36Sopenharmony_ci					ss->percentage_divider = 100;
154262306a36Sopenharmony_ci					return true;
154362306a36Sopenharmony_ci				}
154462306a36Sopenharmony_ci				ss_assign = (union asic_ss_assignment *)
154562306a36Sopenharmony_ci					((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT));
154662306a36Sopenharmony_ci			}
154762306a36Sopenharmony_ci			break;
154862306a36Sopenharmony_ci		case 2:
154962306a36Sopenharmony_ci			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
155062306a36Sopenharmony_ci				sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
155162306a36Sopenharmony_ci			ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_2.asSpreadSpectrum[0]);
155262306a36Sopenharmony_ci			for (i = 0; i < num_indices; i++) {
155362306a36Sopenharmony_ci				if ((ss_assign->v2.ucClockIndication == id) &&
155462306a36Sopenharmony_ci				    (clock <= le32_to_cpu(ss_assign->v2.ulTargetClockRange))) {
155562306a36Sopenharmony_ci					ss->percentage =
155662306a36Sopenharmony_ci						le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage);
155762306a36Sopenharmony_ci					ss->type = ss_assign->v2.ucSpreadSpectrumMode;
155862306a36Sopenharmony_ci					ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz);
155962306a36Sopenharmony_ci					ss->percentage_divider = 100;
156062306a36Sopenharmony_ci					if ((crev == 2) &&
156162306a36Sopenharmony_ci					    ((id == ASIC_INTERNAL_ENGINE_SS) ||
156262306a36Sopenharmony_ci					     (id == ASIC_INTERNAL_MEMORY_SS)))
156362306a36Sopenharmony_ci						ss->rate /= 100;
156462306a36Sopenharmony_ci					return true;
156562306a36Sopenharmony_ci				}
156662306a36Sopenharmony_ci				ss_assign = (union asic_ss_assignment *)
156762306a36Sopenharmony_ci					((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2));
156862306a36Sopenharmony_ci			}
156962306a36Sopenharmony_ci			break;
157062306a36Sopenharmony_ci		case 3:
157162306a36Sopenharmony_ci			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
157262306a36Sopenharmony_ci				sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
157362306a36Sopenharmony_ci			ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_3.asSpreadSpectrum[0]);
157462306a36Sopenharmony_ci			for (i = 0; i < num_indices; i++) {
157562306a36Sopenharmony_ci				if ((ss_assign->v3.ucClockIndication == id) &&
157662306a36Sopenharmony_ci				    (clock <= le32_to_cpu(ss_assign->v3.ulTargetClockRange))) {
157762306a36Sopenharmony_ci					ss->percentage =
157862306a36Sopenharmony_ci						le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage);
157962306a36Sopenharmony_ci					ss->type = ss_assign->v3.ucSpreadSpectrumMode;
158062306a36Sopenharmony_ci					ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz);
158162306a36Sopenharmony_ci					if (ss_assign->v3.ucSpreadSpectrumMode &
158262306a36Sopenharmony_ci					    SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK)
158362306a36Sopenharmony_ci						ss->percentage_divider = 1000;
158462306a36Sopenharmony_ci					else
158562306a36Sopenharmony_ci						ss->percentage_divider = 100;
158662306a36Sopenharmony_ci					if ((id == ASIC_INTERNAL_ENGINE_SS) ||
158762306a36Sopenharmony_ci					    (id == ASIC_INTERNAL_MEMORY_SS))
158862306a36Sopenharmony_ci						ss->rate /= 100;
158962306a36Sopenharmony_ci					if (rdev->flags & RADEON_IS_IGP)
159062306a36Sopenharmony_ci						radeon_atombios_get_igp_ss_overrides(rdev, ss, id);
159162306a36Sopenharmony_ci					return true;
159262306a36Sopenharmony_ci				}
159362306a36Sopenharmony_ci				ss_assign = (union asic_ss_assignment *)
159462306a36Sopenharmony_ci					((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3));
159562306a36Sopenharmony_ci			}
159662306a36Sopenharmony_ci			break;
159762306a36Sopenharmony_ci		default:
159862306a36Sopenharmony_ci			DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);
159962306a36Sopenharmony_ci			break;
160062306a36Sopenharmony_ci		}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci	return false;
160462306a36Sopenharmony_ci}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ciunion lvds_info {
160762306a36Sopenharmony_ci	struct _ATOM_LVDS_INFO info;
160862306a36Sopenharmony_ci	struct _ATOM_LVDS_INFO_V12 info_12;
160962306a36Sopenharmony_ci};
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_cistruct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
161262306a36Sopenharmony_ci							      radeon_encoder
161362306a36Sopenharmony_ci							      *encoder)
161462306a36Sopenharmony_ci{
161562306a36Sopenharmony_ci	struct drm_device *dev = encoder->base.dev;
161662306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
161762306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
161862306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
161962306a36Sopenharmony_ci	uint16_t data_offset, misc;
162062306a36Sopenharmony_ci	union lvds_info *lvds_info;
162162306a36Sopenharmony_ci	uint8_t frev, crev;
162262306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *lvds = NULL;
162362306a36Sopenharmony_ci	int encoder_enum = (encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
162662306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
162762306a36Sopenharmony_ci		lvds_info =
162862306a36Sopenharmony_ci			(union lvds_info *)(mode_info->atom_context->bios + data_offset);
162962306a36Sopenharmony_ci		lvds =
163062306a36Sopenharmony_ci		    kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL);
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci		if (!lvds)
163362306a36Sopenharmony_ci			return NULL;
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci		lvds->native_mode.clock =
163662306a36Sopenharmony_ci		    le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10;
163762306a36Sopenharmony_ci		lvds->native_mode.hdisplay =
163862306a36Sopenharmony_ci		    le16_to_cpu(lvds_info->info.sLCDTiming.usHActive);
163962306a36Sopenharmony_ci		lvds->native_mode.vdisplay =
164062306a36Sopenharmony_ci		    le16_to_cpu(lvds_info->info.sLCDTiming.usVActive);
164162306a36Sopenharmony_ci		lvds->native_mode.htotal = lvds->native_mode.hdisplay +
164262306a36Sopenharmony_ci			le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
164362306a36Sopenharmony_ci		lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
164462306a36Sopenharmony_ci			le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
164562306a36Sopenharmony_ci		lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
164662306a36Sopenharmony_ci			le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);
164762306a36Sopenharmony_ci		lvds->native_mode.vtotal = lvds->native_mode.vdisplay +
164862306a36Sopenharmony_ci			le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
164962306a36Sopenharmony_ci		lvds->native_mode.vsync_start = lvds->native_mode.vdisplay +
165062306a36Sopenharmony_ci			le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset);
165162306a36Sopenharmony_ci		lvds->native_mode.vsync_end = lvds->native_mode.vsync_start +
165262306a36Sopenharmony_ci			le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
165362306a36Sopenharmony_ci		lvds->panel_pwr_delay =
165462306a36Sopenharmony_ci		    le16_to_cpu(lvds_info->info.usOffDelayInMs);
165562306a36Sopenharmony_ci		lvds->lcd_misc = lvds_info->info.ucLVDS_Misc;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci		misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess);
165862306a36Sopenharmony_ci		if (misc & ATOM_VSYNC_POLARITY)
165962306a36Sopenharmony_ci			lvds->native_mode.flags |= DRM_MODE_FLAG_NVSYNC;
166062306a36Sopenharmony_ci		if (misc & ATOM_HSYNC_POLARITY)
166162306a36Sopenharmony_ci			lvds->native_mode.flags |= DRM_MODE_FLAG_NHSYNC;
166262306a36Sopenharmony_ci		if (misc & ATOM_COMPOSITESYNC)
166362306a36Sopenharmony_ci			lvds->native_mode.flags |= DRM_MODE_FLAG_CSYNC;
166462306a36Sopenharmony_ci		if (misc & ATOM_INTERLACE)
166562306a36Sopenharmony_ci			lvds->native_mode.flags |= DRM_MODE_FLAG_INTERLACE;
166662306a36Sopenharmony_ci		if (misc & ATOM_DOUBLE_CLOCK_MODE)
166762306a36Sopenharmony_ci			lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci		lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize);
167062306a36Sopenharmony_ci		lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci		/* set crtc values */
167362306a36Sopenharmony_ci		drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci		lvds->lcd_ss_id = lvds_info->info.ucSS_Id;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci		encoder->native_mode = lvds->native_mode;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci		if (encoder_enum == 2)
168062306a36Sopenharmony_ci			lvds->linkb = true;
168162306a36Sopenharmony_ci		else
168262306a36Sopenharmony_ci			lvds->linkb = false;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci		/* parse the lcd record table */
168562306a36Sopenharmony_ci		if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) {
168662306a36Sopenharmony_ci			ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
168762306a36Sopenharmony_ci			ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
168862306a36Sopenharmony_ci			bool bad_record = false;
168962306a36Sopenharmony_ci			u8 *record;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci			if ((frev == 1) && (crev < 2))
169262306a36Sopenharmony_ci				/* absolute */
169362306a36Sopenharmony_ci				record = (u8 *)(mode_info->atom_context->bios +
169462306a36Sopenharmony_ci						le16_to_cpu(lvds_info->info.usModePatchTableOffset));
169562306a36Sopenharmony_ci			else
169662306a36Sopenharmony_ci				/* relative */
169762306a36Sopenharmony_ci				record = (u8 *)(mode_info->atom_context->bios +
169862306a36Sopenharmony_ci						data_offset +
169962306a36Sopenharmony_ci						le16_to_cpu(lvds_info->info.usModePatchTableOffset));
170062306a36Sopenharmony_ci			while (*record != ATOM_RECORD_END_TYPE) {
170162306a36Sopenharmony_ci				switch (*record) {
170262306a36Sopenharmony_ci				case LCD_MODE_PATCH_RECORD_MODE_TYPE:
170362306a36Sopenharmony_ci					record += sizeof(ATOM_PATCH_RECORD_MODE);
170462306a36Sopenharmony_ci					break;
170562306a36Sopenharmony_ci				case LCD_RTS_RECORD_TYPE:
170662306a36Sopenharmony_ci					record += sizeof(ATOM_LCD_RTS_RECORD);
170762306a36Sopenharmony_ci					break;
170862306a36Sopenharmony_ci				case LCD_CAP_RECORD_TYPE:
170962306a36Sopenharmony_ci					record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
171062306a36Sopenharmony_ci					break;
171162306a36Sopenharmony_ci				case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
171262306a36Sopenharmony_ci					fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
171362306a36Sopenharmony_ci					if (fake_edid_record->ucFakeEDIDLength) {
171462306a36Sopenharmony_ci						struct edid *edid;
171562306a36Sopenharmony_ci						int edid_size =
171662306a36Sopenharmony_ci							max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength);
171762306a36Sopenharmony_ci						edid = kmalloc(edid_size, GFP_KERNEL);
171862306a36Sopenharmony_ci						if (edid) {
171962306a36Sopenharmony_ci							memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
172062306a36Sopenharmony_ci							       fake_edid_record->ucFakeEDIDLength);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci							if (drm_edid_is_valid(edid)) {
172362306a36Sopenharmony_ci								rdev->mode_info.bios_hardcoded_edid = edid;
172462306a36Sopenharmony_ci								rdev->mode_info.bios_hardcoded_edid_size = edid_size;
172562306a36Sopenharmony_ci							} else
172662306a36Sopenharmony_ci								kfree(edid);
172762306a36Sopenharmony_ci						}
172862306a36Sopenharmony_ci					}
172962306a36Sopenharmony_ci					record += fake_edid_record->ucFakeEDIDLength ?
173062306a36Sopenharmony_ci						  struct_size(fake_edid_record,
173162306a36Sopenharmony_ci							      ucFakeEDIDString,
173262306a36Sopenharmony_ci							      fake_edid_record->ucFakeEDIDLength) :
173362306a36Sopenharmony_ci						  /* empty fake edid record must be 3 bytes long */
173462306a36Sopenharmony_ci						  sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
173562306a36Sopenharmony_ci					break;
173662306a36Sopenharmony_ci				case LCD_PANEL_RESOLUTION_RECORD_TYPE:
173762306a36Sopenharmony_ci					panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
173862306a36Sopenharmony_ci					lvds->native_mode.width_mm = panel_res_record->usHSize;
173962306a36Sopenharmony_ci					lvds->native_mode.height_mm = panel_res_record->usVSize;
174062306a36Sopenharmony_ci					record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
174162306a36Sopenharmony_ci					break;
174262306a36Sopenharmony_ci				default:
174362306a36Sopenharmony_ci					DRM_ERROR("Bad LCD record %d\n", *record);
174462306a36Sopenharmony_ci					bad_record = true;
174562306a36Sopenharmony_ci					break;
174662306a36Sopenharmony_ci				}
174762306a36Sopenharmony_ci				if (bad_record)
174862306a36Sopenharmony_ci					break;
174962306a36Sopenharmony_ci			}
175062306a36Sopenharmony_ci		}
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci	return lvds;
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_cistruct radeon_encoder_primary_dac *
175662306a36Sopenharmony_ciradeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder)
175762306a36Sopenharmony_ci{
175862306a36Sopenharmony_ci	struct drm_device *dev = encoder->base.dev;
175962306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
176062306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
176162306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, CompassionateData);
176262306a36Sopenharmony_ci	uint16_t data_offset;
176362306a36Sopenharmony_ci	struct _COMPASSIONATE_DATA *dac_info;
176462306a36Sopenharmony_ci	uint8_t frev, crev;
176562306a36Sopenharmony_ci	uint8_t bg, dac;
176662306a36Sopenharmony_ci	struct radeon_encoder_primary_dac *p_dac = NULL;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
176962306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
177062306a36Sopenharmony_ci		dac_info = (struct _COMPASSIONATE_DATA *)
177162306a36Sopenharmony_ci			(mode_info->atom_context->bios + data_offset);
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci		p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), GFP_KERNEL);
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci		if (!p_dac)
177662306a36Sopenharmony_ci			return NULL;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci		bg = dac_info->ucDAC1_BG_Adjustment;
177962306a36Sopenharmony_ci		dac = dac_info->ucDAC1_DAC_Adjustment;
178062306a36Sopenharmony_ci		p_dac->ps2_pdac_adj = (bg << 8) | (dac);
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	}
178362306a36Sopenharmony_ci	return p_dac;
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_cibool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
178762306a36Sopenharmony_ci				struct drm_display_mode *mode)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
179062306a36Sopenharmony_ci	ATOM_ANALOG_TV_INFO *tv_info;
179162306a36Sopenharmony_ci	ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
179262306a36Sopenharmony_ci	ATOM_DTD_FORMAT *dtd_timings;
179362306a36Sopenharmony_ci	int data_index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
179462306a36Sopenharmony_ci	u8 frev, crev;
179562306a36Sopenharmony_ci	u16 data_offset, misc;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	if (!atom_parse_data_header(mode_info->atom_context, data_index, NULL,
179862306a36Sopenharmony_ci				    &frev, &crev, &data_offset))
179962306a36Sopenharmony_ci		return false;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	switch (crev) {
180262306a36Sopenharmony_ci	case 1:
180362306a36Sopenharmony_ci		tv_info = (ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset);
180462306a36Sopenharmony_ci		if (index >= MAX_SUPPORTED_TV_TIMING)
180562306a36Sopenharmony_ci			return false;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci		mode->crtc_htotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
180862306a36Sopenharmony_ci		mode->crtc_hdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
180962306a36Sopenharmony_ci		mode->crtc_hsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
181062306a36Sopenharmony_ci		mode->crtc_hsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) +
181162306a36Sopenharmony_ci			le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci		mode->crtc_vtotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
181462306a36Sopenharmony_ci		mode->crtc_vdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
181562306a36Sopenharmony_ci		mode->crtc_vsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
181662306a36Sopenharmony_ci		mode->crtc_vsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) +
181762306a36Sopenharmony_ci			le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci		mode->flags = 0;
182062306a36Sopenharmony_ci		misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess);
182162306a36Sopenharmony_ci		if (misc & ATOM_VSYNC_POLARITY)
182262306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_NVSYNC;
182362306a36Sopenharmony_ci		if (misc & ATOM_HSYNC_POLARITY)
182462306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_NHSYNC;
182562306a36Sopenharmony_ci		if (misc & ATOM_COMPOSITESYNC)
182662306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_CSYNC;
182762306a36Sopenharmony_ci		if (misc & ATOM_INTERLACE)
182862306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_INTERLACE;
182962306a36Sopenharmony_ci		if (misc & ATOM_DOUBLE_CLOCK_MODE)
183062306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_DBLSCAN;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci		mode->crtc_clock = mode->clock =
183362306a36Sopenharmony_ci			le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci		if (index == 1) {
183662306a36Sopenharmony_ci			/* PAL timings appear to have wrong values for totals */
183762306a36Sopenharmony_ci			mode->crtc_htotal -= 1;
183862306a36Sopenharmony_ci			mode->crtc_vtotal -= 1;
183962306a36Sopenharmony_ci		}
184062306a36Sopenharmony_ci		break;
184162306a36Sopenharmony_ci	case 2:
184262306a36Sopenharmony_ci		tv_info_v1_2 = (ATOM_ANALOG_TV_INFO_V1_2 *)(mode_info->atom_context->bios + data_offset);
184362306a36Sopenharmony_ci		if (index >= MAX_SUPPORTED_TV_TIMING_V1_2)
184462306a36Sopenharmony_ci			return false;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci		dtd_timings = &tv_info_v1_2->aModeTimings[index];
184762306a36Sopenharmony_ci		mode->crtc_htotal = le16_to_cpu(dtd_timings->usHActive) +
184862306a36Sopenharmony_ci			le16_to_cpu(dtd_timings->usHBlanking_Time);
184962306a36Sopenharmony_ci		mode->crtc_hdisplay = le16_to_cpu(dtd_timings->usHActive);
185062306a36Sopenharmony_ci		mode->crtc_hsync_start = le16_to_cpu(dtd_timings->usHActive) +
185162306a36Sopenharmony_ci			le16_to_cpu(dtd_timings->usHSyncOffset);
185262306a36Sopenharmony_ci		mode->crtc_hsync_end = mode->crtc_hsync_start +
185362306a36Sopenharmony_ci			le16_to_cpu(dtd_timings->usHSyncWidth);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci		mode->crtc_vtotal = le16_to_cpu(dtd_timings->usVActive) +
185662306a36Sopenharmony_ci			le16_to_cpu(dtd_timings->usVBlanking_Time);
185762306a36Sopenharmony_ci		mode->crtc_vdisplay = le16_to_cpu(dtd_timings->usVActive);
185862306a36Sopenharmony_ci		mode->crtc_vsync_start = le16_to_cpu(dtd_timings->usVActive) +
185962306a36Sopenharmony_ci			le16_to_cpu(dtd_timings->usVSyncOffset);
186062306a36Sopenharmony_ci		mode->crtc_vsync_end = mode->crtc_vsync_start +
186162306a36Sopenharmony_ci			le16_to_cpu(dtd_timings->usVSyncWidth);
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci		mode->flags = 0;
186462306a36Sopenharmony_ci		misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
186562306a36Sopenharmony_ci		if (misc & ATOM_VSYNC_POLARITY)
186662306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_NVSYNC;
186762306a36Sopenharmony_ci		if (misc & ATOM_HSYNC_POLARITY)
186862306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_NHSYNC;
186962306a36Sopenharmony_ci		if (misc & ATOM_COMPOSITESYNC)
187062306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_CSYNC;
187162306a36Sopenharmony_ci		if (misc & ATOM_INTERLACE)
187262306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_INTERLACE;
187362306a36Sopenharmony_ci		if (misc & ATOM_DOUBLE_CLOCK_MODE)
187462306a36Sopenharmony_ci			mode->flags |= DRM_MODE_FLAG_DBLSCAN;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci		mode->crtc_clock = mode->clock =
187762306a36Sopenharmony_ci			le16_to_cpu(dtd_timings->usPixClk) * 10;
187862306a36Sopenharmony_ci		break;
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci	return true;
188162306a36Sopenharmony_ci}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_cienum radeon_tv_std
188462306a36Sopenharmony_ciradeon_atombios_get_tv_info(struct radeon_device *rdev)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
188762306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
188862306a36Sopenharmony_ci	uint16_t data_offset;
188962306a36Sopenharmony_ci	uint8_t frev, crev;
189062306a36Sopenharmony_ci	struct _ATOM_ANALOG_TV_INFO *tv_info;
189162306a36Sopenharmony_ci	enum radeon_tv_std tv_std = TV_STD_NTSC;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
189462306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci		tv_info = (struct _ATOM_ANALOG_TV_INFO *)
189762306a36Sopenharmony_ci			(mode_info->atom_context->bios + data_offset);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci		switch (tv_info->ucTV_BootUpDefaultStandard) {
190062306a36Sopenharmony_ci		case ATOM_TV_NTSC:
190162306a36Sopenharmony_ci			tv_std = TV_STD_NTSC;
190262306a36Sopenharmony_ci			DRM_DEBUG_KMS("Default TV standard: NTSC\n");
190362306a36Sopenharmony_ci			break;
190462306a36Sopenharmony_ci		case ATOM_TV_NTSCJ:
190562306a36Sopenharmony_ci			tv_std = TV_STD_NTSC_J;
190662306a36Sopenharmony_ci			DRM_DEBUG_KMS("Default TV standard: NTSC-J\n");
190762306a36Sopenharmony_ci			break;
190862306a36Sopenharmony_ci		case ATOM_TV_PAL:
190962306a36Sopenharmony_ci			tv_std = TV_STD_PAL;
191062306a36Sopenharmony_ci			DRM_DEBUG_KMS("Default TV standard: PAL\n");
191162306a36Sopenharmony_ci			break;
191262306a36Sopenharmony_ci		case ATOM_TV_PALM:
191362306a36Sopenharmony_ci			tv_std = TV_STD_PAL_M;
191462306a36Sopenharmony_ci			DRM_DEBUG_KMS("Default TV standard: PAL-M\n");
191562306a36Sopenharmony_ci			break;
191662306a36Sopenharmony_ci		case ATOM_TV_PALN:
191762306a36Sopenharmony_ci			tv_std = TV_STD_PAL_N;
191862306a36Sopenharmony_ci			DRM_DEBUG_KMS("Default TV standard: PAL-N\n");
191962306a36Sopenharmony_ci			break;
192062306a36Sopenharmony_ci		case ATOM_TV_PALCN:
192162306a36Sopenharmony_ci			tv_std = TV_STD_PAL_CN;
192262306a36Sopenharmony_ci			DRM_DEBUG_KMS("Default TV standard: PAL-CN\n");
192362306a36Sopenharmony_ci			break;
192462306a36Sopenharmony_ci		case ATOM_TV_PAL60:
192562306a36Sopenharmony_ci			tv_std = TV_STD_PAL_60;
192662306a36Sopenharmony_ci			DRM_DEBUG_KMS("Default TV standard: PAL-60\n");
192762306a36Sopenharmony_ci			break;
192862306a36Sopenharmony_ci		case ATOM_TV_SECAM:
192962306a36Sopenharmony_ci			tv_std = TV_STD_SECAM;
193062306a36Sopenharmony_ci			DRM_DEBUG_KMS("Default TV standard: SECAM\n");
193162306a36Sopenharmony_ci			break;
193262306a36Sopenharmony_ci		default:
193362306a36Sopenharmony_ci			tv_std = TV_STD_NTSC;
193462306a36Sopenharmony_ci			DRM_DEBUG_KMS("Unknown TV standard; defaulting to NTSC\n");
193562306a36Sopenharmony_ci			break;
193662306a36Sopenharmony_ci		}
193762306a36Sopenharmony_ci	}
193862306a36Sopenharmony_ci	return tv_std;
193962306a36Sopenharmony_ci}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_cistruct radeon_encoder_tv_dac *
194262306a36Sopenharmony_ciradeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
194362306a36Sopenharmony_ci{
194462306a36Sopenharmony_ci	struct drm_device *dev = encoder->base.dev;
194562306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
194662306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
194762306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, CompassionateData);
194862306a36Sopenharmony_ci	uint16_t data_offset;
194962306a36Sopenharmony_ci	struct _COMPASSIONATE_DATA *dac_info;
195062306a36Sopenharmony_ci	uint8_t frev, crev;
195162306a36Sopenharmony_ci	uint8_t bg, dac;
195262306a36Sopenharmony_ci	struct radeon_encoder_tv_dac *tv_dac = NULL;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
195562306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci		dac_info = (struct _COMPASSIONATE_DATA *)
195862306a36Sopenharmony_ci			(mode_info->atom_context->bios + data_offset);
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci		tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL);
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci		if (!tv_dac)
196362306a36Sopenharmony_ci			return NULL;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci		bg = dac_info->ucDAC2_CRT2_BG_Adjustment;
196662306a36Sopenharmony_ci		dac = dac_info->ucDAC2_CRT2_DAC_Adjustment;
196762306a36Sopenharmony_ci		tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci		bg = dac_info->ucDAC2_PAL_BG_Adjustment;
197062306a36Sopenharmony_ci		dac = dac_info->ucDAC2_PAL_DAC_Adjustment;
197162306a36Sopenharmony_ci		tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci		bg = dac_info->ucDAC2_NTSC_BG_Adjustment;
197462306a36Sopenharmony_ci		dac = dac_info->ucDAC2_NTSC_DAC_Adjustment;
197562306a36Sopenharmony_ci		tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci		tv_dac->tv_std = radeon_atombios_get_tv_info(rdev);
197862306a36Sopenharmony_ci	}
197962306a36Sopenharmony_ci	return tv_dac;
198062306a36Sopenharmony_ci}
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_cistatic const char *thermal_controller_names[] = {
198362306a36Sopenharmony_ci	"NONE",
198462306a36Sopenharmony_ci	"lm63",
198562306a36Sopenharmony_ci	"adm1032",
198662306a36Sopenharmony_ci	"adm1030",
198762306a36Sopenharmony_ci	"max6649",
198862306a36Sopenharmony_ci	"lm63", /* lm64 */
198962306a36Sopenharmony_ci	"f75375",
199062306a36Sopenharmony_ci	"asc7xxx",
199162306a36Sopenharmony_ci};
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_cistatic const char *pp_lib_thermal_controller_names[] = {
199462306a36Sopenharmony_ci	"NONE",
199562306a36Sopenharmony_ci	"lm63",
199662306a36Sopenharmony_ci	"adm1032",
199762306a36Sopenharmony_ci	"adm1030",
199862306a36Sopenharmony_ci	"max6649",
199962306a36Sopenharmony_ci	"lm63", /* lm64 */
200062306a36Sopenharmony_ci	"f75375",
200162306a36Sopenharmony_ci	"RV6xx",
200262306a36Sopenharmony_ci	"RV770",
200362306a36Sopenharmony_ci	"adt7473",
200462306a36Sopenharmony_ci	"NONE",
200562306a36Sopenharmony_ci	"External GPIO",
200662306a36Sopenharmony_ci	"Evergreen",
200762306a36Sopenharmony_ci	"emc2103",
200862306a36Sopenharmony_ci	"Sumo",
200962306a36Sopenharmony_ci	"Northern Islands",
201062306a36Sopenharmony_ci	"Southern Islands",
201162306a36Sopenharmony_ci	"lm96163",
201262306a36Sopenharmony_ci	"Sea Islands",
201362306a36Sopenharmony_ci};
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ciunion power_info {
201662306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO info;
201762306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V2 info_2;
201862306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V3 info_3;
201962306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
202062306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
202162306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
202262306a36Sopenharmony_ci};
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ciunion pplib_clock_info {
202562306a36Sopenharmony_ci	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
202662306a36Sopenharmony_ci	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
202762306a36Sopenharmony_ci	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
202862306a36Sopenharmony_ci	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
202962306a36Sopenharmony_ci	struct _ATOM_PPLIB_SI_CLOCK_INFO si;
203062306a36Sopenharmony_ci	struct _ATOM_PPLIB_CI_CLOCK_INFO ci;
203162306a36Sopenharmony_ci};
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ciunion pplib_power_state {
203462306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE v1;
203562306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE_V2 v2;
203662306a36Sopenharmony_ci};
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_cistatic void radeon_atombios_parse_misc_flags_1_3(struct radeon_device *rdev,
203962306a36Sopenharmony_ci						 int state_index,
204062306a36Sopenharmony_ci						 u32 misc, u32 misc2)
204162306a36Sopenharmony_ci{
204262306a36Sopenharmony_ci	rdev->pm.power_state[state_index].misc = misc;
204362306a36Sopenharmony_ci	rdev->pm.power_state[state_index].misc2 = misc2;
204462306a36Sopenharmony_ci	/* order matters! */
204562306a36Sopenharmony_ci	if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
204662306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
204762306a36Sopenharmony_ci			POWER_STATE_TYPE_POWERSAVE;
204862306a36Sopenharmony_ci	if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
204962306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
205062306a36Sopenharmony_ci			POWER_STATE_TYPE_BATTERY;
205162306a36Sopenharmony_ci	if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
205262306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
205362306a36Sopenharmony_ci			POWER_STATE_TYPE_BATTERY;
205462306a36Sopenharmony_ci	if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
205562306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
205662306a36Sopenharmony_ci			POWER_STATE_TYPE_BALANCED;
205762306a36Sopenharmony_ci	if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
205862306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
205962306a36Sopenharmony_ci			POWER_STATE_TYPE_PERFORMANCE;
206062306a36Sopenharmony_ci		rdev->pm.power_state[state_index].flags &=
206162306a36Sopenharmony_ci			~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
206262306a36Sopenharmony_ci	}
206362306a36Sopenharmony_ci	if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
206462306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
206562306a36Sopenharmony_ci			POWER_STATE_TYPE_BALANCED;
206662306a36Sopenharmony_ci	if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
206762306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
206862306a36Sopenharmony_ci			POWER_STATE_TYPE_DEFAULT;
206962306a36Sopenharmony_ci		rdev->pm.default_power_state_index = state_index;
207062306a36Sopenharmony_ci		rdev->pm.power_state[state_index].default_clock_mode =
207162306a36Sopenharmony_ci			&rdev->pm.power_state[state_index].clock_info[0];
207262306a36Sopenharmony_ci	} else if (state_index == 0) {
207362306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[0].flags |=
207462306a36Sopenharmony_ci			RADEON_PM_MODE_NO_DISPLAY;
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cistatic int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
207962306a36Sopenharmony_ci{
208062306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
208162306a36Sopenharmony_ci	u32 misc, misc2 = 0;
208262306a36Sopenharmony_ci	int num_modes = 0, i;
208362306a36Sopenharmony_ci	int state_index = 0;
208462306a36Sopenharmony_ci	struct radeon_i2c_bus_rec i2c_bus;
208562306a36Sopenharmony_ci	union power_info *power_info;
208662306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
208762306a36Sopenharmony_ci	u16 data_offset;
208862306a36Sopenharmony_ci	u8 frev, crev;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
209162306a36Sopenharmony_ci				   &frev, &crev, &data_offset))
209262306a36Sopenharmony_ci		return state_index;
209362306a36Sopenharmony_ci	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	/* add the i2c bus for thermal/fan chip */
209662306a36Sopenharmony_ci	if ((power_info->info.ucOverdriveThermalController > 0) &&
209762306a36Sopenharmony_ci	    (power_info->info.ucOverdriveThermalController < ARRAY_SIZE(thermal_controller_names))) {
209862306a36Sopenharmony_ci		DRM_INFO("Possible %s thermal controller at 0x%02x\n",
209962306a36Sopenharmony_ci			 thermal_controller_names[power_info->info.ucOverdriveThermalController],
210062306a36Sopenharmony_ci			 power_info->info.ucOverdriveControllerAddress >> 1);
210162306a36Sopenharmony_ci		i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
210262306a36Sopenharmony_ci		rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
210362306a36Sopenharmony_ci		if (rdev->pm.i2c_bus) {
210462306a36Sopenharmony_ci			struct i2c_board_info info = { };
210562306a36Sopenharmony_ci			const char *name = thermal_controller_names[power_info->info.
210662306a36Sopenharmony_ci								    ucOverdriveThermalController];
210762306a36Sopenharmony_ci			info.addr = power_info->info.ucOverdriveControllerAddress >> 1;
210862306a36Sopenharmony_ci			strscpy(info.type, name, sizeof(info.type));
210962306a36Sopenharmony_ci			i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info);
211062306a36Sopenharmony_ci		}
211162306a36Sopenharmony_ci	}
211262306a36Sopenharmony_ci	num_modes = power_info->info.ucNumOfPowerModeEntries;
211362306a36Sopenharmony_ci	if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
211462306a36Sopenharmony_ci		num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
211562306a36Sopenharmony_ci	if (num_modes == 0)
211662306a36Sopenharmony_ci		return state_index;
211762306a36Sopenharmony_ci	rdev->pm.power_state = kcalloc(num_modes,
211862306a36Sopenharmony_ci				       sizeof(struct radeon_power_state),
211962306a36Sopenharmony_ci				       GFP_KERNEL);
212062306a36Sopenharmony_ci	if (!rdev->pm.power_state)
212162306a36Sopenharmony_ci		return state_index;
212262306a36Sopenharmony_ci	/* last mode is usually default, array is low to high */
212362306a36Sopenharmony_ci	for (i = 0; i < num_modes; i++) {
212462306a36Sopenharmony_ci		/* avoid memory leaks from invalid modes or unknown frev. */
212562306a36Sopenharmony_ci		if (!rdev->pm.power_state[state_index].clock_info) {
212662306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info =
212762306a36Sopenharmony_ci				kzalloc(sizeof(struct radeon_pm_clock_info),
212862306a36Sopenharmony_ci					GFP_KERNEL);
212962306a36Sopenharmony_ci		}
213062306a36Sopenharmony_ci		if (!rdev->pm.power_state[state_index].clock_info)
213162306a36Sopenharmony_ci			goto out;
213262306a36Sopenharmony_ci		rdev->pm.power_state[state_index].num_clock_modes = 1;
213362306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
213462306a36Sopenharmony_ci		switch (frev) {
213562306a36Sopenharmony_ci		case 1:
213662306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].mclk =
213762306a36Sopenharmony_ci				le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock);
213862306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].sclk =
213962306a36Sopenharmony_ci				le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock);
214062306a36Sopenharmony_ci			/* skip invalid modes */
214162306a36Sopenharmony_ci			if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
214262306a36Sopenharmony_ci			    (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
214362306a36Sopenharmony_ci				continue;
214462306a36Sopenharmony_ci			rdev->pm.power_state[state_index].pcie_lanes =
214562306a36Sopenharmony_ci				power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
214662306a36Sopenharmony_ci			misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
214762306a36Sopenharmony_ci			if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
214862306a36Sopenharmony_ci			    (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
214962306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
215062306a36Sopenharmony_ci					VOLTAGE_GPIO;
215162306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
215262306a36Sopenharmony_ci					radeon_atombios_lookup_gpio(rdev,
215362306a36Sopenharmony_ci							   power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
215462306a36Sopenharmony_ci				if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
215562306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
215662306a36Sopenharmony_ci						true;
215762306a36Sopenharmony_ci				else
215862306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
215962306a36Sopenharmony_ci						false;
216062306a36Sopenharmony_ci			} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
216162306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
216262306a36Sopenharmony_ci					VOLTAGE_VDDC;
216362306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
216462306a36Sopenharmony_ci					power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
216562306a36Sopenharmony_ci			}
216662306a36Sopenharmony_ci			rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
216762306a36Sopenharmony_ci			radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0);
216862306a36Sopenharmony_ci			state_index++;
216962306a36Sopenharmony_ci			break;
217062306a36Sopenharmony_ci		case 2:
217162306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].mclk =
217262306a36Sopenharmony_ci				le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
217362306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].sclk =
217462306a36Sopenharmony_ci				le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock);
217562306a36Sopenharmony_ci			/* skip invalid modes */
217662306a36Sopenharmony_ci			if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
217762306a36Sopenharmony_ci			    (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
217862306a36Sopenharmony_ci				continue;
217962306a36Sopenharmony_ci			rdev->pm.power_state[state_index].pcie_lanes =
218062306a36Sopenharmony_ci				power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
218162306a36Sopenharmony_ci			misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
218262306a36Sopenharmony_ci			misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
218362306a36Sopenharmony_ci			if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
218462306a36Sopenharmony_ci			    (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
218562306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
218662306a36Sopenharmony_ci					VOLTAGE_GPIO;
218762306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
218862306a36Sopenharmony_ci					radeon_atombios_lookup_gpio(rdev,
218962306a36Sopenharmony_ci							   power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
219062306a36Sopenharmony_ci				if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
219162306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
219262306a36Sopenharmony_ci						true;
219362306a36Sopenharmony_ci				else
219462306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
219562306a36Sopenharmony_ci						false;
219662306a36Sopenharmony_ci			} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
219762306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
219862306a36Sopenharmony_ci					VOLTAGE_VDDC;
219962306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
220062306a36Sopenharmony_ci					power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
220162306a36Sopenharmony_ci			}
220262306a36Sopenharmony_ci			rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
220362306a36Sopenharmony_ci			radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
220462306a36Sopenharmony_ci			state_index++;
220562306a36Sopenharmony_ci			break;
220662306a36Sopenharmony_ci		case 3:
220762306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].mclk =
220862306a36Sopenharmony_ci				le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
220962306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].sclk =
221062306a36Sopenharmony_ci				le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock);
221162306a36Sopenharmony_ci			/* skip invalid modes */
221262306a36Sopenharmony_ci			if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
221362306a36Sopenharmony_ci			    (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
221462306a36Sopenharmony_ci				continue;
221562306a36Sopenharmony_ci			rdev->pm.power_state[state_index].pcie_lanes =
221662306a36Sopenharmony_ci				power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
221762306a36Sopenharmony_ci			misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
221862306a36Sopenharmony_ci			misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2);
221962306a36Sopenharmony_ci			if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
222062306a36Sopenharmony_ci			    (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
222162306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
222262306a36Sopenharmony_ci					VOLTAGE_GPIO;
222362306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
222462306a36Sopenharmony_ci					radeon_atombios_lookup_gpio(rdev,
222562306a36Sopenharmony_ci							   power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
222662306a36Sopenharmony_ci				if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
222762306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
222862306a36Sopenharmony_ci						true;
222962306a36Sopenharmony_ci				else
223062306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
223162306a36Sopenharmony_ci						false;
223262306a36Sopenharmony_ci			} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
223362306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
223462306a36Sopenharmony_ci					VOLTAGE_VDDC;
223562306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
223662306a36Sopenharmony_ci					power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex;
223762306a36Sopenharmony_ci				if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) {
223862306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled =
223962306a36Sopenharmony_ci						true;
224062306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id =
224162306a36Sopenharmony_ci						power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
224262306a36Sopenharmony_ci				}
224362306a36Sopenharmony_ci			}
224462306a36Sopenharmony_ci			rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
224562306a36Sopenharmony_ci			radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
224662306a36Sopenharmony_ci			state_index++;
224762306a36Sopenharmony_ci			break;
224862306a36Sopenharmony_ci		}
224962306a36Sopenharmony_ci	}
225062306a36Sopenharmony_ciout:
225162306a36Sopenharmony_ci	/* free any unused clock_info allocation. */
225262306a36Sopenharmony_ci	if (state_index && state_index < num_modes) {
225362306a36Sopenharmony_ci		kfree(rdev->pm.power_state[state_index].clock_info);
225462306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info = NULL;
225562306a36Sopenharmony_ci	}
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	/* last mode is usually default */
225862306a36Sopenharmony_ci	if (state_index && rdev->pm.default_power_state_index == -1) {
225962306a36Sopenharmony_ci		rdev->pm.power_state[state_index - 1].type =
226062306a36Sopenharmony_ci			POWER_STATE_TYPE_DEFAULT;
226162306a36Sopenharmony_ci		rdev->pm.default_power_state_index = state_index - 1;
226262306a36Sopenharmony_ci		rdev->pm.power_state[state_index - 1].default_clock_mode =
226362306a36Sopenharmony_ci			&rdev->pm.power_state[state_index - 1].clock_info[0];
226462306a36Sopenharmony_ci		rdev->pm.power_state[state_index - 1].flags &=
226562306a36Sopenharmony_ci			~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
226662306a36Sopenharmony_ci		rdev->pm.power_state[state_index - 1].misc = 0;
226762306a36Sopenharmony_ci		rdev->pm.power_state[state_index - 1].misc2 = 0;
226862306a36Sopenharmony_ci	}
226962306a36Sopenharmony_ci	return state_index;
227062306a36Sopenharmony_ci}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_cistatic void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *rdev,
227362306a36Sopenharmony_ci							 ATOM_PPLIB_THERMALCONTROLLER *controller)
227462306a36Sopenharmony_ci{
227562306a36Sopenharmony_ci	struct radeon_i2c_bus_rec i2c_bus;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	/* add the i2c bus for thermal/fan chip */
227862306a36Sopenharmony_ci	if (controller->ucType > 0) {
227962306a36Sopenharmony_ci		if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN)
228062306a36Sopenharmony_ci			rdev->pm.no_fan = true;
228162306a36Sopenharmony_ci		rdev->pm.fan_pulses_per_revolution =
228262306a36Sopenharmony_ci			controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
228362306a36Sopenharmony_ci		if (rdev->pm.fan_pulses_per_revolution) {
228462306a36Sopenharmony_ci			rdev->pm.fan_min_rpm = controller->ucFanMinRPM;
228562306a36Sopenharmony_ci			rdev->pm.fan_max_rpm = controller->ucFanMaxRPM;
228662306a36Sopenharmony_ci		}
228762306a36Sopenharmony_ci		if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
228862306a36Sopenharmony_ci			DRM_INFO("Internal thermal controller %s fan control\n",
228962306a36Sopenharmony_ci				 (controller->ucFanParameters &
229062306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
229162306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
229262306a36Sopenharmony_ci		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
229362306a36Sopenharmony_ci			DRM_INFO("Internal thermal controller %s fan control\n",
229462306a36Sopenharmony_ci				 (controller->ucFanParameters &
229562306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
229662306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_RV770;
229762306a36Sopenharmony_ci		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
229862306a36Sopenharmony_ci			DRM_INFO("Internal thermal controller %s fan control\n",
229962306a36Sopenharmony_ci				 (controller->ucFanParameters &
230062306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
230162306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
230262306a36Sopenharmony_ci		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
230362306a36Sopenharmony_ci			DRM_INFO("Internal thermal controller %s fan control\n",
230462306a36Sopenharmony_ci				 (controller->ucFanParameters &
230562306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
230662306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_SUMO;
230762306a36Sopenharmony_ci		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
230862306a36Sopenharmony_ci			DRM_INFO("Internal thermal controller %s fan control\n",
230962306a36Sopenharmony_ci				 (controller->ucFanParameters &
231062306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
231162306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_NI;
231262306a36Sopenharmony_ci		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
231362306a36Sopenharmony_ci			DRM_INFO("Internal thermal controller %s fan control\n",
231462306a36Sopenharmony_ci				 (controller->ucFanParameters &
231562306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
231662306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_SI;
231762306a36Sopenharmony_ci		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
231862306a36Sopenharmony_ci			DRM_INFO("Internal thermal controller %s fan control\n",
231962306a36Sopenharmony_ci				 (controller->ucFanParameters &
232062306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
232162306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_CI;
232262306a36Sopenharmony_ci		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) {
232362306a36Sopenharmony_ci			DRM_INFO("Internal thermal controller %s fan control\n",
232462306a36Sopenharmony_ci				 (controller->ucFanParameters &
232562306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
232662306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_KV;
232762306a36Sopenharmony_ci		} else if (controller->ucType ==
232862306a36Sopenharmony_ci			   ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) {
232962306a36Sopenharmony_ci			DRM_INFO("External GPIO thermal controller %s fan control\n",
233062306a36Sopenharmony_ci				 (controller->ucFanParameters &
233162306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
233262306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO;
233362306a36Sopenharmony_ci		} else if (controller->ucType ==
233462306a36Sopenharmony_ci			   ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) {
233562306a36Sopenharmony_ci			DRM_INFO("ADT7473 with internal thermal controller %s fan control\n",
233662306a36Sopenharmony_ci				 (controller->ucFanParameters &
233762306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
233862306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL;
233962306a36Sopenharmony_ci		} else if (controller->ucType ==
234062306a36Sopenharmony_ci			   ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) {
234162306a36Sopenharmony_ci			DRM_INFO("EMC2103 with internal thermal controller %s fan control\n",
234262306a36Sopenharmony_ci				 (controller->ucFanParameters &
234362306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
234462306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL;
234562306a36Sopenharmony_ci		} else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
234662306a36Sopenharmony_ci			DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
234762306a36Sopenharmony_ci				 pp_lib_thermal_controller_names[controller->ucType],
234862306a36Sopenharmony_ci				 controller->ucI2cAddress >> 1,
234962306a36Sopenharmony_ci				 (controller->ucFanParameters &
235062306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
235162306a36Sopenharmony_ci			rdev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL;
235262306a36Sopenharmony_ci			i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
235362306a36Sopenharmony_ci			rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
235462306a36Sopenharmony_ci			if (rdev->pm.i2c_bus) {
235562306a36Sopenharmony_ci				struct i2c_board_info info = { };
235662306a36Sopenharmony_ci				const char *name = pp_lib_thermal_controller_names[controller->ucType];
235762306a36Sopenharmony_ci				info.addr = controller->ucI2cAddress >> 1;
235862306a36Sopenharmony_ci				strscpy(info.type, name, sizeof(info.type));
235962306a36Sopenharmony_ci				i2c_new_client_device(&rdev->pm.i2c_bus->adapter, &info);
236062306a36Sopenharmony_ci			}
236162306a36Sopenharmony_ci		} else {
236262306a36Sopenharmony_ci			DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n",
236362306a36Sopenharmony_ci				 controller->ucType,
236462306a36Sopenharmony_ci				 controller->ucI2cAddress >> 1,
236562306a36Sopenharmony_ci				 (controller->ucFanParameters &
236662306a36Sopenharmony_ci				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
236762306a36Sopenharmony_ci		}
236862306a36Sopenharmony_ci	}
236962306a36Sopenharmony_ci}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_civoid radeon_atombios_get_default_voltages(struct radeon_device *rdev,
237262306a36Sopenharmony_ci					  u16 *vddc, u16 *vddci, u16 *mvdd)
237362306a36Sopenharmony_ci{
237462306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
237562306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
237662306a36Sopenharmony_ci	u8 frev, crev;
237762306a36Sopenharmony_ci	u16 data_offset;
237862306a36Sopenharmony_ci	union firmware_info *firmware_info;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	*vddc = 0;
238162306a36Sopenharmony_ci	*vddci = 0;
238262306a36Sopenharmony_ci	*mvdd = 0;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
238562306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
238662306a36Sopenharmony_ci		firmware_info =
238762306a36Sopenharmony_ci			(union firmware_info *)(mode_info->atom_context->bios +
238862306a36Sopenharmony_ci						data_offset);
238962306a36Sopenharmony_ci		*vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
239062306a36Sopenharmony_ci		if ((frev == 2) && (crev >= 2)) {
239162306a36Sopenharmony_ci			*vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);
239262306a36Sopenharmony_ci			*mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage);
239362306a36Sopenharmony_ci		}
239462306a36Sopenharmony_ci	}
239562306a36Sopenharmony_ci}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_cistatic void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev,
239862306a36Sopenharmony_ci						       int state_index, int mode_index,
239962306a36Sopenharmony_ci						       struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info)
240062306a36Sopenharmony_ci{
240162306a36Sopenharmony_ci	int j;
240262306a36Sopenharmony_ci	u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
240362306a36Sopenharmony_ci	u32 misc2 = le16_to_cpu(non_clock_info->usClassification);
240462306a36Sopenharmony_ci	u16 vddc, vddci, mvdd;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd);
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	rdev->pm.power_state[state_index].misc = misc;
240962306a36Sopenharmony_ci	rdev->pm.power_state[state_index].misc2 = misc2;
241062306a36Sopenharmony_ci	rdev->pm.power_state[state_index].pcie_lanes =
241162306a36Sopenharmony_ci		((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
241262306a36Sopenharmony_ci		 ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
241362306a36Sopenharmony_ci	switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
241462306a36Sopenharmony_ci	case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
241562306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
241662306a36Sopenharmony_ci			POWER_STATE_TYPE_BATTERY;
241762306a36Sopenharmony_ci		break;
241862306a36Sopenharmony_ci	case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
241962306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
242062306a36Sopenharmony_ci			POWER_STATE_TYPE_BALANCED;
242162306a36Sopenharmony_ci		break;
242262306a36Sopenharmony_ci	case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
242362306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
242462306a36Sopenharmony_ci			POWER_STATE_TYPE_PERFORMANCE;
242562306a36Sopenharmony_ci		break;
242662306a36Sopenharmony_ci	case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
242762306a36Sopenharmony_ci		if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
242862306a36Sopenharmony_ci			rdev->pm.power_state[state_index].type =
242962306a36Sopenharmony_ci				POWER_STATE_TYPE_PERFORMANCE;
243062306a36Sopenharmony_ci		break;
243162306a36Sopenharmony_ci	}
243262306a36Sopenharmony_ci	rdev->pm.power_state[state_index].flags = 0;
243362306a36Sopenharmony_ci	if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
243462306a36Sopenharmony_ci		rdev->pm.power_state[state_index].flags |=
243562306a36Sopenharmony_ci			RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
243662306a36Sopenharmony_ci	if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
243762306a36Sopenharmony_ci		rdev->pm.power_state[state_index].type =
243862306a36Sopenharmony_ci			POWER_STATE_TYPE_DEFAULT;
243962306a36Sopenharmony_ci		rdev->pm.default_power_state_index = state_index;
244062306a36Sopenharmony_ci		rdev->pm.power_state[state_index].default_clock_mode =
244162306a36Sopenharmony_ci			&rdev->pm.power_state[state_index].clock_info[mode_index - 1];
244262306a36Sopenharmony_ci		if ((rdev->family >= CHIP_BARTS) && !(rdev->flags & RADEON_IS_IGP)) {
244362306a36Sopenharmony_ci			/* NI chips post without MC ucode, so default clocks are strobe mode only */
244462306a36Sopenharmony_ci			rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk;
244562306a36Sopenharmony_ci			rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk;
244662306a36Sopenharmony_ci			rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage;
244762306a36Sopenharmony_ci			rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci;
244862306a36Sopenharmony_ci		} else {
244962306a36Sopenharmony_ci			u16 max_vddci = 0;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci			if (ASIC_IS_DCE4(rdev))
245262306a36Sopenharmony_ci				radeon_atom_get_max_voltage(rdev,
245362306a36Sopenharmony_ci							    SET_VOLTAGE_TYPE_ASIC_VDDCI,
245462306a36Sopenharmony_ci							    &max_vddci);
245562306a36Sopenharmony_ci			/* patch the table values with the default sclk/mclk from firmware info */
245662306a36Sopenharmony_ci			for (j = 0; j < mode_index; j++) {
245762306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[j].mclk =
245862306a36Sopenharmony_ci					rdev->clock.default_mclk;
245962306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[j].sclk =
246062306a36Sopenharmony_ci					rdev->clock.default_sclk;
246162306a36Sopenharmony_ci				if (vddc)
246262306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
246362306a36Sopenharmony_ci						vddc;
246462306a36Sopenharmony_ci				if (max_vddci)
246562306a36Sopenharmony_ci					rdev->pm.power_state[state_index].clock_info[j].voltage.vddci =
246662306a36Sopenharmony_ci						max_vddci;
246762306a36Sopenharmony_ci			}
246862306a36Sopenharmony_ci		}
246962306a36Sopenharmony_ci	}
247062306a36Sopenharmony_ci}
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_cistatic bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
247362306a36Sopenharmony_ci						   int state_index, int mode_index,
247462306a36Sopenharmony_ci						   union pplib_clock_info *clock_info)
247562306a36Sopenharmony_ci{
247662306a36Sopenharmony_ci	u32 sclk, mclk;
247762306a36Sopenharmony_ci	u16 vddc;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_IGP) {
248062306a36Sopenharmony_ci		if (rdev->family >= CHIP_PALM) {
248162306a36Sopenharmony_ci			sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
248262306a36Sopenharmony_ci			sclk |= clock_info->sumo.ucEngineClockHigh << 16;
248362306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
248462306a36Sopenharmony_ci		} else {
248562306a36Sopenharmony_ci			sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
248662306a36Sopenharmony_ci			sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
248762306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
248862306a36Sopenharmony_ci		}
248962306a36Sopenharmony_ci	} else if (rdev->family >= CHIP_BONAIRE) {
249062306a36Sopenharmony_ci		sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
249162306a36Sopenharmony_ci		sclk |= clock_info->ci.ucEngineClockHigh << 16;
249262306a36Sopenharmony_ci		mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
249362306a36Sopenharmony_ci		mclk |= clock_info->ci.ucMemoryClockHigh << 16;
249462306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
249562306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
249662306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
249762306a36Sopenharmony_ci			VOLTAGE_NONE;
249862306a36Sopenharmony_ci	} else if (rdev->family >= CHIP_TAHITI) {
249962306a36Sopenharmony_ci		sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
250062306a36Sopenharmony_ci		sclk |= clock_info->si.ucEngineClockHigh << 16;
250162306a36Sopenharmony_ci		mclk = le16_to_cpu(clock_info->si.usMemoryClockLow);
250262306a36Sopenharmony_ci		mclk |= clock_info->si.ucMemoryClockHigh << 16;
250362306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
250462306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
250562306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
250662306a36Sopenharmony_ci			VOLTAGE_SW;
250762306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
250862306a36Sopenharmony_ci			le16_to_cpu(clock_info->si.usVDDC);
250962306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
251062306a36Sopenharmony_ci			le16_to_cpu(clock_info->si.usVDDCI);
251162306a36Sopenharmony_ci	} else if (rdev->family >= CHIP_CEDAR) {
251262306a36Sopenharmony_ci		sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
251362306a36Sopenharmony_ci		sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
251462306a36Sopenharmony_ci		mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
251562306a36Sopenharmony_ci		mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
251662306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
251762306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
251862306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
251962306a36Sopenharmony_ci			VOLTAGE_SW;
252062306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
252162306a36Sopenharmony_ci			le16_to_cpu(clock_info->evergreen.usVDDC);
252262306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
252362306a36Sopenharmony_ci			le16_to_cpu(clock_info->evergreen.usVDDCI);
252462306a36Sopenharmony_ci	} else {
252562306a36Sopenharmony_ci		sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
252662306a36Sopenharmony_ci		sclk |= clock_info->r600.ucEngineClockHigh << 16;
252762306a36Sopenharmony_ci		mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
252862306a36Sopenharmony_ci		mclk |= clock_info->r600.ucMemoryClockHigh << 16;
252962306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
253062306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
253162306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
253262306a36Sopenharmony_ci			VOLTAGE_SW;
253362306a36Sopenharmony_ci		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
253462306a36Sopenharmony_ci			le16_to_cpu(clock_info->r600.usVDDC);
253562306a36Sopenharmony_ci	}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	/* patch up vddc if necessary */
253862306a36Sopenharmony_ci	switch (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage) {
253962306a36Sopenharmony_ci	case ATOM_VIRTUAL_VOLTAGE_ID0:
254062306a36Sopenharmony_ci	case ATOM_VIRTUAL_VOLTAGE_ID1:
254162306a36Sopenharmony_ci	case ATOM_VIRTUAL_VOLTAGE_ID2:
254262306a36Sopenharmony_ci	case ATOM_VIRTUAL_VOLTAGE_ID3:
254362306a36Sopenharmony_ci	case ATOM_VIRTUAL_VOLTAGE_ID4:
254462306a36Sopenharmony_ci	case ATOM_VIRTUAL_VOLTAGE_ID5:
254562306a36Sopenharmony_ci	case ATOM_VIRTUAL_VOLTAGE_ID6:
254662306a36Sopenharmony_ci	case ATOM_VIRTUAL_VOLTAGE_ID7:
254762306a36Sopenharmony_ci		if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC,
254862306a36Sopenharmony_ci					     rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage,
254962306a36Sopenharmony_ci					     &vddc) == 0)
255062306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = vddc;
255162306a36Sopenharmony_ci		break;
255262306a36Sopenharmony_ci	default:
255362306a36Sopenharmony_ci		break;
255462306a36Sopenharmony_ci	}
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_IGP) {
255762306a36Sopenharmony_ci		/* skip invalid modes */
255862306a36Sopenharmony_ci		if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
255962306a36Sopenharmony_ci			return false;
256062306a36Sopenharmony_ci	} else {
256162306a36Sopenharmony_ci		/* skip invalid modes */
256262306a36Sopenharmony_ci		if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
256362306a36Sopenharmony_ci		    (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
256462306a36Sopenharmony_ci			return false;
256562306a36Sopenharmony_ci	}
256662306a36Sopenharmony_ci	return true;
256762306a36Sopenharmony_ci}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_cistatic int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev)
257062306a36Sopenharmony_ci{
257162306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
257262306a36Sopenharmony_ci	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
257362306a36Sopenharmony_ci	union pplib_power_state *power_state;
257462306a36Sopenharmony_ci	int i, j;
257562306a36Sopenharmony_ci	int state_index = 0, mode_index = 0;
257662306a36Sopenharmony_ci	union pplib_clock_info *clock_info;
257762306a36Sopenharmony_ci	bool valid;
257862306a36Sopenharmony_ci	union power_info *power_info;
257962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
258062306a36Sopenharmony_ci	u16 data_offset;
258162306a36Sopenharmony_ci	u8 frev, crev;
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
258462306a36Sopenharmony_ci				   &frev, &crev, &data_offset))
258562306a36Sopenharmony_ci		return state_index;
258662306a36Sopenharmony_ci	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
258962306a36Sopenharmony_ci	if (power_info->pplib.ucNumStates == 0)
259062306a36Sopenharmony_ci		return state_index;
259162306a36Sopenharmony_ci	rdev->pm.power_state = kcalloc(power_info->pplib.ucNumStates,
259262306a36Sopenharmony_ci				       sizeof(struct radeon_power_state),
259362306a36Sopenharmony_ci				       GFP_KERNEL);
259462306a36Sopenharmony_ci	if (!rdev->pm.power_state)
259562306a36Sopenharmony_ci		return state_index;
259662306a36Sopenharmony_ci	/* first mode is usually default, followed by low to high */
259762306a36Sopenharmony_ci	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
259862306a36Sopenharmony_ci		mode_index = 0;
259962306a36Sopenharmony_ci		power_state = (union pplib_power_state *)
260062306a36Sopenharmony_ci			(mode_info->atom_context->bios + data_offset +
260162306a36Sopenharmony_ci			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
260262306a36Sopenharmony_ci			 i * power_info->pplib.ucStateEntrySize);
260362306a36Sopenharmony_ci		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
260462306a36Sopenharmony_ci			(mode_info->atom_context->bios + data_offset +
260562306a36Sopenharmony_ci			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
260662306a36Sopenharmony_ci			 (power_state->v1.ucNonClockStateIndex *
260762306a36Sopenharmony_ci			  power_info->pplib.ucNonClockSize));
260862306a36Sopenharmony_ci		rdev->pm.power_state[i].clock_info =
260962306a36Sopenharmony_ci			kcalloc((power_info->pplib.ucStateEntrySize - 1) ?
261062306a36Sopenharmony_ci				(power_info->pplib.ucStateEntrySize - 1) : 1,
261162306a36Sopenharmony_ci				sizeof(struct radeon_pm_clock_info),
261262306a36Sopenharmony_ci				GFP_KERNEL);
261362306a36Sopenharmony_ci		if (!rdev->pm.power_state[i].clock_info)
261462306a36Sopenharmony_ci			return state_index;
261562306a36Sopenharmony_ci		if (power_info->pplib.ucStateEntrySize - 1) {
261662306a36Sopenharmony_ci			for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
261762306a36Sopenharmony_ci				clock_info = (union pplib_clock_info *)
261862306a36Sopenharmony_ci					(mode_info->atom_context->bios + data_offset +
261962306a36Sopenharmony_ci					 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
262062306a36Sopenharmony_ci					 (power_state->v1.ucClockStateIndices[j] *
262162306a36Sopenharmony_ci					  power_info->pplib.ucClockInfoSize));
262262306a36Sopenharmony_ci				valid = radeon_atombios_parse_pplib_clock_info(rdev,
262362306a36Sopenharmony_ci									       state_index, mode_index,
262462306a36Sopenharmony_ci									       clock_info);
262562306a36Sopenharmony_ci				if (valid)
262662306a36Sopenharmony_ci					mode_index++;
262762306a36Sopenharmony_ci			}
262862306a36Sopenharmony_ci		} else {
262962306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].mclk =
263062306a36Sopenharmony_ci				rdev->clock.default_mclk;
263162306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].sclk =
263262306a36Sopenharmony_ci				rdev->clock.default_sclk;
263362306a36Sopenharmony_ci			mode_index++;
263462306a36Sopenharmony_ci		}
263562306a36Sopenharmony_ci		rdev->pm.power_state[state_index].num_clock_modes = mode_index;
263662306a36Sopenharmony_ci		if (mode_index) {
263762306a36Sopenharmony_ci			radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
263862306a36Sopenharmony_ci								   non_clock_info);
263962306a36Sopenharmony_ci			state_index++;
264062306a36Sopenharmony_ci		}
264162306a36Sopenharmony_ci	}
264262306a36Sopenharmony_ci	/* if multiple clock modes, mark the lowest as no display */
264362306a36Sopenharmony_ci	for (i = 0; i < state_index; i++) {
264462306a36Sopenharmony_ci		if (rdev->pm.power_state[i].num_clock_modes > 1)
264562306a36Sopenharmony_ci			rdev->pm.power_state[i].clock_info[0].flags |=
264662306a36Sopenharmony_ci				RADEON_PM_MODE_NO_DISPLAY;
264762306a36Sopenharmony_ci	}
264862306a36Sopenharmony_ci	/* first mode is usually default */
264962306a36Sopenharmony_ci	if (rdev->pm.default_power_state_index == -1) {
265062306a36Sopenharmony_ci		rdev->pm.power_state[0].type =
265162306a36Sopenharmony_ci			POWER_STATE_TYPE_DEFAULT;
265262306a36Sopenharmony_ci		rdev->pm.default_power_state_index = 0;
265362306a36Sopenharmony_ci		rdev->pm.power_state[0].default_clock_mode =
265462306a36Sopenharmony_ci			&rdev->pm.power_state[0].clock_info[0];
265562306a36Sopenharmony_ci	}
265662306a36Sopenharmony_ci	return state_index;
265762306a36Sopenharmony_ci}
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_cistatic int radeon_atombios_parse_power_table_6(struct radeon_device *rdev)
266062306a36Sopenharmony_ci{
266162306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
266262306a36Sopenharmony_ci	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
266362306a36Sopenharmony_ci	union pplib_power_state *power_state;
266462306a36Sopenharmony_ci	int i, j, non_clock_array_index, clock_array_index;
266562306a36Sopenharmony_ci	int state_index = 0, mode_index = 0;
266662306a36Sopenharmony_ci	union pplib_clock_info *clock_info;
266762306a36Sopenharmony_ci	struct _StateArray *state_array;
266862306a36Sopenharmony_ci	struct _ClockInfoArray *clock_info_array;
266962306a36Sopenharmony_ci	struct _NonClockInfoArray *non_clock_info_array;
267062306a36Sopenharmony_ci	bool valid;
267162306a36Sopenharmony_ci	union power_info *power_info;
267262306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
267362306a36Sopenharmony_ci	u16 data_offset;
267462306a36Sopenharmony_ci	u8 frev, crev;
267562306a36Sopenharmony_ci	u8 *power_state_offset;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
267862306a36Sopenharmony_ci				   &frev, &crev, &data_offset))
267962306a36Sopenharmony_ci		return state_index;
268062306a36Sopenharmony_ci	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
268362306a36Sopenharmony_ci	state_array = (struct _StateArray *)
268462306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
268562306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
268662306a36Sopenharmony_ci	clock_info_array = (struct _ClockInfoArray *)
268762306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
268862306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
268962306a36Sopenharmony_ci	non_clock_info_array = (struct _NonClockInfoArray *)
269062306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
269162306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
269262306a36Sopenharmony_ci	if (state_array->ucNumEntries == 0)
269362306a36Sopenharmony_ci		return state_index;
269462306a36Sopenharmony_ci	rdev->pm.power_state = kcalloc(state_array->ucNumEntries,
269562306a36Sopenharmony_ci				       sizeof(struct radeon_power_state),
269662306a36Sopenharmony_ci				       GFP_KERNEL);
269762306a36Sopenharmony_ci	if (!rdev->pm.power_state)
269862306a36Sopenharmony_ci		return state_index;
269962306a36Sopenharmony_ci	power_state_offset = (u8 *)state_array->states;
270062306a36Sopenharmony_ci	for (i = 0; i < state_array->ucNumEntries; i++) {
270162306a36Sopenharmony_ci		mode_index = 0;
270262306a36Sopenharmony_ci		power_state = (union pplib_power_state *)power_state_offset;
270362306a36Sopenharmony_ci		non_clock_array_index = power_state->v2.nonClockInfoIndex;
270462306a36Sopenharmony_ci		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
270562306a36Sopenharmony_ci			&non_clock_info_array->nonClockInfo[non_clock_array_index];
270662306a36Sopenharmony_ci		rdev->pm.power_state[i].clock_info =
270762306a36Sopenharmony_ci			kcalloc(power_state->v2.ucNumDPMLevels ?
270862306a36Sopenharmony_ci				power_state->v2.ucNumDPMLevels : 1,
270962306a36Sopenharmony_ci				sizeof(struct radeon_pm_clock_info),
271062306a36Sopenharmony_ci				GFP_KERNEL);
271162306a36Sopenharmony_ci		if (!rdev->pm.power_state[i].clock_info)
271262306a36Sopenharmony_ci			return state_index;
271362306a36Sopenharmony_ci		if (power_state->v2.ucNumDPMLevels) {
271462306a36Sopenharmony_ci			for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
271562306a36Sopenharmony_ci				clock_array_index = power_state->v2.clockInfoIndex[j];
271662306a36Sopenharmony_ci				clock_info = (union pplib_clock_info *)
271762306a36Sopenharmony_ci					&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
271862306a36Sopenharmony_ci				valid = radeon_atombios_parse_pplib_clock_info(rdev,
271962306a36Sopenharmony_ci									       state_index, mode_index,
272062306a36Sopenharmony_ci									       clock_info);
272162306a36Sopenharmony_ci				if (valid)
272262306a36Sopenharmony_ci					mode_index++;
272362306a36Sopenharmony_ci			}
272462306a36Sopenharmony_ci		} else {
272562306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].mclk =
272662306a36Sopenharmony_ci				rdev->clock.default_mclk;
272762306a36Sopenharmony_ci			rdev->pm.power_state[state_index].clock_info[0].sclk =
272862306a36Sopenharmony_ci				rdev->clock.default_sclk;
272962306a36Sopenharmony_ci			mode_index++;
273062306a36Sopenharmony_ci		}
273162306a36Sopenharmony_ci		rdev->pm.power_state[state_index].num_clock_modes = mode_index;
273262306a36Sopenharmony_ci		if (mode_index) {
273362306a36Sopenharmony_ci			radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
273462306a36Sopenharmony_ci								   non_clock_info);
273562306a36Sopenharmony_ci			state_index++;
273662306a36Sopenharmony_ci		}
273762306a36Sopenharmony_ci		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
273862306a36Sopenharmony_ci	}
273962306a36Sopenharmony_ci	/* if multiple clock modes, mark the lowest as no display */
274062306a36Sopenharmony_ci	for (i = 0; i < state_index; i++) {
274162306a36Sopenharmony_ci		if (rdev->pm.power_state[i].num_clock_modes > 1)
274262306a36Sopenharmony_ci			rdev->pm.power_state[i].clock_info[0].flags |=
274362306a36Sopenharmony_ci				RADEON_PM_MODE_NO_DISPLAY;
274462306a36Sopenharmony_ci	}
274562306a36Sopenharmony_ci	/* first mode is usually default */
274662306a36Sopenharmony_ci	if (rdev->pm.default_power_state_index == -1) {
274762306a36Sopenharmony_ci		rdev->pm.power_state[0].type =
274862306a36Sopenharmony_ci			POWER_STATE_TYPE_DEFAULT;
274962306a36Sopenharmony_ci		rdev->pm.default_power_state_index = 0;
275062306a36Sopenharmony_ci		rdev->pm.power_state[0].default_clock_mode =
275162306a36Sopenharmony_ci			&rdev->pm.power_state[0].clock_info[0];
275262306a36Sopenharmony_ci	}
275362306a36Sopenharmony_ci	return state_index;
275462306a36Sopenharmony_ci}
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_civoid radeon_atombios_get_power_modes(struct radeon_device *rdev)
275762306a36Sopenharmony_ci{
275862306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
275962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
276062306a36Sopenharmony_ci	u16 data_offset;
276162306a36Sopenharmony_ci	u8 frev, crev;
276262306a36Sopenharmony_ci	int state_index = 0;
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	rdev->pm.default_power_state_index = -1;
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
276762306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
276862306a36Sopenharmony_ci		switch (frev) {
276962306a36Sopenharmony_ci		case 1:
277062306a36Sopenharmony_ci		case 2:
277162306a36Sopenharmony_ci		case 3:
277262306a36Sopenharmony_ci			state_index = radeon_atombios_parse_power_table_1_3(rdev);
277362306a36Sopenharmony_ci			break;
277462306a36Sopenharmony_ci		case 4:
277562306a36Sopenharmony_ci		case 5:
277662306a36Sopenharmony_ci			state_index = radeon_atombios_parse_power_table_4_5(rdev);
277762306a36Sopenharmony_ci			break;
277862306a36Sopenharmony_ci		case 6:
277962306a36Sopenharmony_ci			state_index = radeon_atombios_parse_power_table_6(rdev);
278062306a36Sopenharmony_ci			break;
278162306a36Sopenharmony_ci		default:
278262306a36Sopenharmony_ci			break;
278362306a36Sopenharmony_ci		}
278462306a36Sopenharmony_ci	}
278562306a36Sopenharmony_ci
278662306a36Sopenharmony_ci	if (state_index == 0) {
278762306a36Sopenharmony_ci		rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL);
278862306a36Sopenharmony_ci		if (rdev->pm.power_state) {
278962306a36Sopenharmony_ci			rdev->pm.power_state[0].clock_info =
279062306a36Sopenharmony_ci				kcalloc(1,
279162306a36Sopenharmony_ci				        sizeof(struct radeon_pm_clock_info),
279262306a36Sopenharmony_ci				        GFP_KERNEL);
279362306a36Sopenharmony_ci			if (rdev->pm.power_state[0].clock_info) {
279462306a36Sopenharmony_ci				/* add the default mode */
279562306a36Sopenharmony_ci				rdev->pm.power_state[state_index].type =
279662306a36Sopenharmony_ci					POWER_STATE_TYPE_DEFAULT;
279762306a36Sopenharmony_ci				rdev->pm.power_state[state_index].num_clock_modes = 1;
279862306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
279962306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
280062306a36Sopenharmony_ci				rdev->pm.power_state[state_index].default_clock_mode =
280162306a36Sopenharmony_ci					&rdev->pm.power_state[state_index].clock_info[0];
280262306a36Sopenharmony_ci				rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
280362306a36Sopenharmony_ci				rdev->pm.power_state[state_index].pcie_lanes = 16;
280462306a36Sopenharmony_ci				rdev->pm.default_power_state_index = state_index;
280562306a36Sopenharmony_ci				rdev->pm.power_state[state_index].flags = 0;
280662306a36Sopenharmony_ci				state_index++;
280762306a36Sopenharmony_ci			}
280862306a36Sopenharmony_ci		}
280962306a36Sopenharmony_ci	}
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	rdev->pm.num_power_states = state_index;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
281462306a36Sopenharmony_ci	rdev->pm.current_clock_mode_index = 0;
281562306a36Sopenharmony_ci	if (rdev->pm.default_power_state_index >= 0)
281662306a36Sopenharmony_ci		rdev->pm.current_vddc =
281762306a36Sopenharmony_ci			rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
281862306a36Sopenharmony_ci	else
281962306a36Sopenharmony_ci		rdev->pm.current_vddc = 0;
282062306a36Sopenharmony_ci}
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ciunion get_clock_dividers {
282362306a36Sopenharmony_ci	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1;
282462306a36Sopenharmony_ci	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2;
282562306a36Sopenharmony_ci	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3;
282662306a36Sopenharmony_ci	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4;
282762306a36Sopenharmony_ci	struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5;
282862306a36Sopenharmony_ci	struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in;
282962306a36Sopenharmony_ci	struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out;
283062306a36Sopenharmony_ci};
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ciint radeon_atom_get_clock_dividers(struct radeon_device *rdev,
283362306a36Sopenharmony_ci				   u8 clock_type,
283462306a36Sopenharmony_ci				   u32 clock,
283562306a36Sopenharmony_ci				   bool strobe_mode,
283662306a36Sopenharmony_ci				   struct atom_clock_dividers *dividers)
283762306a36Sopenharmony_ci{
283862306a36Sopenharmony_ci	union get_clock_dividers args;
283962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL);
284062306a36Sopenharmony_ci	u8 frev, crev;
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
284362306a36Sopenharmony_ci	memset(dividers, 0, sizeof(struct atom_clock_dividers));
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
284662306a36Sopenharmony_ci		return -EINVAL;
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	switch (crev) {
284962306a36Sopenharmony_ci	case 1:
285062306a36Sopenharmony_ci		/* r4xx, r5xx */
285162306a36Sopenharmony_ci		args.v1.ucAction = clock_type;
285262306a36Sopenharmony_ci		args.v1.ulClock = cpu_to_le32(clock);	/* 10 khz */
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci		dividers->post_div = args.v1.ucPostDiv;
285762306a36Sopenharmony_ci		dividers->fb_div = args.v1.ucFbDiv;
285862306a36Sopenharmony_ci		dividers->enable_post_div = true;
285962306a36Sopenharmony_ci		break;
286062306a36Sopenharmony_ci	case 2:
286162306a36Sopenharmony_ci	case 3:
286262306a36Sopenharmony_ci	case 5:
286362306a36Sopenharmony_ci		/* r6xx, r7xx, evergreen, ni, si */
286462306a36Sopenharmony_ci		if (rdev->family <= CHIP_RV770) {
286562306a36Sopenharmony_ci			args.v2.ucAction = clock_type;
286662306a36Sopenharmony_ci			args.v2.ulClock = cpu_to_le32(clock);	/* 10 khz */
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci			atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci			dividers->post_div = args.v2.ucPostDiv;
287162306a36Sopenharmony_ci			dividers->fb_div = le16_to_cpu(args.v2.usFbDiv);
287262306a36Sopenharmony_ci			dividers->ref_div = args.v2.ucAction;
287362306a36Sopenharmony_ci			if (rdev->family == CHIP_RV770) {
287462306a36Sopenharmony_ci				dividers->enable_post_div = (le32_to_cpu(args.v2.ulClock) & (1 << 24)) ?
287562306a36Sopenharmony_ci					true : false;
287662306a36Sopenharmony_ci				dividers->vco_mode = (le32_to_cpu(args.v2.ulClock) & (1 << 25)) ? 1 : 0;
287762306a36Sopenharmony_ci			} else
287862306a36Sopenharmony_ci				dividers->enable_post_div = (dividers->fb_div & 1) ? true : false;
287962306a36Sopenharmony_ci		} else {
288062306a36Sopenharmony_ci			if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {
288162306a36Sopenharmony_ci				args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci				atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci				dividers->post_div = args.v3.ucPostDiv;
288662306a36Sopenharmony_ci				dividers->enable_post_div = (args.v3.ucCntlFlag &
288762306a36Sopenharmony_ci							     ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
288862306a36Sopenharmony_ci				dividers->enable_dithen = (args.v3.ucCntlFlag &
288962306a36Sopenharmony_ci							   ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
289062306a36Sopenharmony_ci				dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
289162306a36Sopenharmony_ci				dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
289262306a36Sopenharmony_ci				dividers->ref_div = args.v3.ucRefDiv;
289362306a36Sopenharmony_ci				dividers->vco_mode = (args.v3.ucCntlFlag &
289462306a36Sopenharmony_ci						      ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
289562306a36Sopenharmony_ci			} else {
289662306a36Sopenharmony_ci				/* for SI we use ComputeMemoryClockParam for memory plls */
289762306a36Sopenharmony_ci				if (rdev->family >= CHIP_TAHITI)
289862306a36Sopenharmony_ci					return -EINVAL;
289962306a36Sopenharmony_ci				args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
290062306a36Sopenharmony_ci				if (strobe_mode)
290162306a36Sopenharmony_ci					args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci				atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci				dividers->post_div = args.v5.ucPostDiv;
290662306a36Sopenharmony_ci				dividers->enable_post_div = (args.v5.ucCntlFlag &
290762306a36Sopenharmony_ci							     ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
290862306a36Sopenharmony_ci				dividers->enable_dithen = (args.v5.ucCntlFlag &
290962306a36Sopenharmony_ci							   ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
291062306a36Sopenharmony_ci				dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv);
291162306a36Sopenharmony_ci				dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac);
291262306a36Sopenharmony_ci				dividers->ref_div = args.v5.ucRefDiv;
291362306a36Sopenharmony_ci				dividers->vco_mode = (args.v5.ucCntlFlag &
291462306a36Sopenharmony_ci						      ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
291562306a36Sopenharmony_ci			}
291662306a36Sopenharmony_ci		}
291762306a36Sopenharmony_ci		break;
291862306a36Sopenharmony_ci	case 4:
291962306a36Sopenharmony_ci		/* fusion */
292062306a36Sopenharmony_ci		args.v4.ulClock = cpu_to_le32(clock);	/* 10 khz */
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci		dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;
292562306a36Sopenharmony_ci		dividers->real_clock = le32_to_cpu(args.v4.ulClock);
292662306a36Sopenharmony_ci		break;
292762306a36Sopenharmony_ci	case 6:
292862306a36Sopenharmony_ci		/* CI */
292962306a36Sopenharmony_ci		/* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */
293062306a36Sopenharmony_ci		args.v6_in.ulClock.ulComputeClockFlag = clock_type;
293162306a36Sopenharmony_ci		args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock);	/* 10 khz */
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci		dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);
293662306a36Sopenharmony_ci		dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);
293762306a36Sopenharmony_ci		dividers->ref_div = args.v6_out.ucPllRefDiv;
293862306a36Sopenharmony_ci		dividers->post_div = args.v6_out.ucPllPostDiv;
293962306a36Sopenharmony_ci		dividers->flags = args.v6_out.ucPllCntlFlag;
294062306a36Sopenharmony_ci		dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock);
294162306a36Sopenharmony_ci		dividers->post_divider = args.v6_out.ulClock.ucPostDiv;
294262306a36Sopenharmony_ci		break;
294362306a36Sopenharmony_ci	default:
294462306a36Sopenharmony_ci		return -EINVAL;
294562306a36Sopenharmony_ci	}
294662306a36Sopenharmony_ci	return 0;
294762306a36Sopenharmony_ci}
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ciint radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev,
295062306a36Sopenharmony_ci					u32 clock,
295162306a36Sopenharmony_ci					bool strobe_mode,
295262306a36Sopenharmony_ci					struct atom_mpll_param *mpll_param)
295362306a36Sopenharmony_ci{
295462306a36Sopenharmony_ci	COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 args;
295562306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam);
295662306a36Sopenharmony_ci	u8 frev, crev;
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
295962306a36Sopenharmony_ci	memset(mpll_param, 0, sizeof(struct atom_mpll_param));
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
296262306a36Sopenharmony_ci		return -EINVAL;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	switch (frev) {
296562306a36Sopenharmony_ci	case 2:
296662306a36Sopenharmony_ci		switch (crev) {
296762306a36Sopenharmony_ci		case 1:
296862306a36Sopenharmony_ci			/* SI */
296962306a36Sopenharmony_ci			args.ulClock = cpu_to_le32(clock);	/* 10 khz */
297062306a36Sopenharmony_ci			args.ucInputFlag = 0;
297162306a36Sopenharmony_ci			if (strobe_mode)
297262306a36Sopenharmony_ci				args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN;
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci			atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci			mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac);
297762306a36Sopenharmony_ci			mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv);
297862306a36Sopenharmony_ci			mpll_param->post_div = args.ucPostDiv;
297962306a36Sopenharmony_ci			mpll_param->dll_speed = args.ucDllSpeed;
298062306a36Sopenharmony_ci			mpll_param->bwcntl = args.ucBWCntl;
298162306a36Sopenharmony_ci			mpll_param->vco_mode =
298262306a36Sopenharmony_ci				(args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK);
298362306a36Sopenharmony_ci			mpll_param->yclk_sel =
298462306a36Sopenharmony_ci				(args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0;
298562306a36Sopenharmony_ci			mpll_param->qdr =
298662306a36Sopenharmony_ci				(args.ucPllCntlFlag & MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0;
298762306a36Sopenharmony_ci			mpll_param->half_rate =
298862306a36Sopenharmony_ci				(args.ucPllCntlFlag & MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0;
298962306a36Sopenharmony_ci			break;
299062306a36Sopenharmony_ci		default:
299162306a36Sopenharmony_ci			return -EINVAL;
299262306a36Sopenharmony_ci		}
299362306a36Sopenharmony_ci		break;
299462306a36Sopenharmony_ci	default:
299562306a36Sopenharmony_ci		return -EINVAL;
299662306a36Sopenharmony_ci	}
299762306a36Sopenharmony_ci	return 0;
299862306a36Sopenharmony_ci}
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_civoid radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
300162306a36Sopenharmony_ci{
300262306a36Sopenharmony_ci	DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
300362306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	args.ucEnable = enable;
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
300862306a36Sopenharmony_ci}
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ciuint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev)
301162306a36Sopenharmony_ci{
301262306a36Sopenharmony_ci	GET_ENGINE_CLOCK_PS_ALLOCATION args;
301362306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock);
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
301662306a36Sopenharmony_ci	return le32_to_cpu(args.ulReturnEngineClock);
301762306a36Sopenharmony_ci}
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ciuint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev)
302062306a36Sopenharmony_ci{
302162306a36Sopenharmony_ci	GET_MEMORY_CLOCK_PS_ALLOCATION args;
302262306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock);
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
302562306a36Sopenharmony_ci	return le32_to_cpu(args.ulReturnMemoryClock);
302662306a36Sopenharmony_ci}
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_civoid radeon_atom_set_engine_clock(struct radeon_device *rdev,
302962306a36Sopenharmony_ci				  uint32_t eng_clock)
303062306a36Sopenharmony_ci{
303162306a36Sopenharmony_ci	SET_ENGINE_CLOCK_PS_ALLOCATION args;
303262306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	args.ulTargetEngineClock = cpu_to_le32(eng_clock);	/* 10 khz */
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
303762306a36Sopenharmony_ci}
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_civoid radeon_atom_set_memory_clock(struct radeon_device *rdev,
304062306a36Sopenharmony_ci				  uint32_t mem_clock)
304162306a36Sopenharmony_ci{
304262306a36Sopenharmony_ci	SET_MEMORY_CLOCK_PS_ALLOCATION args;
304362306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_IGP)
304662306a36Sopenharmony_ci		return;
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	args.ulTargetMemoryClock = cpu_to_le32(mem_clock);	/* 10 khz */
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
305162306a36Sopenharmony_ci}
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_civoid radeon_atom_set_engine_dram_timings(struct radeon_device *rdev,
305462306a36Sopenharmony_ci					 u32 eng_clock, u32 mem_clock)
305562306a36Sopenharmony_ci{
305662306a36Sopenharmony_ci	SET_ENGINE_CLOCK_PS_ALLOCATION args;
305762306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
305862306a36Sopenharmony_ci	u32 tmp;
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci	memset(&args, 0, sizeof(args));
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	tmp = eng_clock & SET_CLOCK_FREQ_MASK;
306362306a36Sopenharmony_ci	tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24);
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	args.ulTargetEngineClock = cpu_to_le32(tmp);
306662306a36Sopenharmony_ci	if (mem_clock)
306762306a36Sopenharmony_ci		args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK);
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
307062306a36Sopenharmony_ci}
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_civoid radeon_atom_update_memory_dll(struct radeon_device *rdev,
307362306a36Sopenharmony_ci				   u32 mem_clock)
307462306a36Sopenharmony_ci{
307562306a36Sopenharmony_ci	u32 args;
307662306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	args = cpu_to_le32(mem_clock);	/* 10 khz */
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
308162306a36Sopenharmony_ci}
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_civoid radeon_atom_set_ac_timing(struct radeon_device *rdev,
308462306a36Sopenharmony_ci			       u32 mem_clock)
308562306a36Sopenharmony_ci{
308662306a36Sopenharmony_ci	SET_MEMORY_CLOCK_PS_ALLOCATION args;
308762306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
308862306a36Sopenharmony_ci	u32 tmp = mem_clock | (COMPUTE_MEMORY_PLL_PARAM << 24);
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	args.ulTargetMemoryClock = cpu_to_le32(tmp);	/* 10 khz */
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
309362306a36Sopenharmony_ci}
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ciunion set_voltage {
309662306a36Sopenharmony_ci	struct _SET_VOLTAGE_PS_ALLOCATION alloc;
309762306a36Sopenharmony_ci	struct _SET_VOLTAGE_PARAMETERS v1;
309862306a36Sopenharmony_ci	struct _SET_VOLTAGE_PARAMETERS_V2 v2;
309962306a36Sopenharmony_ci	struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;
310062306a36Sopenharmony_ci};
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_civoid radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type)
310362306a36Sopenharmony_ci{
310462306a36Sopenharmony_ci	union set_voltage args;
310562306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
310662306a36Sopenharmony_ci	u8 frev, crev, volt_index = voltage_level;
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
310962306a36Sopenharmony_ci		return;
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci	/* 0xff01 is a flag rather then an actual voltage */
311262306a36Sopenharmony_ci	if (voltage_level == 0xff01)
311362306a36Sopenharmony_ci		return;
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	switch (crev) {
311662306a36Sopenharmony_ci	case 1:
311762306a36Sopenharmony_ci		args.v1.ucVoltageType = voltage_type;
311862306a36Sopenharmony_ci		args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE;
311962306a36Sopenharmony_ci		args.v1.ucVoltageIndex = volt_index;
312062306a36Sopenharmony_ci		break;
312162306a36Sopenharmony_ci	case 2:
312262306a36Sopenharmony_ci		args.v2.ucVoltageType = voltage_type;
312362306a36Sopenharmony_ci		args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE;
312462306a36Sopenharmony_ci		args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
312562306a36Sopenharmony_ci		break;
312662306a36Sopenharmony_ci	case 3:
312762306a36Sopenharmony_ci		args.v3.ucVoltageType = voltage_type;
312862306a36Sopenharmony_ci		args.v3.ucVoltageMode = ATOM_SET_VOLTAGE;
312962306a36Sopenharmony_ci		args.v3.usVoltageLevel = cpu_to_le16(voltage_level);
313062306a36Sopenharmony_ci		break;
313162306a36Sopenharmony_ci	default:
313262306a36Sopenharmony_ci		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
313362306a36Sopenharmony_ci		return;
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
313762306a36Sopenharmony_ci}
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ciint radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
314062306a36Sopenharmony_ci			     u16 voltage_id, u16 *voltage)
314162306a36Sopenharmony_ci{
314262306a36Sopenharmony_ci	union set_voltage args;
314362306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
314462306a36Sopenharmony_ci	u8 frev, crev;
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
314762306a36Sopenharmony_ci		return -EINVAL;
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	switch (crev) {
315062306a36Sopenharmony_ci	case 1:
315162306a36Sopenharmony_ci		return -EINVAL;
315262306a36Sopenharmony_ci	case 2:
315362306a36Sopenharmony_ci		args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;
315462306a36Sopenharmony_ci		args.v2.ucVoltageMode = 0;
315562306a36Sopenharmony_ci		args.v2.usVoltageLevel = 0;
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci		*voltage = le16_to_cpu(args.v2.usVoltageLevel);
316062306a36Sopenharmony_ci		break;
316162306a36Sopenharmony_ci	case 3:
316262306a36Sopenharmony_ci		args.v3.ucVoltageType = voltage_type;
316362306a36Sopenharmony_ci		args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;
316462306a36Sopenharmony_ci		args.v3.usVoltageLevel = cpu_to_le16(voltage_id);
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci		*voltage = le16_to_cpu(args.v3.usVoltageLevel);
316962306a36Sopenharmony_ci		break;
317062306a36Sopenharmony_ci	default:
317162306a36Sopenharmony_ci		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
317262306a36Sopenharmony_ci		return -EINVAL;
317362306a36Sopenharmony_ci	}
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	return 0;
317662306a36Sopenharmony_ci}
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ciint radeon_atom_get_leakage_vddc_based_on_leakage_idx(struct radeon_device *rdev,
317962306a36Sopenharmony_ci						      u16 *voltage,
318062306a36Sopenharmony_ci						      u16 leakage_idx)
318162306a36Sopenharmony_ci{
318262306a36Sopenharmony_ci	return radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage);
318362306a36Sopenharmony_ci}
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ciint radeon_atom_get_leakage_id_from_vbios(struct radeon_device *rdev,
318662306a36Sopenharmony_ci					  u16 *leakage_id)
318762306a36Sopenharmony_ci{
318862306a36Sopenharmony_ci	union set_voltage args;
318962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
319062306a36Sopenharmony_ci	u8 frev, crev;
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
319362306a36Sopenharmony_ci		return -EINVAL;
319462306a36Sopenharmony_ci
319562306a36Sopenharmony_ci	switch (crev) {
319662306a36Sopenharmony_ci	case 3:
319762306a36Sopenharmony_ci	case 4:
319862306a36Sopenharmony_ci		args.v3.ucVoltageType = 0;
319962306a36Sopenharmony_ci		args.v3.ucVoltageMode = ATOM_GET_LEAKAGE_ID;
320062306a36Sopenharmony_ci		args.v3.usVoltageLevel = 0;
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci		*leakage_id = le16_to_cpu(args.v3.usVoltageLevel);
320562306a36Sopenharmony_ci		break;
320662306a36Sopenharmony_ci	default:
320762306a36Sopenharmony_ci		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
320862306a36Sopenharmony_ci		return -EINVAL;
320962306a36Sopenharmony_ci	}
321062306a36Sopenharmony_ci
321162306a36Sopenharmony_ci	return 0;
321262306a36Sopenharmony_ci}
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ciint radeon_atom_get_leakage_vddc_based_on_leakage_params(struct radeon_device *rdev,
321562306a36Sopenharmony_ci							 u16 *vddc, u16 *vddci,
321662306a36Sopenharmony_ci							 u16 virtual_voltage_id,
321762306a36Sopenharmony_ci							 u16 vbios_voltage_id)
321862306a36Sopenharmony_ci{
321962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo);
322062306a36Sopenharmony_ci	u8 frev, crev;
322162306a36Sopenharmony_ci	u16 data_offset, size;
322262306a36Sopenharmony_ci	int i, j;
322362306a36Sopenharmony_ci	ATOM_ASIC_PROFILING_INFO_V2_1 *profile;
322462306a36Sopenharmony_ci	u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf;
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	*vddc = 0;
322762306a36Sopenharmony_ci	*vddci = 0;
322862306a36Sopenharmony_ci
322962306a36Sopenharmony_ci	if (!atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
323062306a36Sopenharmony_ci				    &frev, &crev, &data_offset))
323162306a36Sopenharmony_ci		return -EINVAL;
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *)
323462306a36Sopenharmony_ci		(rdev->mode_info.atom_context->bios + data_offset);
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci	switch (frev) {
323762306a36Sopenharmony_ci	case 1:
323862306a36Sopenharmony_ci		return -EINVAL;
323962306a36Sopenharmony_ci	case 2:
324062306a36Sopenharmony_ci		switch (crev) {
324162306a36Sopenharmony_ci		case 1:
324262306a36Sopenharmony_ci			if (size < sizeof(ATOM_ASIC_PROFILING_INFO_V2_1))
324362306a36Sopenharmony_ci				return -EINVAL;
324462306a36Sopenharmony_ci			leakage_bin = (u16 *)
324562306a36Sopenharmony_ci				(rdev->mode_info.atom_context->bios + data_offset +
324662306a36Sopenharmony_ci				 le16_to_cpu(profile->usLeakageBinArrayOffset));
324762306a36Sopenharmony_ci			vddc_id_buf = (u16 *)
324862306a36Sopenharmony_ci				(rdev->mode_info.atom_context->bios + data_offset +
324962306a36Sopenharmony_ci				 le16_to_cpu(profile->usElbVDDC_IdArrayOffset));
325062306a36Sopenharmony_ci			vddc_buf = (u16 *)
325162306a36Sopenharmony_ci				(rdev->mode_info.atom_context->bios + data_offset +
325262306a36Sopenharmony_ci				 le16_to_cpu(profile->usElbVDDC_LevelArrayOffset));
325362306a36Sopenharmony_ci			vddci_id_buf = (u16 *)
325462306a36Sopenharmony_ci				(rdev->mode_info.atom_context->bios + data_offset +
325562306a36Sopenharmony_ci				 le16_to_cpu(profile->usElbVDDCI_IdArrayOffset));
325662306a36Sopenharmony_ci			vddci_buf = (u16 *)
325762306a36Sopenharmony_ci				(rdev->mode_info.atom_context->bios + data_offset +
325862306a36Sopenharmony_ci				 le16_to_cpu(profile->usElbVDDCI_LevelArrayOffset));
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci			if (profile->ucElbVDDC_Num > 0) {
326162306a36Sopenharmony_ci				for (i = 0; i < profile->ucElbVDDC_Num; i++) {
326262306a36Sopenharmony_ci					if (vddc_id_buf[i] == virtual_voltage_id) {
326362306a36Sopenharmony_ci						for (j = 0; j < profile->ucLeakageBinNum; j++) {
326462306a36Sopenharmony_ci							if (vbios_voltage_id <= leakage_bin[j]) {
326562306a36Sopenharmony_ci								*vddc = vddc_buf[j * profile->ucElbVDDC_Num + i];
326662306a36Sopenharmony_ci								break;
326762306a36Sopenharmony_ci							}
326862306a36Sopenharmony_ci						}
326962306a36Sopenharmony_ci						break;
327062306a36Sopenharmony_ci					}
327162306a36Sopenharmony_ci				}
327262306a36Sopenharmony_ci			}
327362306a36Sopenharmony_ci			if (profile->ucElbVDDCI_Num > 0) {
327462306a36Sopenharmony_ci				for (i = 0; i < profile->ucElbVDDCI_Num; i++) {
327562306a36Sopenharmony_ci					if (vddci_id_buf[i] == virtual_voltage_id) {
327662306a36Sopenharmony_ci						for (j = 0; j < profile->ucLeakageBinNum; j++) {
327762306a36Sopenharmony_ci							if (vbios_voltage_id <= leakage_bin[j]) {
327862306a36Sopenharmony_ci								*vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i];
327962306a36Sopenharmony_ci								break;
328062306a36Sopenharmony_ci							}
328162306a36Sopenharmony_ci						}
328262306a36Sopenharmony_ci						break;
328362306a36Sopenharmony_ci					}
328462306a36Sopenharmony_ci				}
328562306a36Sopenharmony_ci			}
328662306a36Sopenharmony_ci			break;
328762306a36Sopenharmony_ci		default:
328862306a36Sopenharmony_ci			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
328962306a36Sopenharmony_ci			return -EINVAL;
329062306a36Sopenharmony_ci		}
329162306a36Sopenharmony_ci		break;
329262306a36Sopenharmony_ci	default:
329362306a36Sopenharmony_ci		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
329462306a36Sopenharmony_ci		return -EINVAL;
329562306a36Sopenharmony_ci	}
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	return 0;
329862306a36Sopenharmony_ci}
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ciunion get_voltage_info {
330162306a36Sopenharmony_ci	struct  _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 in;
330262306a36Sopenharmony_ci	struct  _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 evv_out;
330362306a36Sopenharmony_ci};
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ciint radeon_atom_get_voltage_evv(struct radeon_device *rdev,
330662306a36Sopenharmony_ci				u16 virtual_voltage_id,
330762306a36Sopenharmony_ci				u16 *voltage)
330862306a36Sopenharmony_ci{
330962306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, GetVoltageInfo);
331062306a36Sopenharmony_ci	u32 entry_id;
331162306a36Sopenharmony_ci	u32 count = rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count;
331262306a36Sopenharmony_ci	union get_voltage_info args;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	for (entry_id = 0; entry_id < count; entry_id++) {
331562306a36Sopenharmony_ci		if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].v ==
331662306a36Sopenharmony_ci		    virtual_voltage_id)
331762306a36Sopenharmony_ci			break;
331862306a36Sopenharmony_ci	}
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	if (entry_id >= count)
332162306a36Sopenharmony_ci		return -EINVAL;
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	args.in.ucVoltageType = VOLTAGE_TYPE_VDDC;
332462306a36Sopenharmony_ci	args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE;
332562306a36Sopenharmony_ci	args.in.usVoltageLevel = cpu_to_le16(virtual_voltage_id);
332662306a36Sopenharmony_ci	args.in.ulSCLKFreq =
332762306a36Sopenharmony_ci		cpu_to_le32(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk);
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_ci	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci	*voltage = le16_to_cpu(args.evv_out.usVoltageLevel);
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	return 0;
333462306a36Sopenharmony_ci}
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ciint radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev,
333762306a36Sopenharmony_ci					  u16 voltage_level, u8 voltage_type,
333862306a36Sopenharmony_ci					  u32 *gpio_value, u32 *gpio_mask)
333962306a36Sopenharmony_ci{
334062306a36Sopenharmony_ci	union set_voltage args;
334162306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
334262306a36Sopenharmony_ci	u8 frev, crev;
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
334562306a36Sopenharmony_ci		return -EINVAL;
334662306a36Sopenharmony_ci
334762306a36Sopenharmony_ci	switch (crev) {
334862306a36Sopenharmony_ci	case 1:
334962306a36Sopenharmony_ci		return -EINVAL;
335062306a36Sopenharmony_ci	case 2:
335162306a36Sopenharmony_ci		args.v2.ucVoltageType = voltage_type;
335262306a36Sopenharmony_ci		args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK;
335362306a36Sopenharmony_ci		args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci		*gpio_mask = le32_to_cpu(*(u32 *)&args.v2);
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci		args.v2.ucVoltageType = voltage_type;
336062306a36Sopenharmony_ci		args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL;
336162306a36Sopenharmony_ci		args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
336462306a36Sopenharmony_ci
336562306a36Sopenharmony_ci		*gpio_value = le32_to_cpu(*(u32 *)&args.v2);
336662306a36Sopenharmony_ci		break;
336762306a36Sopenharmony_ci	default:
336862306a36Sopenharmony_ci		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
336962306a36Sopenharmony_ci		return -EINVAL;
337062306a36Sopenharmony_ci	}
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	return 0;
337362306a36Sopenharmony_ci}
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ciunion voltage_object_info {
337662306a36Sopenharmony_ci	struct _ATOM_VOLTAGE_OBJECT_INFO v1;
337762306a36Sopenharmony_ci	struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
337862306a36Sopenharmony_ci	struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
337962306a36Sopenharmony_ci};
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ciunion voltage_object {
338262306a36Sopenharmony_ci	struct _ATOM_VOLTAGE_OBJECT v1;
338362306a36Sopenharmony_ci	struct _ATOM_VOLTAGE_OBJECT_V2 v2;
338462306a36Sopenharmony_ci	union _ATOM_VOLTAGE_OBJECT_V3 v3;
338562306a36Sopenharmony_ci};
338662306a36Sopenharmony_ci
338762306a36Sopenharmony_cistatic ATOM_VOLTAGE_OBJECT *atom_lookup_voltage_object_v1(ATOM_VOLTAGE_OBJECT_INFO *v1,
338862306a36Sopenharmony_ci							  u8 voltage_type)
338962306a36Sopenharmony_ci{
339062306a36Sopenharmony_ci	u32 size = le16_to_cpu(v1->sHeader.usStructureSize);
339162306a36Sopenharmony_ci	u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO, asVoltageObj[0]);
339262306a36Sopenharmony_ci	u8 *start = (u8 *)v1;
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci	while (offset < size) {
339562306a36Sopenharmony_ci		ATOM_VOLTAGE_OBJECT *vo = (ATOM_VOLTAGE_OBJECT *)(start + offset);
339662306a36Sopenharmony_ci		if (vo->ucVoltageType == voltage_type)
339762306a36Sopenharmony_ci			return vo;
339862306a36Sopenharmony_ci		offset += offsetof(ATOM_VOLTAGE_OBJECT, asFormula.ucVIDAdjustEntries) +
339962306a36Sopenharmony_ci			vo->asFormula.ucNumOfVoltageEntries;
340062306a36Sopenharmony_ci	}
340162306a36Sopenharmony_ci	return NULL;
340262306a36Sopenharmony_ci}
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_cistatic ATOM_VOLTAGE_OBJECT_V2 *atom_lookup_voltage_object_v2(ATOM_VOLTAGE_OBJECT_INFO_V2 *v2,
340562306a36Sopenharmony_ci							     u8 voltage_type)
340662306a36Sopenharmony_ci{
340762306a36Sopenharmony_ci	u32 size = le16_to_cpu(v2->sHeader.usStructureSize);
340862306a36Sopenharmony_ci	u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V2, asVoltageObj[0]);
340962306a36Sopenharmony_ci	u8 *start = (u8 *)v2;
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci	while (offset < size) {
341262306a36Sopenharmony_ci		ATOM_VOLTAGE_OBJECT_V2 *vo = (ATOM_VOLTAGE_OBJECT_V2 *)(start + offset);
341362306a36Sopenharmony_ci		if (vo->ucVoltageType == voltage_type)
341462306a36Sopenharmony_ci			return vo;
341562306a36Sopenharmony_ci		offset += offsetof(ATOM_VOLTAGE_OBJECT_V2, asFormula.asVIDAdjustEntries) +
341662306a36Sopenharmony_ci			(vo->asFormula.ucNumOfVoltageEntries * sizeof(VOLTAGE_LUT_ENTRY));
341762306a36Sopenharmony_ci	}
341862306a36Sopenharmony_ci	return NULL;
341962306a36Sopenharmony_ci}
342062306a36Sopenharmony_ci
342162306a36Sopenharmony_cistatic ATOM_VOLTAGE_OBJECT_V3 *atom_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3,
342262306a36Sopenharmony_ci							     u8 voltage_type, u8 voltage_mode)
342362306a36Sopenharmony_ci{
342462306a36Sopenharmony_ci	u32 size = le16_to_cpu(v3->sHeader.usStructureSize);
342562306a36Sopenharmony_ci	u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
342662306a36Sopenharmony_ci	u8 *start = (u8 *)v3;
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	while (offset < size) {
342962306a36Sopenharmony_ci		ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
343062306a36Sopenharmony_ci		if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) &&
343162306a36Sopenharmony_ci		    (vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode))
343262306a36Sopenharmony_ci			return vo;
343362306a36Sopenharmony_ci		offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize);
343462306a36Sopenharmony_ci	}
343562306a36Sopenharmony_ci	return NULL;
343662306a36Sopenharmony_ci}
343762306a36Sopenharmony_ci
343862306a36Sopenharmony_cibool
343962306a36Sopenharmony_ciradeon_atom_is_voltage_gpio(struct radeon_device *rdev,
344062306a36Sopenharmony_ci			    u8 voltage_type, u8 voltage_mode)
344162306a36Sopenharmony_ci{
344262306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
344362306a36Sopenharmony_ci	u8 frev, crev;
344462306a36Sopenharmony_ci	u16 data_offset, size;
344562306a36Sopenharmony_ci	union voltage_object_info *voltage_info;
344662306a36Sopenharmony_ci	union voltage_object *voltage_object = NULL;
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
344962306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
345062306a36Sopenharmony_ci		voltage_info = (union voltage_object_info *)
345162306a36Sopenharmony_ci			(rdev->mode_info.atom_context->bios + data_offset);
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci		switch (frev) {
345462306a36Sopenharmony_ci		case 1:
345562306a36Sopenharmony_ci		case 2:
345662306a36Sopenharmony_ci			switch (crev) {
345762306a36Sopenharmony_ci			case 1:
345862306a36Sopenharmony_ci				voltage_object = (union voltage_object *)
345962306a36Sopenharmony_ci					atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
346062306a36Sopenharmony_ci				if (voltage_object &&
346162306a36Sopenharmony_ci				    (voltage_object->v1.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
346262306a36Sopenharmony_ci					return true;
346362306a36Sopenharmony_ci				break;
346462306a36Sopenharmony_ci			case 2:
346562306a36Sopenharmony_ci				voltage_object = (union voltage_object *)
346662306a36Sopenharmony_ci					atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
346762306a36Sopenharmony_ci				if (voltage_object &&
346862306a36Sopenharmony_ci				    (voltage_object->v2.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
346962306a36Sopenharmony_ci					return true;
347062306a36Sopenharmony_ci				break;
347162306a36Sopenharmony_ci			default:
347262306a36Sopenharmony_ci				DRM_ERROR("unknown voltage object table\n");
347362306a36Sopenharmony_ci				return false;
347462306a36Sopenharmony_ci			}
347562306a36Sopenharmony_ci			break;
347662306a36Sopenharmony_ci		case 3:
347762306a36Sopenharmony_ci			switch (crev) {
347862306a36Sopenharmony_ci			case 1:
347962306a36Sopenharmony_ci				if (atom_lookup_voltage_object_v3(&voltage_info->v3,
348062306a36Sopenharmony_ci								  voltage_type, voltage_mode))
348162306a36Sopenharmony_ci					return true;
348262306a36Sopenharmony_ci				break;
348362306a36Sopenharmony_ci			default:
348462306a36Sopenharmony_ci				DRM_ERROR("unknown voltage object table\n");
348562306a36Sopenharmony_ci				return false;
348662306a36Sopenharmony_ci			}
348762306a36Sopenharmony_ci			break;
348862306a36Sopenharmony_ci		default:
348962306a36Sopenharmony_ci			DRM_ERROR("unknown voltage object table\n");
349062306a36Sopenharmony_ci			return false;
349162306a36Sopenharmony_ci		}
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci	}
349462306a36Sopenharmony_ci	return false;
349562306a36Sopenharmony_ci}
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ciint radeon_atom_get_svi2_info(struct radeon_device *rdev,
349862306a36Sopenharmony_ci			      u8 voltage_type,
349962306a36Sopenharmony_ci			      u8 *svd_gpio_id, u8 *svc_gpio_id)
350062306a36Sopenharmony_ci{
350162306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
350262306a36Sopenharmony_ci	u8 frev, crev;
350362306a36Sopenharmony_ci	u16 data_offset, size;
350462306a36Sopenharmony_ci	union voltage_object_info *voltage_info;
350562306a36Sopenharmony_ci	union voltage_object *voltage_object = NULL;
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
350862306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
350962306a36Sopenharmony_ci		voltage_info = (union voltage_object_info *)
351062306a36Sopenharmony_ci			(rdev->mode_info.atom_context->bios + data_offset);
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci		switch (frev) {
351362306a36Sopenharmony_ci		case 3:
351462306a36Sopenharmony_ci			switch (crev) {
351562306a36Sopenharmony_ci			case 1:
351662306a36Sopenharmony_ci				voltage_object = (union voltage_object *)
351762306a36Sopenharmony_ci					atom_lookup_voltage_object_v3(&voltage_info->v3,
351862306a36Sopenharmony_ci								      voltage_type,
351962306a36Sopenharmony_ci								      VOLTAGE_OBJ_SVID2);
352062306a36Sopenharmony_ci				if (voltage_object) {
352162306a36Sopenharmony_ci					*svd_gpio_id = voltage_object->v3.asSVID2Obj.ucSVDGpioId;
352262306a36Sopenharmony_ci					*svc_gpio_id = voltage_object->v3.asSVID2Obj.ucSVCGpioId;
352362306a36Sopenharmony_ci				} else {
352462306a36Sopenharmony_ci					return -EINVAL;
352562306a36Sopenharmony_ci				}
352662306a36Sopenharmony_ci				break;
352762306a36Sopenharmony_ci			default:
352862306a36Sopenharmony_ci				DRM_ERROR("unknown voltage object table\n");
352962306a36Sopenharmony_ci				return -EINVAL;
353062306a36Sopenharmony_ci			}
353162306a36Sopenharmony_ci			break;
353262306a36Sopenharmony_ci		default:
353362306a36Sopenharmony_ci			DRM_ERROR("unknown voltage object table\n");
353462306a36Sopenharmony_ci			return -EINVAL;
353562306a36Sopenharmony_ci		}
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_ci	}
353862306a36Sopenharmony_ci	return 0;
353962306a36Sopenharmony_ci}
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ciint radeon_atom_get_max_voltage(struct radeon_device *rdev,
354262306a36Sopenharmony_ci				u8 voltage_type, u16 *max_voltage)
354362306a36Sopenharmony_ci{
354462306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
354562306a36Sopenharmony_ci	u8 frev, crev;
354662306a36Sopenharmony_ci	u16 data_offset, size;
354762306a36Sopenharmony_ci	union voltage_object_info *voltage_info;
354862306a36Sopenharmony_ci	union voltage_object *voltage_object = NULL;
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
355162306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
355262306a36Sopenharmony_ci		voltage_info = (union voltage_object_info *)
355362306a36Sopenharmony_ci			(rdev->mode_info.atom_context->bios + data_offset);
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci		switch (crev) {
355662306a36Sopenharmony_ci		case 1:
355762306a36Sopenharmony_ci			voltage_object = (union voltage_object *)
355862306a36Sopenharmony_ci				atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
355962306a36Sopenharmony_ci			if (voltage_object) {
356062306a36Sopenharmony_ci				ATOM_VOLTAGE_FORMULA *formula =
356162306a36Sopenharmony_ci					&voltage_object->v1.asFormula;
356262306a36Sopenharmony_ci				if (formula->ucFlag & 1)
356362306a36Sopenharmony_ci					*max_voltage =
356462306a36Sopenharmony_ci						le16_to_cpu(formula->usVoltageBaseLevel) +
356562306a36Sopenharmony_ci						formula->ucNumOfVoltageEntries / 2 *
356662306a36Sopenharmony_ci						le16_to_cpu(formula->usVoltageStep);
356762306a36Sopenharmony_ci				else
356862306a36Sopenharmony_ci					*max_voltage =
356962306a36Sopenharmony_ci						le16_to_cpu(formula->usVoltageBaseLevel) +
357062306a36Sopenharmony_ci						(formula->ucNumOfVoltageEntries - 1) *
357162306a36Sopenharmony_ci						le16_to_cpu(formula->usVoltageStep);
357262306a36Sopenharmony_ci				return 0;
357362306a36Sopenharmony_ci			}
357462306a36Sopenharmony_ci			break;
357562306a36Sopenharmony_ci		case 2:
357662306a36Sopenharmony_ci			voltage_object = (union voltage_object *)
357762306a36Sopenharmony_ci				atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
357862306a36Sopenharmony_ci			if (voltage_object) {
357962306a36Sopenharmony_ci				ATOM_VOLTAGE_FORMULA_V2 *formula =
358062306a36Sopenharmony_ci					&voltage_object->v2.asFormula;
358162306a36Sopenharmony_ci				if (formula->ucNumOfVoltageEntries) {
358262306a36Sopenharmony_ci					VOLTAGE_LUT_ENTRY *lut = (VOLTAGE_LUT_ENTRY *)
358362306a36Sopenharmony_ci						((u8 *)&formula->asVIDAdjustEntries[0] +
358462306a36Sopenharmony_ci						 (sizeof(VOLTAGE_LUT_ENTRY) * (formula->ucNumOfVoltageEntries - 1)));
358562306a36Sopenharmony_ci					*max_voltage =
358662306a36Sopenharmony_ci						le16_to_cpu(lut->usVoltageValue);
358762306a36Sopenharmony_ci					return 0;
358862306a36Sopenharmony_ci				}
358962306a36Sopenharmony_ci			}
359062306a36Sopenharmony_ci			break;
359162306a36Sopenharmony_ci		default:
359262306a36Sopenharmony_ci			DRM_ERROR("unknown voltage object table\n");
359362306a36Sopenharmony_ci			return -EINVAL;
359462306a36Sopenharmony_ci		}
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci	}
359762306a36Sopenharmony_ci	return -EINVAL;
359862306a36Sopenharmony_ci}
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ciint radeon_atom_get_min_voltage(struct radeon_device *rdev,
360162306a36Sopenharmony_ci				u8 voltage_type, u16 *min_voltage)
360262306a36Sopenharmony_ci{
360362306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
360462306a36Sopenharmony_ci	u8 frev, crev;
360562306a36Sopenharmony_ci	u16 data_offset, size;
360662306a36Sopenharmony_ci	union voltage_object_info *voltage_info;
360762306a36Sopenharmony_ci	union voltage_object *voltage_object = NULL;
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
361062306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
361162306a36Sopenharmony_ci		voltage_info = (union voltage_object_info *)
361262306a36Sopenharmony_ci			(rdev->mode_info.atom_context->bios + data_offset);
361362306a36Sopenharmony_ci
361462306a36Sopenharmony_ci		switch (crev) {
361562306a36Sopenharmony_ci		case 1:
361662306a36Sopenharmony_ci			voltage_object = (union voltage_object *)
361762306a36Sopenharmony_ci				atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
361862306a36Sopenharmony_ci			if (voltage_object) {
361962306a36Sopenharmony_ci				ATOM_VOLTAGE_FORMULA *formula =
362062306a36Sopenharmony_ci					&voltage_object->v1.asFormula;
362162306a36Sopenharmony_ci				*min_voltage =
362262306a36Sopenharmony_ci					le16_to_cpu(formula->usVoltageBaseLevel);
362362306a36Sopenharmony_ci				return 0;
362462306a36Sopenharmony_ci			}
362562306a36Sopenharmony_ci			break;
362662306a36Sopenharmony_ci		case 2:
362762306a36Sopenharmony_ci			voltage_object = (union voltage_object *)
362862306a36Sopenharmony_ci				atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
362962306a36Sopenharmony_ci			if (voltage_object) {
363062306a36Sopenharmony_ci				ATOM_VOLTAGE_FORMULA_V2 *formula =
363162306a36Sopenharmony_ci					&voltage_object->v2.asFormula;
363262306a36Sopenharmony_ci				if (formula->ucNumOfVoltageEntries) {
363362306a36Sopenharmony_ci					*min_voltage =
363462306a36Sopenharmony_ci						le16_to_cpu(formula->asVIDAdjustEntries[
363562306a36Sopenharmony_ci								    0
363662306a36Sopenharmony_ci								    ].usVoltageValue);
363762306a36Sopenharmony_ci					return 0;
363862306a36Sopenharmony_ci				}
363962306a36Sopenharmony_ci			}
364062306a36Sopenharmony_ci			break;
364162306a36Sopenharmony_ci		default:
364262306a36Sopenharmony_ci			DRM_ERROR("unknown voltage object table\n");
364362306a36Sopenharmony_ci			return -EINVAL;
364462306a36Sopenharmony_ci		}
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci	}
364762306a36Sopenharmony_ci	return -EINVAL;
364862306a36Sopenharmony_ci}
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_ciint radeon_atom_get_voltage_step(struct radeon_device *rdev,
365162306a36Sopenharmony_ci				 u8 voltage_type, u16 *voltage_step)
365262306a36Sopenharmony_ci{
365362306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
365462306a36Sopenharmony_ci	u8 frev, crev;
365562306a36Sopenharmony_ci	u16 data_offset, size;
365662306a36Sopenharmony_ci	union voltage_object_info *voltage_info;
365762306a36Sopenharmony_ci	union voltage_object *voltage_object = NULL;
365862306a36Sopenharmony_ci
365962306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
366062306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
366162306a36Sopenharmony_ci		voltage_info = (union voltage_object_info *)
366262306a36Sopenharmony_ci			(rdev->mode_info.atom_context->bios + data_offset);
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_ci		switch (crev) {
366562306a36Sopenharmony_ci		case 1:
366662306a36Sopenharmony_ci			voltage_object = (union voltage_object *)
366762306a36Sopenharmony_ci				atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
366862306a36Sopenharmony_ci			if (voltage_object) {
366962306a36Sopenharmony_ci				ATOM_VOLTAGE_FORMULA *formula =
367062306a36Sopenharmony_ci					&voltage_object->v1.asFormula;
367162306a36Sopenharmony_ci				if (formula->ucFlag & 1)
367262306a36Sopenharmony_ci					*voltage_step =
367362306a36Sopenharmony_ci						(le16_to_cpu(formula->usVoltageStep) + 1) / 2;
367462306a36Sopenharmony_ci				else
367562306a36Sopenharmony_ci					*voltage_step =
367662306a36Sopenharmony_ci						le16_to_cpu(formula->usVoltageStep);
367762306a36Sopenharmony_ci				return 0;
367862306a36Sopenharmony_ci			}
367962306a36Sopenharmony_ci			break;
368062306a36Sopenharmony_ci		case 2:
368162306a36Sopenharmony_ci			return -EINVAL;
368262306a36Sopenharmony_ci		default:
368362306a36Sopenharmony_ci			DRM_ERROR("unknown voltage object table\n");
368462306a36Sopenharmony_ci			return -EINVAL;
368562306a36Sopenharmony_ci		}
368662306a36Sopenharmony_ci
368762306a36Sopenharmony_ci	}
368862306a36Sopenharmony_ci	return -EINVAL;
368962306a36Sopenharmony_ci}
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_ciint radeon_atom_round_to_true_voltage(struct radeon_device *rdev,
369262306a36Sopenharmony_ci				      u8 voltage_type,
369362306a36Sopenharmony_ci				      u16 nominal_voltage,
369462306a36Sopenharmony_ci				      u16 *true_voltage)
369562306a36Sopenharmony_ci{
369662306a36Sopenharmony_ci	u16 min_voltage, max_voltage, voltage_step;
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci	if (radeon_atom_get_max_voltage(rdev, voltage_type, &max_voltage))
369962306a36Sopenharmony_ci		return -EINVAL;
370062306a36Sopenharmony_ci	if (radeon_atom_get_min_voltage(rdev, voltage_type, &min_voltage))
370162306a36Sopenharmony_ci		return -EINVAL;
370262306a36Sopenharmony_ci	if (radeon_atom_get_voltage_step(rdev, voltage_type, &voltage_step))
370362306a36Sopenharmony_ci		return -EINVAL;
370462306a36Sopenharmony_ci
370562306a36Sopenharmony_ci	if (nominal_voltage <= min_voltage)
370662306a36Sopenharmony_ci		*true_voltage = min_voltage;
370762306a36Sopenharmony_ci	else if (nominal_voltage >= max_voltage)
370862306a36Sopenharmony_ci		*true_voltage = max_voltage;
370962306a36Sopenharmony_ci	else
371062306a36Sopenharmony_ci		*true_voltage = min_voltage +
371162306a36Sopenharmony_ci			((nominal_voltage - min_voltage) / voltage_step) *
371262306a36Sopenharmony_ci			voltage_step;
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci	return 0;
371562306a36Sopenharmony_ci}
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ciint radeon_atom_get_voltage_table(struct radeon_device *rdev,
371862306a36Sopenharmony_ci				  u8 voltage_type, u8 voltage_mode,
371962306a36Sopenharmony_ci				  struct atom_voltage_table *voltage_table)
372062306a36Sopenharmony_ci{
372162306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
372262306a36Sopenharmony_ci	u8 frev, crev;
372362306a36Sopenharmony_ci	u16 data_offset, size;
372462306a36Sopenharmony_ci	int i, ret;
372562306a36Sopenharmony_ci	union voltage_object_info *voltage_info;
372662306a36Sopenharmony_ci	union voltage_object *voltage_object = NULL;
372762306a36Sopenharmony_ci
372862306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
372962306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
373062306a36Sopenharmony_ci		voltage_info = (union voltage_object_info *)
373162306a36Sopenharmony_ci			(rdev->mode_info.atom_context->bios + data_offset);
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci		switch (frev) {
373462306a36Sopenharmony_ci		case 1:
373562306a36Sopenharmony_ci		case 2:
373662306a36Sopenharmony_ci			switch (crev) {
373762306a36Sopenharmony_ci			case 1:
373862306a36Sopenharmony_ci				DRM_ERROR("old table version %d, %d\n", frev, crev);
373962306a36Sopenharmony_ci				return -EINVAL;
374062306a36Sopenharmony_ci			case 2:
374162306a36Sopenharmony_ci				voltage_object = (union voltage_object *)
374262306a36Sopenharmony_ci					atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
374362306a36Sopenharmony_ci				if (voltage_object) {
374462306a36Sopenharmony_ci					ATOM_VOLTAGE_FORMULA_V2 *formula =
374562306a36Sopenharmony_ci						&voltage_object->v2.asFormula;
374662306a36Sopenharmony_ci					VOLTAGE_LUT_ENTRY *lut;
374762306a36Sopenharmony_ci					if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES)
374862306a36Sopenharmony_ci						return -EINVAL;
374962306a36Sopenharmony_ci					lut = &formula->asVIDAdjustEntries[0];
375062306a36Sopenharmony_ci					for (i = 0; i < formula->ucNumOfVoltageEntries; i++) {
375162306a36Sopenharmony_ci						voltage_table->entries[i].value =
375262306a36Sopenharmony_ci							le16_to_cpu(lut->usVoltageValue);
375362306a36Sopenharmony_ci						ret = radeon_atom_get_voltage_gpio_settings(rdev,
375462306a36Sopenharmony_ci											    voltage_table->entries[i].value,
375562306a36Sopenharmony_ci											    voltage_type,
375662306a36Sopenharmony_ci											    &voltage_table->entries[i].smio_low,
375762306a36Sopenharmony_ci											    &voltage_table->mask_low);
375862306a36Sopenharmony_ci						if (ret)
375962306a36Sopenharmony_ci							return ret;
376062306a36Sopenharmony_ci						lut = (VOLTAGE_LUT_ENTRY *)
376162306a36Sopenharmony_ci							((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY));
376262306a36Sopenharmony_ci					}
376362306a36Sopenharmony_ci					voltage_table->count = formula->ucNumOfVoltageEntries;
376462306a36Sopenharmony_ci					return 0;
376562306a36Sopenharmony_ci				}
376662306a36Sopenharmony_ci				break;
376762306a36Sopenharmony_ci			default:
376862306a36Sopenharmony_ci				DRM_ERROR("unknown voltage object table\n");
376962306a36Sopenharmony_ci				return -EINVAL;
377062306a36Sopenharmony_ci			}
377162306a36Sopenharmony_ci			break;
377262306a36Sopenharmony_ci		case 3:
377362306a36Sopenharmony_ci			switch (crev) {
377462306a36Sopenharmony_ci			case 1:
377562306a36Sopenharmony_ci				voltage_object = (union voltage_object *)
377662306a36Sopenharmony_ci					atom_lookup_voltage_object_v3(&voltage_info->v3,
377762306a36Sopenharmony_ci								      voltage_type, voltage_mode);
377862306a36Sopenharmony_ci				if (voltage_object) {
377962306a36Sopenharmony_ci					ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio =
378062306a36Sopenharmony_ci						&voltage_object->v3.asGpioVoltageObj;
378162306a36Sopenharmony_ci					VOLTAGE_LUT_ENTRY_V2 *lut;
378262306a36Sopenharmony_ci					if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES)
378362306a36Sopenharmony_ci						return -EINVAL;
378462306a36Sopenharmony_ci					lut = &gpio->asVolGpioLut[0];
378562306a36Sopenharmony_ci					for (i = 0; i < gpio->ucGpioEntryNum; i++) {
378662306a36Sopenharmony_ci						voltage_table->entries[i].value =
378762306a36Sopenharmony_ci							le16_to_cpu(lut->usVoltageValue);
378862306a36Sopenharmony_ci						voltage_table->entries[i].smio_low =
378962306a36Sopenharmony_ci							le32_to_cpu(lut->ulVoltageId);
379062306a36Sopenharmony_ci						lut = (VOLTAGE_LUT_ENTRY_V2 *)
379162306a36Sopenharmony_ci							((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY_V2));
379262306a36Sopenharmony_ci					}
379362306a36Sopenharmony_ci					voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal);
379462306a36Sopenharmony_ci					voltage_table->count = gpio->ucGpioEntryNum;
379562306a36Sopenharmony_ci					voltage_table->phase_delay = gpio->ucPhaseDelay;
379662306a36Sopenharmony_ci					return 0;
379762306a36Sopenharmony_ci				}
379862306a36Sopenharmony_ci				break;
379962306a36Sopenharmony_ci			default:
380062306a36Sopenharmony_ci				DRM_ERROR("unknown voltage object table\n");
380162306a36Sopenharmony_ci				return -EINVAL;
380262306a36Sopenharmony_ci			}
380362306a36Sopenharmony_ci			break;
380462306a36Sopenharmony_ci		default:
380562306a36Sopenharmony_ci			DRM_ERROR("unknown voltage object table\n");
380662306a36Sopenharmony_ci			return -EINVAL;
380762306a36Sopenharmony_ci		}
380862306a36Sopenharmony_ci	}
380962306a36Sopenharmony_ci	return -EINVAL;
381062306a36Sopenharmony_ci}
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ciunion vram_info {
381362306a36Sopenharmony_ci	struct _ATOM_VRAM_INFO_V3 v1_3;
381462306a36Sopenharmony_ci	struct _ATOM_VRAM_INFO_V4 v1_4;
381562306a36Sopenharmony_ci	struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1;
381662306a36Sopenharmony_ci};
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ciint radeon_atom_get_memory_info(struct radeon_device *rdev,
381962306a36Sopenharmony_ci				u8 module_index, struct atom_memory_info *mem_info)
382062306a36Sopenharmony_ci{
382162306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
382262306a36Sopenharmony_ci	u8 frev, crev, i;
382362306a36Sopenharmony_ci	u16 data_offset, size;
382462306a36Sopenharmony_ci	union vram_info *vram_info;
382562306a36Sopenharmony_ci
382662306a36Sopenharmony_ci	memset(mem_info, 0, sizeof(struct atom_memory_info));
382762306a36Sopenharmony_ci
382862306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
382962306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
383062306a36Sopenharmony_ci		vram_info = (union vram_info *)
383162306a36Sopenharmony_ci			(rdev->mode_info.atom_context->bios + data_offset);
383262306a36Sopenharmony_ci		switch (frev) {
383362306a36Sopenharmony_ci		case 1:
383462306a36Sopenharmony_ci			switch (crev) {
383562306a36Sopenharmony_ci			case 3:
383662306a36Sopenharmony_ci				/* r6xx */
383762306a36Sopenharmony_ci				if (module_index < vram_info->v1_3.ucNumOfVRAMModule) {
383862306a36Sopenharmony_ci					ATOM_VRAM_MODULE_V3 *vram_module =
383962306a36Sopenharmony_ci						(ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo;
384062306a36Sopenharmony_ci
384162306a36Sopenharmony_ci					for (i = 0; i < module_index; i++) {
384262306a36Sopenharmony_ci						if (le16_to_cpu(vram_module->usSize) == 0)
384362306a36Sopenharmony_ci							return -EINVAL;
384462306a36Sopenharmony_ci						vram_module = (ATOM_VRAM_MODULE_V3 *)
384562306a36Sopenharmony_ci							((u8 *)vram_module + le16_to_cpu(vram_module->usSize));
384662306a36Sopenharmony_ci					}
384762306a36Sopenharmony_ci					mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf;
384862306a36Sopenharmony_ci					mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0;
384962306a36Sopenharmony_ci				} else
385062306a36Sopenharmony_ci					return -EINVAL;
385162306a36Sopenharmony_ci				break;
385262306a36Sopenharmony_ci			case 4:
385362306a36Sopenharmony_ci				/* r7xx, evergreen */
385462306a36Sopenharmony_ci				if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
385562306a36Sopenharmony_ci					ATOM_VRAM_MODULE_V4 *vram_module =
385662306a36Sopenharmony_ci						(ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_ci					for (i = 0; i < module_index; i++) {
385962306a36Sopenharmony_ci						if (le16_to_cpu(vram_module->usModuleSize) == 0)
386062306a36Sopenharmony_ci							return -EINVAL;
386162306a36Sopenharmony_ci						vram_module = (ATOM_VRAM_MODULE_V4 *)
386262306a36Sopenharmony_ci							((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
386362306a36Sopenharmony_ci					}
386462306a36Sopenharmony_ci					mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
386562306a36Sopenharmony_ci					mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
386662306a36Sopenharmony_ci				} else
386762306a36Sopenharmony_ci					return -EINVAL;
386862306a36Sopenharmony_ci				break;
386962306a36Sopenharmony_ci			default:
387062306a36Sopenharmony_ci				DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
387162306a36Sopenharmony_ci				return -EINVAL;
387262306a36Sopenharmony_ci			}
387362306a36Sopenharmony_ci			break;
387462306a36Sopenharmony_ci		case 2:
387562306a36Sopenharmony_ci			switch (crev) {
387662306a36Sopenharmony_ci			case 1:
387762306a36Sopenharmony_ci				/* ni */
387862306a36Sopenharmony_ci				if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
387962306a36Sopenharmony_ci					ATOM_VRAM_MODULE_V7 *vram_module =
388062306a36Sopenharmony_ci						(ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo;
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ci					for (i = 0; i < module_index; i++) {
388362306a36Sopenharmony_ci						if (le16_to_cpu(vram_module->usModuleSize) == 0)
388462306a36Sopenharmony_ci							return -EINVAL;
388562306a36Sopenharmony_ci						vram_module = (ATOM_VRAM_MODULE_V7 *)
388662306a36Sopenharmony_ci							((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
388762306a36Sopenharmony_ci					}
388862306a36Sopenharmony_ci					mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
388962306a36Sopenharmony_ci					mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
389062306a36Sopenharmony_ci				} else
389162306a36Sopenharmony_ci					return -EINVAL;
389262306a36Sopenharmony_ci				break;
389362306a36Sopenharmony_ci			default:
389462306a36Sopenharmony_ci				DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
389562306a36Sopenharmony_ci				return -EINVAL;
389662306a36Sopenharmony_ci			}
389762306a36Sopenharmony_ci			break;
389862306a36Sopenharmony_ci		default:
389962306a36Sopenharmony_ci			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
390062306a36Sopenharmony_ci			return -EINVAL;
390162306a36Sopenharmony_ci		}
390262306a36Sopenharmony_ci		return 0;
390362306a36Sopenharmony_ci	}
390462306a36Sopenharmony_ci	return -EINVAL;
390562306a36Sopenharmony_ci}
390662306a36Sopenharmony_ci
390762306a36Sopenharmony_ciint radeon_atom_get_mclk_range_table(struct radeon_device *rdev,
390862306a36Sopenharmony_ci				     bool gddr5, u8 module_index,
390962306a36Sopenharmony_ci				     struct atom_memory_clock_range_table *mclk_range_table)
391062306a36Sopenharmony_ci{
391162306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
391262306a36Sopenharmony_ci	u8 frev, crev, i;
391362306a36Sopenharmony_ci	u16 data_offset, size;
391462306a36Sopenharmony_ci	union vram_info *vram_info;
391562306a36Sopenharmony_ci	u32 mem_timing_size = gddr5 ?
391662306a36Sopenharmony_ci		sizeof(ATOM_MEMORY_TIMING_FORMAT_V2) : sizeof(ATOM_MEMORY_TIMING_FORMAT);
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci	memset(mclk_range_table, 0, sizeof(struct atom_memory_clock_range_table));
391962306a36Sopenharmony_ci
392062306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
392162306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
392262306a36Sopenharmony_ci		vram_info = (union vram_info *)
392362306a36Sopenharmony_ci			(rdev->mode_info.atom_context->bios + data_offset);
392462306a36Sopenharmony_ci		switch (frev) {
392562306a36Sopenharmony_ci		case 1:
392662306a36Sopenharmony_ci			switch (crev) {
392762306a36Sopenharmony_ci			case 3:
392862306a36Sopenharmony_ci				DRM_ERROR("old table version %d, %d\n", frev, crev);
392962306a36Sopenharmony_ci				return -EINVAL;
393062306a36Sopenharmony_ci			case 4:
393162306a36Sopenharmony_ci				/* r7xx, evergreen */
393262306a36Sopenharmony_ci				if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
393362306a36Sopenharmony_ci					ATOM_VRAM_MODULE_V4 *vram_module =
393462306a36Sopenharmony_ci						(ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
393562306a36Sopenharmony_ci					ATOM_MEMORY_TIMING_FORMAT *format;
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci					for (i = 0; i < module_index; i++) {
393862306a36Sopenharmony_ci						if (le16_to_cpu(vram_module->usModuleSize) == 0)
393962306a36Sopenharmony_ci							return -EINVAL;
394062306a36Sopenharmony_ci						vram_module = (ATOM_VRAM_MODULE_V4 *)
394162306a36Sopenharmony_ci							((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
394262306a36Sopenharmony_ci					}
394362306a36Sopenharmony_ci					mclk_range_table->num_entries = (u8)
394462306a36Sopenharmony_ci						((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) /
394562306a36Sopenharmony_ci						 mem_timing_size);
394662306a36Sopenharmony_ci					format = &vram_module->asMemTiming[0];
394762306a36Sopenharmony_ci					for (i = 0; i < mclk_range_table->num_entries; i++) {
394862306a36Sopenharmony_ci						mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange);
394962306a36Sopenharmony_ci						format = (ATOM_MEMORY_TIMING_FORMAT *)
395062306a36Sopenharmony_ci							((u8 *)format + mem_timing_size);
395162306a36Sopenharmony_ci					}
395262306a36Sopenharmony_ci				} else
395362306a36Sopenharmony_ci					return -EINVAL;
395462306a36Sopenharmony_ci				break;
395562306a36Sopenharmony_ci			default:
395662306a36Sopenharmony_ci				DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
395762306a36Sopenharmony_ci				return -EINVAL;
395862306a36Sopenharmony_ci			}
395962306a36Sopenharmony_ci			break;
396062306a36Sopenharmony_ci		case 2:
396162306a36Sopenharmony_ci			DRM_ERROR("new table version %d, %d\n", frev, crev);
396262306a36Sopenharmony_ci			return -EINVAL;
396362306a36Sopenharmony_ci		default:
396462306a36Sopenharmony_ci			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
396562306a36Sopenharmony_ci			return -EINVAL;
396662306a36Sopenharmony_ci		}
396762306a36Sopenharmony_ci		return 0;
396862306a36Sopenharmony_ci	}
396962306a36Sopenharmony_ci	return -EINVAL;
397062306a36Sopenharmony_ci}
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_ci#define MEM_ID_MASK           0xff000000
397362306a36Sopenharmony_ci#define MEM_ID_SHIFT          24
397462306a36Sopenharmony_ci#define CLOCK_RANGE_MASK      0x00ffffff
397562306a36Sopenharmony_ci#define CLOCK_RANGE_SHIFT     0
397662306a36Sopenharmony_ci#define LOW_NIBBLE_MASK       0xf
397762306a36Sopenharmony_ci#define DATA_EQU_PREV         0
397862306a36Sopenharmony_ci#define DATA_FROM_TABLE       4
397962306a36Sopenharmony_ci
398062306a36Sopenharmony_ciint radeon_atom_init_mc_reg_table(struct radeon_device *rdev,
398162306a36Sopenharmony_ci				  u8 module_index,
398262306a36Sopenharmony_ci				  struct atom_mc_reg_table *reg_table)
398362306a36Sopenharmony_ci{
398462306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
398562306a36Sopenharmony_ci	u8 frev, crev, num_entries, t_mem_id, num_ranges = 0;
398662306a36Sopenharmony_ci	u32 i = 0, j;
398762306a36Sopenharmony_ci	u16 data_offset, size;
398862306a36Sopenharmony_ci	union vram_info *vram_info;
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_ci	memset(reg_table, 0, sizeof(struct atom_mc_reg_table));
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
399362306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
399462306a36Sopenharmony_ci		vram_info = (union vram_info *)
399562306a36Sopenharmony_ci			(rdev->mode_info.atom_context->bios + data_offset);
399662306a36Sopenharmony_ci		switch (frev) {
399762306a36Sopenharmony_ci		case 1:
399862306a36Sopenharmony_ci			DRM_ERROR("old table version %d, %d\n", frev, crev);
399962306a36Sopenharmony_ci			return -EINVAL;
400062306a36Sopenharmony_ci		case 2:
400162306a36Sopenharmony_ci			switch (crev) {
400262306a36Sopenharmony_ci			case 1:
400362306a36Sopenharmony_ci				if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
400462306a36Sopenharmony_ci					ATOM_INIT_REG_BLOCK *reg_block =
400562306a36Sopenharmony_ci						(ATOM_INIT_REG_BLOCK *)
400662306a36Sopenharmony_ci						((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset));
400762306a36Sopenharmony_ci					ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data =
400862306a36Sopenharmony_ci						(ATOM_MEMORY_SETTING_DATA_BLOCK *)
400962306a36Sopenharmony_ci						((u8 *)reg_block + (2 * sizeof(u16)) +
401062306a36Sopenharmony_ci						 le16_to_cpu(reg_block->usRegIndexTblSize));
401162306a36Sopenharmony_ci					ATOM_INIT_REG_INDEX_FORMAT *format = &reg_block->asRegIndexBuf[0];
401262306a36Sopenharmony_ci					num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) /
401362306a36Sopenharmony_ci							   sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1;
401462306a36Sopenharmony_ci					if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE)
401562306a36Sopenharmony_ci						return -EINVAL;
401662306a36Sopenharmony_ci					while (i < num_entries) {
401762306a36Sopenharmony_ci						if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER)
401862306a36Sopenharmony_ci							break;
401962306a36Sopenharmony_ci						reg_table->mc_reg_address[i].s1 =
402062306a36Sopenharmony_ci							(u16)(le16_to_cpu(format->usRegIndex));
402162306a36Sopenharmony_ci						reg_table->mc_reg_address[i].pre_reg_data =
402262306a36Sopenharmony_ci							(u8)(format->ucPreRegDataLength);
402362306a36Sopenharmony_ci						i++;
402462306a36Sopenharmony_ci						format = (ATOM_INIT_REG_INDEX_FORMAT *)
402562306a36Sopenharmony_ci							((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
402662306a36Sopenharmony_ci					}
402762306a36Sopenharmony_ci					reg_table->last = i;
402862306a36Sopenharmony_ci					while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) &&
402962306a36Sopenharmony_ci					       (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {
403062306a36Sopenharmony_ci						t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK)
403162306a36Sopenharmony_ci								>> MEM_ID_SHIFT);
403262306a36Sopenharmony_ci						if (module_index == t_mem_id) {
403362306a36Sopenharmony_ci							reg_table->mc_reg_table_entry[num_ranges].mclk_max =
403462306a36Sopenharmony_ci								(u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK)
403562306a36Sopenharmony_ci								      >> CLOCK_RANGE_SHIFT);
403662306a36Sopenharmony_ci							for (i = 0, j = 1; i < reg_table->last; i++) {
403762306a36Sopenharmony_ci								if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
403862306a36Sopenharmony_ci									reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
403962306a36Sopenharmony_ci										(u32)le32_to_cpu(*((u32 *)reg_data + j));
404062306a36Sopenharmony_ci									j++;
404162306a36Sopenharmony_ci								} else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
404262306a36Sopenharmony_ci									reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
404362306a36Sopenharmony_ci										reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1];
404462306a36Sopenharmony_ci								}
404562306a36Sopenharmony_ci							}
404662306a36Sopenharmony_ci							num_ranges++;
404762306a36Sopenharmony_ci						}
404862306a36Sopenharmony_ci						reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
404962306a36Sopenharmony_ci							((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));
405062306a36Sopenharmony_ci					}
405162306a36Sopenharmony_ci					if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK)
405262306a36Sopenharmony_ci						return -EINVAL;
405362306a36Sopenharmony_ci					reg_table->num_entries = num_ranges;
405462306a36Sopenharmony_ci				} else
405562306a36Sopenharmony_ci					return -EINVAL;
405662306a36Sopenharmony_ci				break;
405762306a36Sopenharmony_ci			default:
405862306a36Sopenharmony_ci				DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
405962306a36Sopenharmony_ci				return -EINVAL;
406062306a36Sopenharmony_ci			}
406162306a36Sopenharmony_ci			break;
406262306a36Sopenharmony_ci		default:
406362306a36Sopenharmony_ci			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
406462306a36Sopenharmony_ci			return -EINVAL;
406562306a36Sopenharmony_ci		}
406662306a36Sopenharmony_ci		return 0;
406762306a36Sopenharmony_ci	}
406862306a36Sopenharmony_ci	return -EINVAL;
406962306a36Sopenharmony_ci}
407062306a36Sopenharmony_ci
407162306a36Sopenharmony_civoid radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
407262306a36Sopenharmony_ci{
407362306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
407462306a36Sopenharmony_ci	uint32_t bios_2_scratch, bios_6_scratch;
407562306a36Sopenharmony_ci
407662306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600) {
407762306a36Sopenharmony_ci		bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
407862306a36Sopenharmony_ci		bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
407962306a36Sopenharmony_ci	} else {
408062306a36Sopenharmony_ci		bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
408162306a36Sopenharmony_ci		bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
408262306a36Sopenharmony_ci	}
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_ci	/* let the bios control the backlight */
408562306a36Sopenharmony_ci	bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;
408662306a36Sopenharmony_ci
408762306a36Sopenharmony_ci	/* tell the bios not to handle mode switching */
408862306a36Sopenharmony_ci	bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_ci	/* clear the vbios dpms state */
409162306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev))
409262306a36Sopenharmony_ci		bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE;
409362306a36Sopenharmony_ci
409462306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600) {
409562306a36Sopenharmony_ci		WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
409662306a36Sopenharmony_ci		WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
409762306a36Sopenharmony_ci	} else {
409862306a36Sopenharmony_ci		WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
409962306a36Sopenharmony_ci		WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
410062306a36Sopenharmony_ci	}
410162306a36Sopenharmony_ci
410262306a36Sopenharmony_ci}
410362306a36Sopenharmony_ci
410462306a36Sopenharmony_civoid radeon_save_bios_scratch_regs(struct radeon_device *rdev)
410562306a36Sopenharmony_ci{
410662306a36Sopenharmony_ci	uint32_t scratch_reg;
410762306a36Sopenharmony_ci	int i;
410862306a36Sopenharmony_ci
410962306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600)
411062306a36Sopenharmony_ci		scratch_reg = R600_BIOS_0_SCRATCH;
411162306a36Sopenharmony_ci	else
411262306a36Sopenharmony_ci		scratch_reg = RADEON_BIOS_0_SCRATCH;
411362306a36Sopenharmony_ci
411462306a36Sopenharmony_ci	for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++)
411562306a36Sopenharmony_ci		rdev->bios_scratch[i] = RREG32(scratch_reg + (i * 4));
411662306a36Sopenharmony_ci}
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_civoid radeon_restore_bios_scratch_regs(struct radeon_device *rdev)
411962306a36Sopenharmony_ci{
412062306a36Sopenharmony_ci	uint32_t scratch_reg;
412162306a36Sopenharmony_ci	int i;
412262306a36Sopenharmony_ci
412362306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600)
412462306a36Sopenharmony_ci		scratch_reg = R600_BIOS_0_SCRATCH;
412562306a36Sopenharmony_ci	else
412662306a36Sopenharmony_ci		scratch_reg = RADEON_BIOS_0_SCRATCH;
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci	for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++)
412962306a36Sopenharmony_ci		WREG32(scratch_reg + (i * 4), rdev->bios_scratch[i]);
413062306a36Sopenharmony_ci}
413162306a36Sopenharmony_ci
413262306a36Sopenharmony_civoid radeon_atom_output_lock(struct drm_encoder *encoder, bool lock)
413362306a36Sopenharmony_ci{
413462306a36Sopenharmony_ci	struct drm_device *dev = encoder->dev;
413562306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
413662306a36Sopenharmony_ci	uint32_t bios_6_scratch;
413762306a36Sopenharmony_ci
413862306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600)
413962306a36Sopenharmony_ci		bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
414062306a36Sopenharmony_ci	else
414162306a36Sopenharmony_ci		bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_ci	if (lock) {
414462306a36Sopenharmony_ci		bios_6_scratch |= ATOM_S6_CRITICAL_STATE;
414562306a36Sopenharmony_ci		bios_6_scratch &= ~ATOM_S6_ACC_MODE;
414662306a36Sopenharmony_ci	} else {
414762306a36Sopenharmony_ci		bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;
414862306a36Sopenharmony_ci		bios_6_scratch |= ATOM_S6_ACC_MODE;
414962306a36Sopenharmony_ci	}
415062306a36Sopenharmony_ci
415162306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600)
415262306a36Sopenharmony_ci		WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
415362306a36Sopenharmony_ci	else
415462306a36Sopenharmony_ci		WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
415562306a36Sopenharmony_ci}
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_ci/* at some point we may want to break this out into individual functions */
415862306a36Sopenharmony_civoid
415962306a36Sopenharmony_ciradeon_atombios_connected_scratch_regs(struct drm_connector *connector,
416062306a36Sopenharmony_ci				       struct drm_encoder *encoder,
416162306a36Sopenharmony_ci				       bool connected)
416262306a36Sopenharmony_ci{
416362306a36Sopenharmony_ci	struct drm_device *dev = connector->dev;
416462306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
416562306a36Sopenharmony_ci	struct radeon_connector *radeon_connector =
416662306a36Sopenharmony_ci	    to_radeon_connector(connector);
416762306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
416862306a36Sopenharmony_ci	uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch;
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600) {
417162306a36Sopenharmony_ci		bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH);
417262306a36Sopenharmony_ci		bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
417362306a36Sopenharmony_ci		bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
417462306a36Sopenharmony_ci	} else {
417562306a36Sopenharmony_ci		bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
417662306a36Sopenharmony_ci		bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
417762306a36Sopenharmony_ci		bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
417862306a36Sopenharmony_ci	}
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) &&
418162306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) {
418262306a36Sopenharmony_ci		if (connected) {
418362306a36Sopenharmony_ci			DRM_DEBUG_KMS("TV1 connected\n");
418462306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_TV1_ACTIVE;
418562306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_TV1;
418662306a36Sopenharmony_ci		} else {
418762306a36Sopenharmony_ci			DRM_DEBUG_KMS("TV1 disconnected\n");
418862306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_TV1_MASK;
418962306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE;
419062306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1;
419162306a36Sopenharmony_ci		}
419262306a36Sopenharmony_ci	}
419362306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) &&
419462306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) {
419562306a36Sopenharmony_ci		if (connected) {
419662306a36Sopenharmony_ci			DRM_DEBUG_KMS("CV connected\n");
419762306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_CV_ACTIVE;
419862306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_CV;
419962306a36Sopenharmony_ci		} else {
420062306a36Sopenharmony_ci			DRM_DEBUG_KMS("CV disconnected\n");
420162306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_CV_MASK;
420262306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_CV_ACTIVE;
420362306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV;
420462306a36Sopenharmony_ci		}
420562306a36Sopenharmony_ci	}
420662306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
420762306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
420862306a36Sopenharmony_ci		if (connected) {
420962306a36Sopenharmony_ci			DRM_DEBUG_KMS("LCD1 connected\n");
421062306a36Sopenharmony_ci			bios_0_scratch |= ATOM_S0_LCD1;
421162306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_LCD1_ACTIVE;
421262306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1;
421362306a36Sopenharmony_ci		} else {
421462306a36Sopenharmony_ci			DRM_DEBUG_KMS("LCD1 disconnected\n");
421562306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_LCD1;
421662306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE;
421762306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1;
421862306a36Sopenharmony_ci		}
421962306a36Sopenharmony_ci	}
422062306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
422162306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
422262306a36Sopenharmony_ci		if (connected) {
422362306a36Sopenharmony_ci			DRM_DEBUG_KMS("CRT1 connected\n");
422462306a36Sopenharmony_ci			bios_0_scratch |= ATOM_S0_CRT1_COLOR;
422562306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_CRT1_ACTIVE;
422662306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1;
422762306a36Sopenharmony_ci		} else {
422862306a36Sopenharmony_ci			DRM_DEBUG_KMS("CRT1 disconnected\n");
422962306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_CRT1_MASK;
423062306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE;
423162306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1;
423262306a36Sopenharmony_ci		}
423362306a36Sopenharmony_ci	}
423462306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
423562306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
423662306a36Sopenharmony_ci		if (connected) {
423762306a36Sopenharmony_ci			DRM_DEBUG_KMS("CRT2 connected\n");
423862306a36Sopenharmony_ci			bios_0_scratch |= ATOM_S0_CRT2_COLOR;
423962306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_CRT2_ACTIVE;
424062306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2;
424162306a36Sopenharmony_ci		} else {
424262306a36Sopenharmony_ci			DRM_DEBUG_KMS("CRT2 disconnected\n");
424362306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_CRT2_MASK;
424462306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE;
424562306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2;
424662306a36Sopenharmony_ci		}
424762306a36Sopenharmony_ci	}
424862306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
424962306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
425062306a36Sopenharmony_ci		if (connected) {
425162306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP1 connected\n");
425262306a36Sopenharmony_ci			bios_0_scratch |= ATOM_S0_DFP1;
425362306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_DFP1_ACTIVE;
425462306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1;
425562306a36Sopenharmony_ci		} else {
425662306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP1 disconnected\n");
425762306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_DFP1;
425862306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE;
425962306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1;
426062306a36Sopenharmony_ci		}
426162306a36Sopenharmony_ci	}
426262306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
426362306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
426462306a36Sopenharmony_ci		if (connected) {
426562306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP2 connected\n");
426662306a36Sopenharmony_ci			bios_0_scratch |= ATOM_S0_DFP2;
426762306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_DFP2_ACTIVE;
426862306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2;
426962306a36Sopenharmony_ci		} else {
427062306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP2 disconnected\n");
427162306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_DFP2;
427262306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE;
427362306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2;
427462306a36Sopenharmony_ci		}
427562306a36Sopenharmony_ci	}
427662306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) &&
427762306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) {
427862306a36Sopenharmony_ci		if (connected) {
427962306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP3 connected\n");
428062306a36Sopenharmony_ci			bios_0_scratch |= ATOM_S0_DFP3;
428162306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_DFP3_ACTIVE;
428262306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3;
428362306a36Sopenharmony_ci		} else {
428462306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP3 disconnected\n");
428562306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_DFP3;
428662306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE;
428762306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3;
428862306a36Sopenharmony_ci		}
428962306a36Sopenharmony_ci	}
429062306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) &&
429162306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) {
429262306a36Sopenharmony_ci		if (connected) {
429362306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP4 connected\n");
429462306a36Sopenharmony_ci			bios_0_scratch |= ATOM_S0_DFP4;
429562306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_DFP4_ACTIVE;
429662306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4;
429762306a36Sopenharmony_ci		} else {
429862306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP4 disconnected\n");
429962306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_DFP4;
430062306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE;
430162306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4;
430262306a36Sopenharmony_ci		}
430362306a36Sopenharmony_ci	}
430462306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) &&
430562306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) {
430662306a36Sopenharmony_ci		if (connected) {
430762306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP5 connected\n");
430862306a36Sopenharmony_ci			bios_0_scratch |= ATOM_S0_DFP5;
430962306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_DFP5_ACTIVE;
431062306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5;
431162306a36Sopenharmony_ci		} else {
431262306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP5 disconnected\n");
431362306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_DFP5;
431462306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE;
431562306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5;
431662306a36Sopenharmony_ci		}
431762306a36Sopenharmony_ci	}
431862306a36Sopenharmony_ci	if ((radeon_encoder->devices & ATOM_DEVICE_DFP6_SUPPORT) &&
431962306a36Sopenharmony_ci	    (radeon_connector->devices & ATOM_DEVICE_DFP6_SUPPORT)) {
432062306a36Sopenharmony_ci		if (connected) {
432162306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP6 connected\n");
432262306a36Sopenharmony_ci			bios_0_scratch |= ATOM_S0_DFP6;
432362306a36Sopenharmony_ci			bios_3_scratch |= ATOM_S3_DFP6_ACTIVE;
432462306a36Sopenharmony_ci			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP6;
432562306a36Sopenharmony_ci		} else {
432662306a36Sopenharmony_ci			DRM_DEBUG_KMS("DFP6 disconnected\n");
432762306a36Sopenharmony_ci			bios_0_scratch &= ~ATOM_S0_DFP6;
432862306a36Sopenharmony_ci			bios_3_scratch &= ~ATOM_S3_DFP6_ACTIVE;
432962306a36Sopenharmony_ci			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP6;
433062306a36Sopenharmony_ci		}
433162306a36Sopenharmony_ci	}
433262306a36Sopenharmony_ci
433362306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600) {
433462306a36Sopenharmony_ci		WREG32(R600_BIOS_0_SCRATCH, bios_0_scratch);
433562306a36Sopenharmony_ci		WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
433662306a36Sopenharmony_ci		WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
433762306a36Sopenharmony_ci	} else {
433862306a36Sopenharmony_ci		WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch);
433962306a36Sopenharmony_ci		WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
434062306a36Sopenharmony_ci		WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
434162306a36Sopenharmony_ci	}
434262306a36Sopenharmony_ci}
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_civoid
434562306a36Sopenharmony_ciradeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc)
434662306a36Sopenharmony_ci{
434762306a36Sopenharmony_ci	struct drm_device *dev = encoder->dev;
434862306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
434962306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
435062306a36Sopenharmony_ci	uint32_t bios_3_scratch;
435162306a36Sopenharmony_ci
435262306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev))
435362306a36Sopenharmony_ci		return;
435462306a36Sopenharmony_ci
435562306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600)
435662306a36Sopenharmony_ci		bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
435762306a36Sopenharmony_ci	else
435862306a36Sopenharmony_ci		bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
435962306a36Sopenharmony_ci
436062306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
436162306a36Sopenharmony_ci		bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE;
436262306a36Sopenharmony_ci		bios_3_scratch |= (crtc << 18);
436362306a36Sopenharmony_ci	}
436462306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
436562306a36Sopenharmony_ci		bios_3_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE;
436662306a36Sopenharmony_ci		bios_3_scratch |= (crtc << 24);
436762306a36Sopenharmony_ci	}
436862306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
436962306a36Sopenharmony_ci		bios_3_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE;
437062306a36Sopenharmony_ci		bios_3_scratch |= (crtc << 16);
437162306a36Sopenharmony_ci	}
437262306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
437362306a36Sopenharmony_ci		bios_3_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE;
437462306a36Sopenharmony_ci		bios_3_scratch |= (crtc << 20);
437562306a36Sopenharmony_ci	}
437662306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
437762306a36Sopenharmony_ci		bios_3_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE;
437862306a36Sopenharmony_ci		bios_3_scratch |= (crtc << 17);
437962306a36Sopenharmony_ci	}
438062306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
438162306a36Sopenharmony_ci		bios_3_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE;
438262306a36Sopenharmony_ci		bios_3_scratch |= (crtc << 19);
438362306a36Sopenharmony_ci	}
438462306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
438562306a36Sopenharmony_ci		bios_3_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE;
438662306a36Sopenharmony_ci		bios_3_scratch |= (crtc << 23);
438762306a36Sopenharmony_ci	}
438862306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
438962306a36Sopenharmony_ci		bios_3_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE;
439062306a36Sopenharmony_ci		bios_3_scratch |= (crtc << 25);
439162306a36Sopenharmony_ci	}
439262306a36Sopenharmony_ci
439362306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600)
439462306a36Sopenharmony_ci		WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
439562306a36Sopenharmony_ci	else
439662306a36Sopenharmony_ci		WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
439762306a36Sopenharmony_ci}
439862306a36Sopenharmony_ci
439962306a36Sopenharmony_civoid
440062306a36Sopenharmony_ciradeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on)
440162306a36Sopenharmony_ci{
440262306a36Sopenharmony_ci	struct drm_device *dev = encoder->dev;
440362306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
440462306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
440562306a36Sopenharmony_ci	uint32_t bios_2_scratch;
440662306a36Sopenharmony_ci
440762306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev))
440862306a36Sopenharmony_ci		return;
440962306a36Sopenharmony_ci
441062306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600)
441162306a36Sopenharmony_ci		bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
441262306a36Sopenharmony_ci	else
441362306a36Sopenharmony_ci		bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
441662306a36Sopenharmony_ci		if (on)
441762306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE;
441862306a36Sopenharmony_ci		else
441962306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_TV1_DPMS_STATE;
442062306a36Sopenharmony_ci	}
442162306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
442262306a36Sopenharmony_ci		if (on)
442362306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE;
442462306a36Sopenharmony_ci		else
442562306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_CV_DPMS_STATE;
442662306a36Sopenharmony_ci	}
442762306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
442862306a36Sopenharmony_ci		if (on)
442962306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE;
443062306a36Sopenharmony_ci		else
443162306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_CRT1_DPMS_STATE;
443262306a36Sopenharmony_ci	}
443362306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
443462306a36Sopenharmony_ci		if (on)
443562306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE;
443662306a36Sopenharmony_ci		else
443762306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_CRT2_DPMS_STATE;
443862306a36Sopenharmony_ci	}
443962306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
444062306a36Sopenharmony_ci		if (on)
444162306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_LCD1_DPMS_STATE;
444262306a36Sopenharmony_ci		else
444362306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_LCD1_DPMS_STATE;
444462306a36Sopenharmony_ci	}
444562306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
444662306a36Sopenharmony_ci		if (on)
444762306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE;
444862306a36Sopenharmony_ci		else
444962306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_DFP1_DPMS_STATE;
445062306a36Sopenharmony_ci	}
445162306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
445262306a36Sopenharmony_ci		if (on)
445362306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE;
445462306a36Sopenharmony_ci		else
445562306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_DFP2_DPMS_STATE;
445662306a36Sopenharmony_ci	}
445762306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
445862306a36Sopenharmony_ci		if (on)
445962306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE;
446062306a36Sopenharmony_ci		else
446162306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_DFP3_DPMS_STATE;
446262306a36Sopenharmony_ci	}
446362306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) {
446462306a36Sopenharmony_ci		if (on)
446562306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_DFP4_DPMS_STATE;
446662306a36Sopenharmony_ci		else
446762306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_DFP4_DPMS_STATE;
446862306a36Sopenharmony_ci	}
446962306a36Sopenharmony_ci	if (radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) {
447062306a36Sopenharmony_ci		if (on)
447162306a36Sopenharmony_ci			bios_2_scratch &= ~ATOM_S2_DFP5_DPMS_STATE;
447262306a36Sopenharmony_ci		else
447362306a36Sopenharmony_ci			bios_2_scratch |= ATOM_S2_DFP5_DPMS_STATE;
447462306a36Sopenharmony_ci	}
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci	if (rdev->family >= CHIP_R600)
447762306a36Sopenharmony_ci		WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
447862306a36Sopenharmony_ci	else
447962306a36Sopenharmony_ci		WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
448062306a36Sopenharmony_ci}
4481