1254885Sdumbbell/*
2254885Sdumbbell * Copyright 2007-8 Advanced Micro Devices, Inc.
3254885Sdumbbell * Copyright 2008 Red Hat Inc.
4254885Sdumbbell *
5254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a
6254885Sdumbbell * copy of this software and associated documentation files (the "Software"),
7254885Sdumbbell * to deal in the Software without restriction, including without limitation
8254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the
10254885Sdumbbell * Software is furnished to do so, subject to the following conditions:
11254885Sdumbbell *
12254885Sdumbbell * The above copyright notice and this permission notice shall be included in
13254885Sdumbbell * all copies or substantial portions of the Software.
14254885Sdumbbell *
15254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE.
22254885Sdumbbell *
23254885Sdumbbell * Authors: Dave Airlie
24254885Sdumbbell *          Alex Deucher
25254885Sdumbbell */
26254885Sdumbbell
27254885Sdumbbell#include <sys/cdefs.h>
28254885Sdumbbell__FBSDID("$FreeBSD$");
29254885Sdumbbell
30254885Sdumbbell#include <dev/drm2/drmP.h>
31254885Sdumbbell#include <dev/drm2/radeon/radeon_drm.h>
32254885Sdumbbell#include "radeon.h"
33254885Sdumbbell#include "radeon_asic.h" /* Declares several prototypes; clang is pleased. */
34254885Sdumbbell
35254885Sdumbbell#include "atom.h"
36254885Sdumbbell#include "atom-bits.h"
37254885Sdumbbell
38282199Sdumbbell#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */
39282199Sdumbbell/* from radeon_encoder.c */
40282199Sdumbbellextern uint32_t
41282199Sdumbbellradeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device,
42282199Sdumbbell			uint8_t dac);
43282199Sdumbbellextern void radeon_link_encoder_connector(struct drm_device *dev);
44282199Sdumbbellextern void
45282199Sdumbbellradeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum,
46282199Sdumbbell			uint32_t supported_device, u16 caps);
47282199Sdumbbell
48282199Sdumbbell/* from radeon_connector.c */
49282199Sdumbbellextern void
50282199Sdumbbellradeon_add_atom_connector(struct drm_device *dev,
51282199Sdumbbell			  uint32_t connector_id,
52282199Sdumbbell			  uint32_t supported_device,
53282199Sdumbbell			  int connector_type,
54282199Sdumbbell			  struct radeon_i2c_bus_rec *i2c_bus,
55282199Sdumbbell			  uint32_t igp_lane_info,
56282199Sdumbbell			  uint16_t connector_object_id,
57282199Sdumbbell			  struct radeon_hpd *hpd,
58282199Sdumbbell			  struct radeon_router *router);
59282199Sdumbbell
60282199Sdumbbell/* from radeon_legacy_encoder.c */
61282199Sdumbbellextern void
62282199Sdumbbellradeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum,
63282199Sdumbbell			  uint32_t supported_device);
64282199Sdumbbell#endif
65282199Sdumbbell
66254885Sdumbbell/* local */
67254885Sdumbbellstatic int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
68254885Sdumbbell				    u16 voltage_id, u16 *voltage);
69254885Sdumbbell
70254885Sdumbbellunion atom_supported_devices {
71254885Sdumbbell	struct _ATOM_SUPPORTED_DEVICES_INFO info;
72254885Sdumbbell	struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
73254885Sdumbbell	struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1;
74254885Sdumbbell};
75254885Sdumbbell
76254885Sdumbbellstatic void radeon_lookup_i2c_gpio_quirks(struct radeon_device *rdev,
77254885Sdumbbell					  ATOM_GPIO_I2C_ASSIGMENT *gpio,
78254885Sdumbbell					  u8 index)
79254885Sdumbbell{
80254885Sdumbbell	/* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */
81254885Sdumbbell	if ((rdev->family == CHIP_R420) ||
82254885Sdumbbell	    (rdev->family == CHIP_R423) ||
83254885Sdumbbell	    (rdev->family == CHIP_RV410)) {
84254885Sdumbbell		if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) ||
85254885Sdumbbell		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) ||
86254885Sdumbbell		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) {
87254885Sdumbbell			gpio->ucClkMaskShift = 0x19;
88254885Sdumbbell			gpio->ucDataMaskShift = 0x18;
89254885Sdumbbell		}
90254885Sdumbbell	}
91254885Sdumbbell
92254885Sdumbbell	/* some evergreen boards have bad data for this entry */
93254885Sdumbbell	if (ASIC_IS_DCE4(rdev)) {
94254885Sdumbbell		if ((index == 7) &&
95254885Sdumbbell		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) &&
96254885Sdumbbell		    (gpio->sucI2cId.ucAccess == 0)) {
97254885Sdumbbell			gpio->sucI2cId.ucAccess = 0x97;
98254885Sdumbbell			gpio->ucDataMaskShift = 8;
99254885Sdumbbell			gpio->ucDataEnShift = 8;
100254885Sdumbbell			gpio->ucDataY_Shift = 8;
101254885Sdumbbell			gpio->ucDataA_Shift = 8;
102254885Sdumbbell		}
103254885Sdumbbell	}
104254885Sdumbbell
105254885Sdumbbell	/* some DCE3 boards have bad data for this entry */
106254885Sdumbbell	if (ASIC_IS_DCE3(rdev)) {
107254885Sdumbbell		if ((index == 4) &&
108254885Sdumbbell		    (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) &&
109254885Sdumbbell		    (gpio->sucI2cId.ucAccess == 0x94))
110254885Sdumbbell			gpio->sucI2cId.ucAccess = 0x14;
111254885Sdumbbell	}
112254885Sdumbbell}
113254885Sdumbbell
114254885Sdumbbellstatic struct radeon_i2c_bus_rec radeon_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio)
115254885Sdumbbell{
116254885Sdumbbell	struct radeon_i2c_bus_rec i2c;
117254885Sdumbbell
118254885Sdumbbell	memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
119254885Sdumbbell
120254885Sdumbbell	i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
121254885Sdumbbell	i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
122254885Sdumbbell	i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
123254885Sdumbbell	i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
124254885Sdumbbell	i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
125254885Sdumbbell	i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
126254885Sdumbbell	i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
127254885Sdumbbell	i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
128254885Sdumbbell	i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
129254885Sdumbbell	i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
130254885Sdumbbell	i2c.en_clk_mask = (1 << gpio->ucClkEnShift);
131254885Sdumbbell	i2c.en_data_mask = (1 << gpio->ucDataEnShift);
132254885Sdumbbell	i2c.y_clk_mask = (1 << gpio->ucClkY_Shift);
133254885Sdumbbell	i2c.y_data_mask = (1 << gpio->ucDataY_Shift);
134254885Sdumbbell	i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
135254885Sdumbbell	i2c.a_data_mask = (1 << gpio->ucDataA_Shift);
136254885Sdumbbell
137254885Sdumbbell	if (gpio->sucI2cId.sbfAccess.bfHW_Capable)
138254885Sdumbbell		i2c.hw_capable = true;
139254885Sdumbbell	else
140254885Sdumbbell		i2c.hw_capable = false;
141254885Sdumbbell
142254885Sdumbbell	if (gpio->sucI2cId.ucAccess == 0xa0)
143254885Sdumbbell		i2c.mm_i2c = true;
144254885Sdumbbell	else
145254885Sdumbbell		i2c.mm_i2c = false;
146254885Sdumbbell
147254885Sdumbbell	i2c.i2c_id = gpio->sucI2cId.ucAccess;
148254885Sdumbbell
149254885Sdumbbell	if (i2c.mask_clk_reg)
150254885Sdumbbell		i2c.valid = true;
151254885Sdumbbell	else
152254885Sdumbbell		i2c.valid = false;
153254885Sdumbbell
154254885Sdumbbell	return i2c;
155254885Sdumbbell}
156254885Sdumbbell
157254885Sdumbbellstatic struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rdev,
158254885Sdumbbell							       uint8_t id)
159254885Sdumbbell{
160254885Sdumbbell	struct atom_context *ctx = rdev->mode_info.atom_context;
161254885Sdumbbell	ATOM_GPIO_I2C_ASSIGMENT *gpio;
162254885Sdumbbell	struct radeon_i2c_bus_rec i2c;
163254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
164254885Sdumbbell	struct _ATOM_GPIO_I2C_INFO *i2c_info;
165254885Sdumbbell	uint16_t data_offset, size;
166254885Sdumbbell	int i, num_indices;
167254885Sdumbbell
168254885Sdumbbell	memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
169254885Sdumbbell	i2c.valid = false;
170254885Sdumbbell
171254885Sdumbbell	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
172254885Sdumbbell		i2c_info = (struct _ATOM_GPIO_I2C_INFO *)((char *)ctx->bios + data_offset);
173254885Sdumbbell
174254885Sdumbbell		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
175254885Sdumbbell			sizeof(ATOM_GPIO_I2C_ASSIGMENT);
176254885Sdumbbell
177254885Sdumbbell		for (i = 0; i < num_indices; i++) {
178254885Sdumbbell			gpio = &i2c_info->asGPIO_Info[i];
179254885Sdumbbell
180254885Sdumbbell			radeon_lookup_i2c_gpio_quirks(rdev, gpio, i);
181254885Sdumbbell
182254885Sdumbbell			if (gpio->sucI2cId.ucAccess == id) {
183254885Sdumbbell				i2c = radeon_get_bus_rec_for_i2c_gpio(gpio);
184254885Sdumbbell				break;
185254885Sdumbbell			}
186254885Sdumbbell		}
187254885Sdumbbell	}
188254885Sdumbbell
189254885Sdumbbell	return i2c;
190254885Sdumbbell}
191254885Sdumbbell
192254885Sdumbbellvoid radeon_atombios_i2c_init(struct radeon_device *rdev)
193254885Sdumbbell{
194254885Sdumbbell	struct atom_context *ctx = rdev->mode_info.atom_context;
195254885Sdumbbell	ATOM_GPIO_I2C_ASSIGMENT *gpio;
196254885Sdumbbell	struct radeon_i2c_bus_rec i2c;
197254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
198254885Sdumbbell	struct _ATOM_GPIO_I2C_INFO *i2c_info;
199254885Sdumbbell	uint16_t data_offset, size;
200254885Sdumbbell	int i, num_indices;
201254885Sdumbbell	char stmp[32];
202254885Sdumbbell
203254885Sdumbbell	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
204254885Sdumbbell		i2c_info = (struct _ATOM_GPIO_I2C_INFO *)((char *)ctx->bios + data_offset);
205254885Sdumbbell
206254885Sdumbbell		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
207254885Sdumbbell			sizeof(ATOM_GPIO_I2C_ASSIGMENT);
208254885Sdumbbell
209254885Sdumbbell		for (i = 0; i < num_indices; i++) {
210254885Sdumbbell			gpio = &i2c_info->asGPIO_Info[i];
211254885Sdumbbell
212254885Sdumbbell			radeon_lookup_i2c_gpio_quirks(rdev, gpio, i);
213254885Sdumbbell
214254885Sdumbbell			i2c = radeon_get_bus_rec_for_i2c_gpio(gpio);
215254885Sdumbbell
216254885Sdumbbell			if (i2c.valid) {
217254885Sdumbbell				sprintf(stmp, "0x%x", i2c.i2c_id);
218254885Sdumbbell				rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp);
219254885Sdumbbell			}
220254885Sdumbbell		}
221254885Sdumbbell	}
222254885Sdumbbell}
223254885Sdumbbell
224254885Sdumbbellstatic struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
225254885Sdumbbell							u8 id)
226254885Sdumbbell{
227254885Sdumbbell	struct atom_context *ctx = rdev->mode_info.atom_context;
228254885Sdumbbell	struct radeon_gpio_rec gpio;
229254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT);
230254885Sdumbbell	struct _ATOM_GPIO_PIN_LUT *gpio_info;
231254885Sdumbbell	ATOM_GPIO_PIN_ASSIGNMENT *pin;
232254885Sdumbbell	u16 data_offset, size;
233254885Sdumbbell	int i, num_indices;
234254885Sdumbbell
235254885Sdumbbell	memset(&gpio, 0, sizeof(struct radeon_gpio_rec));
236254885Sdumbbell	gpio.valid = false;
237254885Sdumbbell
238254885Sdumbbell	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
239254885Sdumbbell		gpio_info = (struct _ATOM_GPIO_PIN_LUT *)((char *)ctx->bios + data_offset);
240254885Sdumbbell
241254885Sdumbbell		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
242254885Sdumbbell			sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
243254885Sdumbbell
244254885Sdumbbell		for (i = 0; i < num_indices; i++) {
245254885Sdumbbell			pin = &gpio_info->asGPIO_Pin[i];
246254885Sdumbbell			if (id == pin->ucGPIO_ID) {
247254885Sdumbbell				gpio.id = pin->ucGPIO_ID;
248254885Sdumbbell				gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4;
249254885Sdumbbell				gpio.mask = (1 << pin->ucGpioPinBitShift);
250254885Sdumbbell				gpio.valid = true;
251254885Sdumbbell				break;
252254885Sdumbbell			}
253254885Sdumbbell		}
254254885Sdumbbell	}
255254885Sdumbbell
256254885Sdumbbell	return gpio;
257254885Sdumbbell}
258254885Sdumbbell
259254885Sdumbbellstatic struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device *rdev,
260254885Sdumbbell							    struct radeon_gpio_rec *gpio)
261254885Sdumbbell{
262254885Sdumbbell	struct radeon_hpd hpd;
263254885Sdumbbell	u32 reg;
264254885Sdumbbell
265254885Sdumbbell	memset(&hpd, 0, sizeof(struct radeon_hpd));
266254885Sdumbbell
267254885Sdumbbell	if (ASIC_IS_DCE6(rdev))
268254885Sdumbbell		reg = SI_DC_GPIO_HPD_A;
269254885Sdumbbell	else if (ASIC_IS_DCE4(rdev))
270254885Sdumbbell		reg = EVERGREEN_DC_GPIO_HPD_A;
271254885Sdumbbell	else
272254885Sdumbbell		reg = AVIVO_DC_GPIO_HPD_A;
273254885Sdumbbell
274254885Sdumbbell	hpd.gpio = *gpio;
275254885Sdumbbell	if (gpio->reg == reg) {
276254885Sdumbbell		switch(gpio->mask) {
277254885Sdumbbell		case (1 << 0):
278254885Sdumbbell			hpd.hpd = RADEON_HPD_1;
279254885Sdumbbell			break;
280254885Sdumbbell		case (1 << 8):
281254885Sdumbbell			hpd.hpd = RADEON_HPD_2;
282254885Sdumbbell			break;
283254885Sdumbbell		case (1 << 16):
284254885Sdumbbell			hpd.hpd = RADEON_HPD_3;
285254885Sdumbbell			break;
286254885Sdumbbell		case (1 << 24):
287254885Sdumbbell			hpd.hpd = RADEON_HPD_4;
288254885Sdumbbell			break;
289254885Sdumbbell		case (1 << 26):
290254885Sdumbbell			hpd.hpd = RADEON_HPD_5;
291254885Sdumbbell			break;
292254885Sdumbbell		case (1 << 28):
293254885Sdumbbell			hpd.hpd = RADEON_HPD_6;
294254885Sdumbbell			break;
295254885Sdumbbell		default:
296254885Sdumbbell			hpd.hpd = RADEON_HPD_NONE;
297254885Sdumbbell			break;
298254885Sdumbbell		}
299254885Sdumbbell	} else
300254885Sdumbbell		hpd.hpd = RADEON_HPD_NONE;
301254885Sdumbbell	return hpd;
302254885Sdumbbell}
303254885Sdumbbell
304254885Sdumbbellstatic bool radeon_atom_apply_quirks(struct drm_device *dev,
305254885Sdumbbell				     uint32_t supported_device,
306254885Sdumbbell				     int *connector_type,
307254885Sdumbbell				     struct radeon_i2c_bus_rec *i2c_bus,
308254885Sdumbbell				     uint16_t *line_mux,
309254885Sdumbbell				     struct radeon_hpd *hpd)
310254885Sdumbbell{
311254885Sdumbbell
312254885Sdumbbell	/* Asus M2A-VM HDMI board lists the DVI port as HDMI */
313254885Sdumbbell	if ((dev->pci_device == 0x791e) &&
314254885Sdumbbell	    (dev->pci_subvendor == 0x1043) &&
315254885Sdumbbell	    (dev->pci_subdevice == 0x826d)) {
316254885Sdumbbell		if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
317254885Sdumbbell		    (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
318254885Sdumbbell			*connector_type = DRM_MODE_CONNECTOR_DVID;
319254885Sdumbbell	}
320254885Sdumbbell
321254885Sdumbbell	/* Asrock RS600 board lists the DVI port as HDMI */
322254885Sdumbbell	if ((dev->pci_device == 0x7941) &&
323254885Sdumbbell	    (dev->pci_subvendor == 0x1849) &&
324254885Sdumbbell	    (dev->pci_subdevice == 0x7941)) {
325254885Sdumbbell		if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
326254885Sdumbbell		    (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
327254885Sdumbbell			*connector_type = DRM_MODE_CONNECTOR_DVID;
328254885Sdumbbell	}
329254885Sdumbbell
330254885Sdumbbell	/* MSI K9A2GM V2/V3 board has no HDMI or DVI */
331254885Sdumbbell	if ((dev->pci_device == 0x796e) &&
332254885Sdumbbell	    (dev->pci_subvendor == 0x1462) &&
333254885Sdumbbell	    (dev->pci_subdevice == 0x7302)) {
334254885Sdumbbell		if ((supported_device == ATOM_DEVICE_DFP2_SUPPORT) ||
335254885Sdumbbell		    (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
336254885Sdumbbell			return false;
337254885Sdumbbell	}
338254885Sdumbbell
339254885Sdumbbell	/* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
340254885Sdumbbell	if ((dev->pci_device == 0x7941) &&
341254885Sdumbbell	    (dev->pci_subvendor == 0x147b) &&
342254885Sdumbbell	    (dev->pci_subdevice == 0x2412)) {
343254885Sdumbbell		if (*connector_type == DRM_MODE_CONNECTOR_DVII)
344254885Sdumbbell			return false;
345254885Sdumbbell	}
346254885Sdumbbell
347254885Sdumbbell	/* Falcon NW laptop lists vga ddc line for LVDS */
348254885Sdumbbell	if ((dev->pci_device == 0x5653) &&
349254885Sdumbbell	    (dev->pci_subvendor == 0x1462) &&
350254885Sdumbbell	    (dev->pci_subdevice == 0x0291)) {
351254885Sdumbbell		if (*connector_type == DRM_MODE_CONNECTOR_LVDS) {
352254885Sdumbbell			i2c_bus->valid = false;
353254885Sdumbbell			*line_mux = 53;
354254885Sdumbbell		}
355254885Sdumbbell	}
356254885Sdumbbell
357254885Sdumbbell	/* HIS X1300 is DVI+VGA, not DVI+DVI */
358254885Sdumbbell	if ((dev->pci_device == 0x7146) &&
359254885Sdumbbell	    (dev->pci_subvendor == 0x17af) &&
360254885Sdumbbell	    (dev->pci_subdevice == 0x2058)) {
361254885Sdumbbell		if (supported_device == ATOM_DEVICE_DFP1_SUPPORT)
362254885Sdumbbell			return false;
363254885Sdumbbell	}
364254885Sdumbbell
365254885Sdumbbell	/* Gigabyte X1300 is DVI+VGA, not DVI+DVI */
366254885Sdumbbell	if ((dev->pci_device == 0x7142) &&
367254885Sdumbbell	    (dev->pci_subvendor == 0x1458) &&
368254885Sdumbbell	    (dev->pci_subdevice == 0x2134)) {
369254885Sdumbbell		if (supported_device == ATOM_DEVICE_DFP1_SUPPORT)
370254885Sdumbbell			return false;
371254885Sdumbbell	}
372254885Sdumbbell
373254885Sdumbbell
374254885Sdumbbell	/* Funky macbooks */
375254885Sdumbbell	if ((dev->pci_device == 0x71C5) &&
376254885Sdumbbell	    (dev->pci_subvendor == 0x106b) &&
377254885Sdumbbell	    (dev->pci_subdevice == 0x0080)) {
378254885Sdumbbell		if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) ||
379254885Sdumbbell		    (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
380254885Sdumbbell			return false;
381254885Sdumbbell		if (supported_device == ATOM_DEVICE_CRT2_SUPPORT)
382254885Sdumbbell			*line_mux = 0x90;
383254885Sdumbbell	}
384254885Sdumbbell
385254885Sdumbbell	/* mac rv630, rv730, others */
386254885Sdumbbell	if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) &&
387254885Sdumbbell	    (*connector_type == DRM_MODE_CONNECTOR_DVII)) {
388254885Sdumbbell		*connector_type = DRM_MODE_CONNECTOR_9PinDIN;
389254885Sdumbbell		*line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1;
390254885Sdumbbell	}
391254885Sdumbbell
392254885Sdumbbell	/* ASUS HD 3600 XT board lists the DVI port as HDMI */
393254885Sdumbbell	if ((dev->pci_device == 0x9598) &&
394254885Sdumbbell	    (dev->pci_subvendor == 0x1043) &&
395254885Sdumbbell	    (dev->pci_subdevice == 0x01da)) {
396254885Sdumbbell		if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
397254885Sdumbbell			*connector_type = DRM_MODE_CONNECTOR_DVII;
398254885Sdumbbell		}
399254885Sdumbbell	}
400254885Sdumbbell
401254885Sdumbbell	/* ASUS HD 3600 board lists the DVI port as HDMI */
402254885Sdumbbell	if ((dev->pci_device == 0x9598) &&
403254885Sdumbbell	    (dev->pci_subvendor == 0x1043) &&
404254885Sdumbbell	    (dev->pci_subdevice == 0x01e4)) {
405254885Sdumbbell		if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
406254885Sdumbbell			*connector_type = DRM_MODE_CONNECTOR_DVII;
407254885Sdumbbell		}
408254885Sdumbbell	}
409254885Sdumbbell
410254885Sdumbbell	/* ASUS HD 3450 board lists the DVI port as HDMI */
411254885Sdumbbell	if ((dev->pci_device == 0x95C5) &&
412254885Sdumbbell	    (dev->pci_subvendor == 0x1043) &&
413254885Sdumbbell	    (dev->pci_subdevice == 0x01e2)) {
414254885Sdumbbell		if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
415254885Sdumbbell			*connector_type = DRM_MODE_CONNECTOR_DVII;
416254885Sdumbbell		}
417254885Sdumbbell	}
418254885Sdumbbell
419254885Sdumbbell	/* some BIOSes seem to report DAC on HDMI - usually this is a board with
420254885Sdumbbell	 * HDMI + VGA reporting as HDMI
421254885Sdumbbell	 */
422254885Sdumbbell	if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
423254885Sdumbbell		if (supported_device & (ATOM_DEVICE_CRT_SUPPORT)) {
424254885Sdumbbell			*connector_type = DRM_MODE_CONNECTOR_VGA;
425254885Sdumbbell			*line_mux = 0;
426254885Sdumbbell		}
427254885Sdumbbell	}
428254885Sdumbbell
429254885Sdumbbell	/* Acer laptop (Acer TravelMate 5730/5730G) has an HDMI port
430254885Sdumbbell	 * on the laptop and a DVI port on the docking station and
431254885Sdumbbell	 * both share the same encoder, hpd pin, and ddc line.
432254885Sdumbbell	 * So while the bios table is technically correct,
433254885Sdumbbell	 * we drop the DVI port here since xrandr has no concept of
434254885Sdumbbell	 * encoders and will try and drive both connectors
435254885Sdumbbell	 * with different crtcs which isn't possible on the hardware
436254885Sdumbbell	 * side and leaves no crtcs for LVDS or VGA.
437254885Sdumbbell	 */
438254885Sdumbbell	if (((dev->pci_device == 0x95c4) || (dev->pci_device == 0x9591)) &&
439254885Sdumbbell	    (dev->pci_subvendor == 0x1025) &&
440254885Sdumbbell	    (dev->pci_subdevice == 0x013c)) {
441254885Sdumbbell		if ((*connector_type == DRM_MODE_CONNECTOR_DVII) &&
442254885Sdumbbell		    (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) {
443254885Sdumbbell			/* actually it's a DVI-D port not DVI-I */
444254885Sdumbbell			*connector_type = DRM_MODE_CONNECTOR_DVID;
445254885Sdumbbell			return false;
446254885Sdumbbell		}
447254885Sdumbbell	}
448254885Sdumbbell
449254885Sdumbbell	/* XFX Pine Group device rv730 reports no VGA DDC lines
450254885Sdumbbell	 * even though they are wired up to record 0x93
451254885Sdumbbell	 */
452254885Sdumbbell	if ((dev->pci_device == 0x9498) &&
453254885Sdumbbell	    (dev->pci_subvendor == 0x1682) &&
454254885Sdumbbell	    (dev->pci_subdevice == 0x2452) &&
455254885Sdumbbell	    (i2c_bus->valid == false) &&
456254885Sdumbbell	    !(supported_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))) {
457254885Sdumbbell		struct radeon_device *rdev = dev->dev_private;
458254885Sdumbbell		*i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93);
459254885Sdumbbell	}
460254885Sdumbbell
461254885Sdumbbell	/* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */
462254885Sdumbbell	if (((dev->pci_device == 0x9802) || (dev->pci_device == 0x9806)) &&
463254885Sdumbbell	    (dev->pci_subvendor == 0x1734) &&
464254885Sdumbbell	    (dev->pci_subdevice == 0x11bd)) {
465254885Sdumbbell		if (*connector_type == DRM_MODE_CONNECTOR_VGA) {
466254885Sdumbbell			*connector_type = DRM_MODE_CONNECTOR_DVII;
467254885Sdumbbell			*line_mux = 0x3103;
468254885Sdumbbell		} else if (*connector_type == DRM_MODE_CONNECTOR_DVID) {
469254885Sdumbbell			*connector_type = DRM_MODE_CONNECTOR_DVII;
470254885Sdumbbell		}
471254885Sdumbbell	}
472254885Sdumbbell
473254885Sdumbbell
474254885Sdumbbell	return true;
475254885Sdumbbell}
476254885Sdumbbell
477254885Sdumbbellconst int supported_devices_connector_convert[] = {
478254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
479254885Sdumbbell	DRM_MODE_CONNECTOR_VGA,
480254885Sdumbbell	DRM_MODE_CONNECTOR_DVII,
481254885Sdumbbell	DRM_MODE_CONNECTOR_DVID,
482254885Sdumbbell	DRM_MODE_CONNECTOR_DVIA,
483254885Sdumbbell	DRM_MODE_CONNECTOR_SVIDEO,
484254885Sdumbbell	DRM_MODE_CONNECTOR_Composite,
485254885Sdumbbell	DRM_MODE_CONNECTOR_LVDS,
486254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
487254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
488254885Sdumbbell	DRM_MODE_CONNECTOR_HDMIA,
489254885Sdumbbell	DRM_MODE_CONNECTOR_HDMIB,
490254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
491254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
492254885Sdumbbell	DRM_MODE_CONNECTOR_9PinDIN,
493254885Sdumbbell	DRM_MODE_CONNECTOR_DisplayPort
494254885Sdumbbell};
495254885Sdumbbell
496254885Sdumbbellconst uint16_t supported_devices_connector_object_id_convert[] = {
497254885Sdumbbell	CONNECTOR_OBJECT_ID_NONE,
498254885Sdumbbell	CONNECTOR_OBJECT_ID_VGA,
499254885Sdumbbell	CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, /* not all boards support DL */
500254885Sdumbbell	CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D, /* not all boards support DL */
501254885Sdumbbell	CONNECTOR_OBJECT_ID_VGA, /* technically DVI-A */
502254885Sdumbbell	CONNECTOR_OBJECT_ID_COMPOSITE,
503254885Sdumbbell	CONNECTOR_OBJECT_ID_SVIDEO,
504254885Sdumbbell	CONNECTOR_OBJECT_ID_LVDS,
505254885Sdumbbell	CONNECTOR_OBJECT_ID_9PIN_DIN,
506254885Sdumbbell	CONNECTOR_OBJECT_ID_9PIN_DIN,
507254885Sdumbbell	CONNECTOR_OBJECT_ID_DISPLAYPORT,
508254885Sdumbbell	CONNECTOR_OBJECT_ID_HDMI_TYPE_A,
509254885Sdumbbell	CONNECTOR_OBJECT_ID_HDMI_TYPE_B,
510254885Sdumbbell	CONNECTOR_OBJECT_ID_SVIDEO
511254885Sdumbbell};
512254885Sdumbbell
513254885Sdumbbellconst int object_connector_convert[] = {
514254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
515254885Sdumbbell	DRM_MODE_CONNECTOR_DVII,
516254885Sdumbbell	DRM_MODE_CONNECTOR_DVII,
517254885Sdumbbell	DRM_MODE_CONNECTOR_DVID,
518254885Sdumbbell	DRM_MODE_CONNECTOR_DVID,
519254885Sdumbbell	DRM_MODE_CONNECTOR_VGA,
520254885Sdumbbell	DRM_MODE_CONNECTOR_Composite,
521254885Sdumbbell	DRM_MODE_CONNECTOR_SVIDEO,
522254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
523254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
524254885Sdumbbell	DRM_MODE_CONNECTOR_9PinDIN,
525254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
526254885Sdumbbell	DRM_MODE_CONNECTOR_HDMIA,
527254885Sdumbbell	DRM_MODE_CONNECTOR_HDMIB,
528254885Sdumbbell	DRM_MODE_CONNECTOR_LVDS,
529254885Sdumbbell	DRM_MODE_CONNECTOR_9PinDIN,
530254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
531254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
532254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown,
533254885Sdumbbell	DRM_MODE_CONNECTOR_DisplayPort,
534254885Sdumbbell	DRM_MODE_CONNECTOR_eDP,
535254885Sdumbbell	DRM_MODE_CONNECTOR_Unknown
536254885Sdumbbell};
537254885Sdumbbell
538254885Sdumbbellbool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
539254885Sdumbbell{
540254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
541254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
542254885Sdumbbell	struct atom_context *ctx = mode_info->atom_context;
543254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, Object_Header);
544254885Sdumbbell	u16 size, data_offset;
545254885Sdumbbell	u8 frev, crev;
546254885Sdumbbell	ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
547254885Sdumbbell	ATOM_ENCODER_OBJECT_TABLE *enc_obj;
548254885Sdumbbell	ATOM_OBJECT_TABLE *router_obj;
549254885Sdumbbell	ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
550254885Sdumbbell	ATOM_OBJECT_HEADER *obj_header;
551254885Sdumbbell	int i, j, k, path_size, device_support;
552254885Sdumbbell	int connector_type;
553254885Sdumbbell	u16 igp_lane_info, conn_id, connector_object_id;
554254885Sdumbbell	struct radeon_i2c_bus_rec ddc_bus;
555254885Sdumbbell	struct radeon_router router;
556254885Sdumbbell	struct radeon_gpio_rec gpio;
557254885Sdumbbell	struct radeon_hpd hpd;
558254885Sdumbbell
559254885Sdumbbell	if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))
560254885Sdumbbell		return false;
561254885Sdumbbell
562254885Sdumbbell	if (crev < 2)
563254885Sdumbbell		return false;
564254885Sdumbbell
565254885Sdumbbell	obj_header = (ATOM_OBJECT_HEADER *) ((char *)ctx->bios + data_offset);
566254885Sdumbbell	path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
567254885Sdumbbell	    ((char *)ctx->bios + data_offset +
568254885Sdumbbell	     le16_to_cpu(obj_header->usDisplayPathTableOffset));
569254885Sdumbbell	con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
570254885Sdumbbell	    ((char *)ctx->bios + data_offset +
571254885Sdumbbell	     le16_to_cpu(obj_header->usConnectorObjectTableOffset));
572254885Sdumbbell	enc_obj = (ATOM_ENCODER_OBJECT_TABLE *)
573254885Sdumbbell	    ((char *)ctx->bios + data_offset +
574254885Sdumbbell	     le16_to_cpu(obj_header->usEncoderObjectTableOffset));
575254885Sdumbbell	router_obj = (ATOM_OBJECT_TABLE *)
576254885Sdumbbell		((char *)ctx->bios + data_offset +
577254885Sdumbbell		 le16_to_cpu(obj_header->usRouterObjectTableOffset));
578254885Sdumbbell	device_support = le16_to_cpu(obj_header->usDeviceSupport);
579254885Sdumbbell
580254885Sdumbbell	path_size = 0;
581254885Sdumbbell	for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
582254885Sdumbbell		uint8_t *addr = (uint8_t *) path_obj->asDispPath;
583254885Sdumbbell		ATOM_DISPLAY_OBJECT_PATH *path;
584254885Sdumbbell		addr += path_size;
585254885Sdumbbell		path = (ATOM_DISPLAY_OBJECT_PATH *) addr;
586254885Sdumbbell		path_size += le16_to_cpu(path->usSize);
587254885Sdumbbell
588254885Sdumbbell		if (device_support & le16_to_cpu(path->usDeviceTag)) {
589254885Sdumbbell			uint8_t con_obj_id, con_obj_num, con_obj_type;
590254885Sdumbbell
591254885Sdumbbell			con_obj_id =
592254885Sdumbbell			    (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK)
593254885Sdumbbell			    >> OBJECT_ID_SHIFT;
594254885Sdumbbell			con_obj_num =
595254885Sdumbbell			    (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK)
596254885Sdumbbell			    >> ENUM_ID_SHIFT;
597254885Sdumbbell			con_obj_type =
598254885Sdumbbell			    (le16_to_cpu(path->usConnObjectId) &
599254885Sdumbbell			     OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
600254885Sdumbbell
601254885Sdumbbell			/* TODO CV support */
602254885Sdumbbell			if (le16_to_cpu(path->usDeviceTag) ==
603254885Sdumbbell				ATOM_DEVICE_CV_SUPPORT)
604254885Sdumbbell				continue;
605254885Sdumbbell
606254885Sdumbbell			/* IGP chips */
607254885Sdumbbell			if ((rdev->flags & RADEON_IS_IGP) &&
608254885Sdumbbell			    (con_obj_id ==
609254885Sdumbbell			     CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
610254885Sdumbbell				uint16_t igp_offset = 0;
611254885Sdumbbell				ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj;
612254885Sdumbbell
613254885Sdumbbell				index =
614254885Sdumbbell				    GetIndexIntoMasterTable(DATA,
615254885Sdumbbell							    IntegratedSystemInfo);
616254885Sdumbbell
617254885Sdumbbell				if (atom_parse_data_header(ctx, index, &size, &frev,
618254885Sdumbbell							   &crev, &igp_offset)) {
619254885Sdumbbell
620254885Sdumbbell					if (crev >= 2) {
621254885Sdumbbell						igp_obj =
622254885Sdumbbell							(ATOM_INTEGRATED_SYSTEM_INFO_V2
623254885Sdumbbell							 *) ((char *)ctx->bios + igp_offset);
624254885Sdumbbell
625254885Sdumbbell						if (igp_obj) {
626254885Sdumbbell							uint32_t slot_config, ct;
627254885Sdumbbell
628254885Sdumbbell							if (con_obj_num == 1)
629254885Sdumbbell								slot_config =
630254885Sdumbbell									igp_obj->
631254885Sdumbbell									ulDDISlot1Config;
632254885Sdumbbell							else
633254885Sdumbbell								slot_config =
634254885Sdumbbell									igp_obj->
635254885Sdumbbell									ulDDISlot2Config;
636254885Sdumbbell
637254885Sdumbbell							ct = (slot_config >> 16) & 0xff;
638254885Sdumbbell							connector_type =
639254885Sdumbbell								object_connector_convert
640254885Sdumbbell								[ct];
641254885Sdumbbell							connector_object_id = ct;
642254885Sdumbbell							igp_lane_info =
643254885Sdumbbell								slot_config & 0xffff;
644254885Sdumbbell						} else
645254885Sdumbbell							continue;
646254885Sdumbbell					} else
647254885Sdumbbell						continue;
648254885Sdumbbell				} else {
649254885Sdumbbell					igp_lane_info = 0;
650254885Sdumbbell					connector_type =
651254885Sdumbbell						object_connector_convert[con_obj_id];
652254885Sdumbbell					connector_object_id = con_obj_id;
653254885Sdumbbell				}
654254885Sdumbbell			} else {
655254885Sdumbbell				igp_lane_info = 0;
656254885Sdumbbell				connector_type =
657254885Sdumbbell				    object_connector_convert[con_obj_id];
658254885Sdumbbell				connector_object_id = con_obj_id;
659254885Sdumbbell			}
660254885Sdumbbell
661254885Sdumbbell			if (connector_type == DRM_MODE_CONNECTOR_Unknown)
662254885Sdumbbell				continue;
663254885Sdumbbell
664254885Sdumbbell			router.ddc_valid = false;
665254885Sdumbbell			router.cd_valid = false;
666254885Sdumbbell			for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
667254885Sdumbbell				uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
668254885Sdumbbell
669254885Sdumbbell				grph_obj_id =
670254885Sdumbbell				    (le16_to_cpu(path->usGraphicObjIds[j]) &
671254885Sdumbbell				     OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
672254885Sdumbbell				grph_obj_num =
673254885Sdumbbell				    (le16_to_cpu(path->usGraphicObjIds[j]) &
674254885Sdumbbell				     ENUM_ID_MASK) >> ENUM_ID_SHIFT;
675254885Sdumbbell				grph_obj_type =
676254885Sdumbbell				    (le16_to_cpu(path->usGraphicObjIds[j]) &
677254885Sdumbbell				     OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
678254885Sdumbbell
679254885Sdumbbell				if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
680254885Sdumbbell					for (k = 0; k < enc_obj->ucNumberOfObjects; k++) {
681254885Sdumbbell						u16 encoder_obj = le16_to_cpu(enc_obj->asObjects[k].usObjectID);
682254885Sdumbbell						if (le16_to_cpu(path->usGraphicObjIds[j]) == encoder_obj) {
683254885Sdumbbell							ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
684254885Sdumbbell								((char *)ctx->bios + data_offset +
685254885Sdumbbell								 le16_to_cpu(enc_obj->asObjects[k].usRecordOffset));
686254885Sdumbbell							ATOM_ENCODER_CAP_RECORD *cap_record;
687254885Sdumbbell							u16 caps = 0;
688254885Sdumbbell
689254885Sdumbbell							while (record->ucRecordSize > 0 &&
690254885Sdumbbell							       record->ucRecordType > 0 &&
691254885Sdumbbell							       record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
692254885Sdumbbell								switch (record->ucRecordType) {
693254885Sdumbbell								case ATOM_ENCODER_CAP_RECORD_TYPE:
694254885Sdumbbell									cap_record =(ATOM_ENCODER_CAP_RECORD *)
695254885Sdumbbell										record;
696254885Sdumbbell									caps = le16_to_cpu(cap_record->usEncoderCap);
697254885Sdumbbell									break;
698254885Sdumbbell								}
699254885Sdumbbell								record = (ATOM_COMMON_RECORD_HEADER *)
700254885Sdumbbell									((char *)record + record->ucRecordSize);
701254885Sdumbbell							}
702254885Sdumbbell							radeon_add_atom_encoder(dev,
703254885Sdumbbell										encoder_obj,
704254885Sdumbbell										le16_to_cpu
705254885Sdumbbell										(path->
706254885Sdumbbell										 usDeviceTag),
707254885Sdumbbell										caps);
708254885Sdumbbell						}
709254885Sdumbbell					}
710254885Sdumbbell				} else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
711254885Sdumbbell					for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
712254885Sdumbbell						u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID);
713254885Sdumbbell						if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
714254885Sdumbbell							ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
715254885Sdumbbell								((char *)ctx->bios + data_offset +
716254885Sdumbbell								 le16_to_cpu(router_obj->asObjects[k].usRecordOffset));
717254885Sdumbbell							ATOM_I2C_RECORD *i2c_record;
718254885Sdumbbell							ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
719254885Sdumbbell							ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
720254885Sdumbbell							ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path;
721254885Sdumbbell							ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
722254885Sdumbbell								(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
723254885Sdumbbell								((char *)ctx->bios + data_offset +
724254885Sdumbbell								 le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset));
725254885Sdumbbell							int enum_id;
726254885Sdumbbell
727254885Sdumbbell							router.router_id = router_obj_id;
728254885Sdumbbell							for (enum_id = 0; enum_id < router_src_dst_table->ucNumberOfDst;
729254885Sdumbbell							     enum_id++) {
730254885Sdumbbell								if (le16_to_cpu(path->usConnObjectId) ==
731254885Sdumbbell								    le16_to_cpu(router_src_dst_table->usDstObjectID[enum_id]))
732254885Sdumbbell									break;
733254885Sdumbbell							}
734254885Sdumbbell
735254885Sdumbbell							while (record->ucRecordSize > 0 &&
736254885Sdumbbell							       record->ucRecordType > 0 &&
737254885Sdumbbell							       record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
738254885Sdumbbell								switch (record->ucRecordType) {
739254885Sdumbbell								case ATOM_I2C_RECORD_TYPE:
740254885Sdumbbell									i2c_record =
741254885Sdumbbell										(ATOM_I2C_RECORD *)
742254885Sdumbbell										record;
743254885Sdumbbell									i2c_config =
744254885Sdumbbell										(ATOM_I2C_ID_CONFIG_ACCESS *)
745254885Sdumbbell										&i2c_record->sucI2cId;
746254885Sdumbbell									router.i2c_info =
747254885Sdumbbell										radeon_lookup_i2c_gpio(rdev,
748254885Sdumbbell												       i2c_config->
749254885Sdumbbell												       ucAccess);
750254885Sdumbbell									router.i2c_addr = i2c_record->ucI2CAddr >> 1;
751254885Sdumbbell									break;
752254885Sdumbbell								case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
753254885Sdumbbell									ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
754254885Sdumbbell										record;
755254885Sdumbbell									router.ddc_valid = true;
756254885Sdumbbell									router.ddc_mux_type = ddc_path->ucMuxType;
757254885Sdumbbell									router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;
758254885Sdumbbell									router.ddc_mux_state = ddc_path->ucMuxState[enum_id];
759254885Sdumbbell									break;
760254885Sdumbbell								case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
761254885Sdumbbell									cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)
762254885Sdumbbell										record;
763254885Sdumbbell									router.cd_valid = true;
764254885Sdumbbell									router.cd_mux_type = cd_path->ucMuxType;
765254885Sdumbbell									router.cd_mux_control_pin = cd_path->ucMuxControlPin;
766254885Sdumbbell									router.cd_mux_state = cd_path->ucMuxState[enum_id];
767254885Sdumbbell									break;
768254885Sdumbbell								}
769254885Sdumbbell								record = (ATOM_COMMON_RECORD_HEADER *)
770254885Sdumbbell									((char *)record + record->ucRecordSize);
771254885Sdumbbell							}
772254885Sdumbbell						}
773254885Sdumbbell					}
774254885Sdumbbell				}
775254885Sdumbbell			}
776254885Sdumbbell
777254885Sdumbbell			/* look up gpio for ddc, hpd */
778254885Sdumbbell			ddc_bus.valid = false;
779254885Sdumbbell			hpd.hpd = RADEON_HPD_NONE;
780254885Sdumbbell			if ((le16_to_cpu(path->usDeviceTag) &
781254885Sdumbbell			     (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
782254885Sdumbbell				for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
783254885Sdumbbell					if (le16_to_cpu(path->usConnObjectId) ==
784254885Sdumbbell					    le16_to_cpu(con_obj->asObjects[j].
785254885Sdumbbell							usObjectID)) {
786254885Sdumbbell						ATOM_COMMON_RECORD_HEADER
787254885Sdumbbell						    *record =
788254885Sdumbbell						    (ATOM_COMMON_RECORD_HEADER
789254885Sdumbbell						     *)
790254885Sdumbbell						    ((char *)ctx->bios + data_offset +
791254885Sdumbbell						     le16_to_cpu(con_obj->
792254885Sdumbbell								 asObjects[j].
793254885Sdumbbell								 usRecordOffset));
794254885Sdumbbell						ATOM_I2C_RECORD *i2c_record;
795254885Sdumbbell						ATOM_HPD_INT_RECORD *hpd_record;
796254885Sdumbbell						ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
797254885Sdumbbell
798254885Sdumbbell						while (record->ucRecordSize > 0 &&
799254885Sdumbbell						       record->ucRecordType > 0 &&
800254885Sdumbbell						       record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
801254885Sdumbbell							switch (record->ucRecordType) {
802254885Sdumbbell							case ATOM_I2C_RECORD_TYPE:
803254885Sdumbbell								i2c_record =
804254885Sdumbbell								    (ATOM_I2C_RECORD *)
805254885Sdumbbell									record;
806254885Sdumbbell								i2c_config =
807254885Sdumbbell									(ATOM_I2C_ID_CONFIG_ACCESS *)
808254885Sdumbbell									&i2c_record->sucI2cId;
809254885Sdumbbell								ddc_bus = radeon_lookup_i2c_gpio(rdev,
810254885Sdumbbell												 i2c_config->
811254885Sdumbbell												 ucAccess);
812254885Sdumbbell								break;
813254885Sdumbbell							case ATOM_HPD_INT_RECORD_TYPE:
814254885Sdumbbell								hpd_record =
815254885Sdumbbell									(ATOM_HPD_INT_RECORD *)
816254885Sdumbbell									record;
817254885Sdumbbell								gpio = radeon_lookup_gpio(rdev,
818254885Sdumbbell											  hpd_record->ucHPDIntGPIOID);
819254885Sdumbbell								hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
820254885Sdumbbell								hpd.plugged_state = hpd_record->ucPlugged_PinState;
821254885Sdumbbell								break;
822254885Sdumbbell							}
823254885Sdumbbell							record =
824254885Sdumbbell							    (ATOM_COMMON_RECORD_HEADER
825254885Sdumbbell							     *) ((char *)record
826254885Sdumbbell								 +
827254885Sdumbbell								 record->
828254885Sdumbbell								 ucRecordSize);
829254885Sdumbbell						}
830254885Sdumbbell						break;
831254885Sdumbbell					}
832254885Sdumbbell				}
833254885Sdumbbell			}
834254885Sdumbbell
835254885Sdumbbell			/* needed for aux chan transactions */
836254885Sdumbbell			ddc_bus.hpd = hpd.hpd;
837254885Sdumbbell
838254885Sdumbbell			conn_id = le16_to_cpu(path->usConnObjectId);
839254885Sdumbbell
840254885Sdumbbell			if (!radeon_atom_apply_quirks
841254885Sdumbbell			    (dev, le16_to_cpu(path->usDeviceTag), &connector_type,
842254885Sdumbbell			     &ddc_bus, &conn_id, &hpd))
843254885Sdumbbell				continue;
844254885Sdumbbell
845254885Sdumbbell			radeon_add_atom_connector(dev,
846254885Sdumbbell						  conn_id,
847254885Sdumbbell						  le16_to_cpu(path->
848254885Sdumbbell							      usDeviceTag),
849254885Sdumbbell						  connector_type, &ddc_bus,
850254885Sdumbbell						  igp_lane_info,
851254885Sdumbbell						  connector_object_id,
852254885Sdumbbell						  &hpd,
853254885Sdumbbell						  &router);
854254885Sdumbbell
855254885Sdumbbell		}
856254885Sdumbbell	}
857254885Sdumbbell
858254885Sdumbbell	radeon_link_encoder_connector(dev);
859254885Sdumbbell
860254885Sdumbbell	return true;
861254885Sdumbbell}
862254885Sdumbbell
863254885Sdumbbellstatic uint16_t atombios_get_connector_object_id(struct drm_device *dev,
864254885Sdumbbell						 int connector_type,
865254885Sdumbbell						 uint16_t devices)
866254885Sdumbbell{
867254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
868254885Sdumbbell
869254885Sdumbbell	if (rdev->flags & RADEON_IS_IGP) {
870254885Sdumbbell		return supported_devices_connector_object_id_convert
871254885Sdumbbell			[connector_type];
872254885Sdumbbell	} else if (((connector_type == DRM_MODE_CONNECTOR_DVII) ||
873254885Sdumbbell		    (connector_type == DRM_MODE_CONNECTOR_DVID)) &&
874254885Sdumbbell		   (devices & ATOM_DEVICE_DFP2_SUPPORT))  {
875254885Sdumbbell		struct radeon_mode_info *mode_info = &rdev->mode_info;
876254885Sdumbbell		struct atom_context *ctx = mode_info->atom_context;
877254885Sdumbbell		int index = GetIndexIntoMasterTable(DATA, XTMDS_Info);
878254885Sdumbbell		uint16_t size, data_offset;
879254885Sdumbbell		uint8_t frev, crev;
880254885Sdumbbell		ATOM_XTMDS_INFO *xtmds;
881254885Sdumbbell
882254885Sdumbbell		if (atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) {
883254885Sdumbbell			xtmds = (ATOM_XTMDS_INFO *)((char *)ctx->bios + data_offset);
884254885Sdumbbell
885254885Sdumbbell			if (xtmds->ucSupportedLink & ATOM_XTMDS_SUPPORTED_DUALLINK) {
886254885Sdumbbell				if (connector_type == DRM_MODE_CONNECTOR_DVII)
887254885Sdumbbell					return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I;
888254885Sdumbbell				else
889254885Sdumbbell					return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D;
890254885Sdumbbell			} else {
891254885Sdumbbell				if (connector_type == DRM_MODE_CONNECTOR_DVII)
892254885Sdumbbell					return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I;
893254885Sdumbbell				else
894254885Sdumbbell					return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D;
895254885Sdumbbell			}
896254885Sdumbbell		} else
897254885Sdumbbell			return supported_devices_connector_object_id_convert
898254885Sdumbbell				[connector_type];
899254885Sdumbbell	} else {
900254885Sdumbbell		return supported_devices_connector_object_id_convert
901254885Sdumbbell			[connector_type];
902254885Sdumbbell	}
903254885Sdumbbell}
904254885Sdumbbell
905254885Sdumbbellstruct bios_connector {
906254885Sdumbbell	bool valid;
907254885Sdumbbell	uint16_t line_mux;
908254885Sdumbbell	uint16_t devices;
909254885Sdumbbell	int connector_type;
910254885Sdumbbell	struct radeon_i2c_bus_rec ddc_bus;
911254885Sdumbbell	struct radeon_hpd hpd;
912254885Sdumbbell};
913254885Sdumbbell
914254885Sdumbbellbool radeon_get_atom_connector_info_from_supported_devices_table(struct
915254885Sdumbbell								 drm_device
916254885Sdumbbell								 *dev)
917254885Sdumbbell{
918254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
919254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
920254885Sdumbbell	struct atom_context *ctx = mode_info->atom_context;
921254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo);
922254885Sdumbbell	uint16_t size, data_offset;
923254885Sdumbbell	uint8_t frev, crev;
924254885Sdumbbell	uint16_t device_support;
925254885Sdumbbell	uint8_t dac;
926254885Sdumbbell	union atom_supported_devices *supported_devices;
927254885Sdumbbell	int i, j, max_device;
928254885Sdumbbell	struct bios_connector *bios_connectors;
929254885Sdumbbell	size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
930254885Sdumbbell	struct radeon_router router;
931254885Sdumbbell
932254885Sdumbbell	router.ddc_valid = false;
933254885Sdumbbell	router.cd_valid = false;
934254885Sdumbbell
935282199Sdumbbell	bios_connectors = malloc(bc_size, DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
936254885Sdumbbell	if (!bios_connectors)
937254885Sdumbbell		return false;
938254885Sdumbbell
939254885Sdumbbell	if (!atom_parse_data_header(ctx, index, &size, &frev, &crev,
940254885Sdumbbell				    &data_offset)) {
941254885Sdumbbell		free(bios_connectors, DRM_MEM_DRIVER);
942254885Sdumbbell		return false;
943254885Sdumbbell	}
944254885Sdumbbell
945254885Sdumbbell	supported_devices =
946254885Sdumbbell	    (union atom_supported_devices *)((char *)ctx->bios + data_offset);
947254885Sdumbbell
948254885Sdumbbell	device_support = le16_to_cpu(supported_devices->info.usDeviceSupport);
949254885Sdumbbell
950254885Sdumbbell	if (frev > 1)
951254885Sdumbbell		max_device = ATOM_MAX_SUPPORTED_DEVICE;
952254885Sdumbbell	else
953254885Sdumbbell		max_device = ATOM_MAX_SUPPORTED_DEVICE_INFO;
954254885Sdumbbell
955254885Sdumbbell	for (i = 0; i < max_device; i++) {
956254885Sdumbbell		ATOM_CONNECTOR_INFO_I2C ci =
957254885Sdumbbell		    supported_devices->info.asConnInfo[i];
958254885Sdumbbell
959254885Sdumbbell		bios_connectors[i].valid = false;
960254885Sdumbbell
961254885Sdumbbell		if (!(device_support & (1 << i))) {
962254885Sdumbbell			continue;
963254885Sdumbbell		}
964254885Sdumbbell
965254885Sdumbbell		if (i == ATOM_DEVICE_CV_INDEX) {
966254885Sdumbbell			DRM_DEBUG_KMS("Skipping Component Video\n");
967254885Sdumbbell			continue;
968254885Sdumbbell		}
969254885Sdumbbell
970254885Sdumbbell		bios_connectors[i].connector_type =
971254885Sdumbbell		    supported_devices_connector_convert[ci.sucConnectorInfo.
972254885Sdumbbell							sbfAccess.
973254885Sdumbbell							bfConnectorType];
974254885Sdumbbell
975254885Sdumbbell		if (bios_connectors[i].connector_type ==
976254885Sdumbbell		    DRM_MODE_CONNECTOR_Unknown)
977254885Sdumbbell			continue;
978254885Sdumbbell
979254885Sdumbbell		dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC;
980254885Sdumbbell
981254885Sdumbbell		bios_connectors[i].line_mux =
982254885Sdumbbell			ci.sucI2cId.ucAccess;
983254885Sdumbbell
984254885Sdumbbell		/* give tv unique connector ids */
985254885Sdumbbell		if (i == ATOM_DEVICE_TV1_INDEX) {
986254885Sdumbbell			bios_connectors[i].ddc_bus.valid = false;
987254885Sdumbbell			bios_connectors[i].line_mux = 50;
988254885Sdumbbell		} else if (i == ATOM_DEVICE_TV2_INDEX) {
989254885Sdumbbell			bios_connectors[i].ddc_bus.valid = false;
990254885Sdumbbell			bios_connectors[i].line_mux = 51;
991254885Sdumbbell		} else if (i == ATOM_DEVICE_CV_INDEX) {
992254885Sdumbbell			bios_connectors[i].ddc_bus.valid = false;
993254885Sdumbbell			bios_connectors[i].line_mux = 52;
994254885Sdumbbell		} else
995254885Sdumbbell			bios_connectors[i].ddc_bus =
996254885Sdumbbell			    radeon_lookup_i2c_gpio(rdev,
997254885Sdumbbell						   bios_connectors[i].line_mux);
998254885Sdumbbell
999254885Sdumbbell		if ((crev > 1) && (frev > 1)) {
1000254885Sdumbbell			u8 isb = supported_devices->info_2d1.asIntSrcInfo[i].ucIntSrcBitmap;
1001254885Sdumbbell			switch (isb) {
1002254885Sdumbbell			case 0x4:
1003254885Sdumbbell				bios_connectors[i].hpd.hpd = RADEON_HPD_1;
1004254885Sdumbbell				break;
1005254885Sdumbbell			case 0xa:
1006254885Sdumbbell				bios_connectors[i].hpd.hpd = RADEON_HPD_2;
1007254885Sdumbbell				break;
1008254885Sdumbbell			default:
1009254885Sdumbbell				bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
1010254885Sdumbbell				break;
1011254885Sdumbbell			}
1012254885Sdumbbell		} else {
1013254885Sdumbbell			if (i == ATOM_DEVICE_DFP1_INDEX)
1014254885Sdumbbell				bios_connectors[i].hpd.hpd = RADEON_HPD_1;
1015254885Sdumbbell			else if (i == ATOM_DEVICE_DFP2_INDEX)
1016254885Sdumbbell				bios_connectors[i].hpd.hpd = RADEON_HPD_2;
1017254885Sdumbbell			else
1018254885Sdumbbell				bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
1019254885Sdumbbell		}
1020254885Sdumbbell
1021254885Sdumbbell		/* Always set the connector type to VGA for CRT1/CRT2. if they are
1022254885Sdumbbell		 * shared with a DVI port, we'll pick up the DVI connector when we
1023254885Sdumbbell		 * merge the outputs.  Some bioses incorrectly list VGA ports as DVI.
1024254885Sdumbbell		 */
1025254885Sdumbbell		if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX)
1026254885Sdumbbell			bios_connectors[i].connector_type =
1027254885Sdumbbell			    DRM_MODE_CONNECTOR_VGA;
1028254885Sdumbbell
1029254885Sdumbbell		if (!radeon_atom_apply_quirks
1030254885Sdumbbell		    (dev, (1 << i), &bios_connectors[i].connector_type,
1031254885Sdumbbell		     &bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux,
1032254885Sdumbbell		     &bios_connectors[i].hpd))
1033254885Sdumbbell			continue;
1034254885Sdumbbell
1035254885Sdumbbell		bios_connectors[i].valid = true;
1036254885Sdumbbell		bios_connectors[i].devices = (1 << i);
1037254885Sdumbbell
1038254885Sdumbbell		if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom)
1039254885Sdumbbell			radeon_add_atom_encoder(dev,
1040254885Sdumbbell						radeon_get_encoder_enum(dev,
1041254885Sdumbbell								      (1 << i),
1042254885Sdumbbell								      dac),
1043254885Sdumbbell						(1 << i),
1044254885Sdumbbell						0);
1045254885Sdumbbell		else
1046254885Sdumbbell			radeon_add_legacy_encoder(dev,
1047254885Sdumbbell						  radeon_get_encoder_enum(dev,
1048254885Sdumbbell									(1 << i),
1049254885Sdumbbell									dac),
1050254885Sdumbbell						  (1 << i));
1051254885Sdumbbell	}
1052254885Sdumbbell
1053254885Sdumbbell	/* combine shared connectors */
1054254885Sdumbbell	for (i = 0; i < max_device; i++) {
1055254885Sdumbbell		if (bios_connectors[i].valid) {
1056254885Sdumbbell			for (j = 0; j < max_device; j++) {
1057254885Sdumbbell				if (bios_connectors[j].valid && (i != j)) {
1058254885Sdumbbell					if (bios_connectors[i].line_mux ==
1059254885Sdumbbell					    bios_connectors[j].line_mux) {
1060254885Sdumbbell						/* make sure not to combine LVDS */
1061254885Sdumbbell						if (bios_connectors[i].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1062254885Sdumbbell							bios_connectors[i].line_mux = 53;
1063254885Sdumbbell							bios_connectors[i].ddc_bus.valid = false;
1064254885Sdumbbell							continue;
1065254885Sdumbbell						}
1066254885Sdumbbell						if (bios_connectors[j].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1067254885Sdumbbell							bios_connectors[j].line_mux = 53;
1068254885Sdumbbell							bios_connectors[j].ddc_bus.valid = false;
1069254885Sdumbbell							continue;
1070254885Sdumbbell						}
1071254885Sdumbbell						/* combine analog and digital for DVI-I */
1072254885Sdumbbell						if (((bios_connectors[i].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
1073254885Sdumbbell						     (bios_connectors[j].devices & (ATOM_DEVICE_CRT_SUPPORT))) ||
1074254885Sdumbbell						    ((bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
1075254885Sdumbbell						     (bios_connectors[i].devices & (ATOM_DEVICE_CRT_SUPPORT)))) {
1076254885Sdumbbell							bios_connectors[i].devices |=
1077254885Sdumbbell								bios_connectors[j].devices;
1078254885Sdumbbell							bios_connectors[i].connector_type =
1079254885Sdumbbell								DRM_MODE_CONNECTOR_DVII;
1080254885Sdumbbell							if (bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT))
1081254885Sdumbbell								bios_connectors[i].hpd =
1082254885Sdumbbell									bios_connectors[j].hpd;
1083254885Sdumbbell							bios_connectors[j].valid = false;
1084254885Sdumbbell						}
1085254885Sdumbbell					}
1086254885Sdumbbell				}
1087254885Sdumbbell			}
1088254885Sdumbbell		}
1089254885Sdumbbell	}
1090254885Sdumbbell
1091254885Sdumbbell	/* add the connectors */
1092254885Sdumbbell	for (i = 0; i < max_device; i++) {
1093254885Sdumbbell		if (bios_connectors[i].valid) {
1094254885Sdumbbell			uint16_t connector_object_id =
1095254885Sdumbbell				atombios_get_connector_object_id(dev,
1096254885Sdumbbell						      bios_connectors[i].connector_type,
1097254885Sdumbbell						      bios_connectors[i].devices);
1098254885Sdumbbell			radeon_add_atom_connector(dev,
1099254885Sdumbbell						  bios_connectors[i].line_mux,
1100254885Sdumbbell						  bios_connectors[i].devices,
1101254885Sdumbbell						  bios_connectors[i].
1102254885Sdumbbell						  connector_type,
1103254885Sdumbbell						  &bios_connectors[i].ddc_bus,
1104254885Sdumbbell						  0,
1105254885Sdumbbell						  connector_object_id,
1106254885Sdumbbell						  &bios_connectors[i].hpd,
1107254885Sdumbbell						  &router);
1108254885Sdumbbell		}
1109254885Sdumbbell	}
1110254885Sdumbbell
1111254885Sdumbbell	radeon_link_encoder_connector(dev);
1112254885Sdumbbell
1113254885Sdumbbell	free(bios_connectors, DRM_MEM_DRIVER);
1114254885Sdumbbell	return true;
1115254885Sdumbbell}
1116254885Sdumbbell
1117254885Sdumbbellunion firmware_info {
1118254885Sdumbbell	ATOM_FIRMWARE_INFO info;
1119254885Sdumbbell	ATOM_FIRMWARE_INFO_V1_2 info_12;
1120254885Sdumbbell	ATOM_FIRMWARE_INFO_V1_3 info_13;
1121254885Sdumbbell	ATOM_FIRMWARE_INFO_V1_4 info_14;
1122254885Sdumbbell	ATOM_FIRMWARE_INFO_V2_1 info_21;
1123254885Sdumbbell	ATOM_FIRMWARE_INFO_V2_2 info_22;
1124254885Sdumbbell};
1125254885Sdumbbell
1126254885Sdumbbellbool radeon_atom_get_clock_info(struct drm_device *dev)
1127254885Sdumbbell{
1128254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1129254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1130254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
1131254885Sdumbbell	union firmware_info *firmware_info;
1132254885Sdumbbell	uint8_t frev, crev;
1133254885Sdumbbell	struct radeon_pll *p1pll = &rdev->clock.p1pll;
1134254885Sdumbbell	struct radeon_pll *p2pll = &rdev->clock.p2pll;
1135254885Sdumbbell	struct radeon_pll *dcpll = &rdev->clock.dcpll;
1136254885Sdumbbell	struct radeon_pll *spll = &rdev->clock.spll;
1137254885Sdumbbell	struct radeon_pll *mpll = &rdev->clock.mpll;
1138254885Sdumbbell	uint16_t data_offset;
1139254885Sdumbbell
1140254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1141254885Sdumbbell				   &frev, &crev, &data_offset)) {
1142254885Sdumbbell		firmware_info =
1143254885Sdumbbell			(union firmware_info *)((char *)mode_info->atom_context->bios +
1144254885Sdumbbell						data_offset);
1145254885Sdumbbell		/* pixel clocks */
1146254885Sdumbbell		p1pll->reference_freq =
1147254885Sdumbbell		    le16_to_cpu(firmware_info->info.usReferenceClock);
1148254885Sdumbbell		p1pll->reference_div = 0;
1149254885Sdumbbell
1150254885Sdumbbell		if (crev < 2)
1151254885Sdumbbell			p1pll->pll_out_min =
1152254885Sdumbbell				le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
1153254885Sdumbbell		else
1154254885Sdumbbell			p1pll->pll_out_min =
1155254885Sdumbbell				le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
1156254885Sdumbbell		p1pll->pll_out_max =
1157254885Sdumbbell		    le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
1158254885Sdumbbell
1159254885Sdumbbell		if (crev >= 4) {
1160254885Sdumbbell			p1pll->lcd_pll_out_min =
1161254885Sdumbbell				le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
1162254885Sdumbbell			if (p1pll->lcd_pll_out_min == 0)
1163254885Sdumbbell				p1pll->lcd_pll_out_min = p1pll->pll_out_min;
1164254885Sdumbbell			p1pll->lcd_pll_out_max =
1165254885Sdumbbell				le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
1166254885Sdumbbell			if (p1pll->lcd_pll_out_max == 0)
1167254885Sdumbbell				p1pll->lcd_pll_out_max = p1pll->pll_out_max;
1168254885Sdumbbell		} else {
1169254885Sdumbbell			p1pll->lcd_pll_out_min = p1pll->pll_out_min;
1170254885Sdumbbell			p1pll->lcd_pll_out_max = p1pll->pll_out_max;
1171254885Sdumbbell		}
1172254885Sdumbbell
1173254885Sdumbbell		if (p1pll->pll_out_min == 0) {
1174254885Sdumbbell			if (ASIC_IS_AVIVO(rdev))
1175254885Sdumbbell				p1pll->pll_out_min = 64800;
1176254885Sdumbbell			else
1177254885Sdumbbell				p1pll->pll_out_min = 20000;
1178254885Sdumbbell		}
1179254885Sdumbbell
1180254885Sdumbbell		p1pll->pll_in_min =
1181254885Sdumbbell		    le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input);
1182254885Sdumbbell		p1pll->pll_in_max =
1183254885Sdumbbell		    le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input);
1184254885Sdumbbell
1185254885Sdumbbell		*p2pll = *p1pll;
1186254885Sdumbbell
1187254885Sdumbbell		/* system clock */
1188254885Sdumbbell		if (ASIC_IS_DCE4(rdev))
1189254885Sdumbbell			spll->reference_freq =
1190254885Sdumbbell				le16_to_cpu(firmware_info->info_21.usCoreReferenceClock);
1191254885Sdumbbell		else
1192254885Sdumbbell			spll->reference_freq =
1193254885Sdumbbell				le16_to_cpu(firmware_info->info.usReferenceClock);
1194254885Sdumbbell		spll->reference_div = 0;
1195254885Sdumbbell
1196254885Sdumbbell		spll->pll_out_min =
1197254885Sdumbbell		    le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output);
1198254885Sdumbbell		spll->pll_out_max =
1199254885Sdumbbell		    le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output);
1200254885Sdumbbell
1201254885Sdumbbell		/* ??? */
1202254885Sdumbbell		if (spll->pll_out_min == 0) {
1203254885Sdumbbell			if (ASIC_IS_AVIVO(rdev))
1204254885Sdumbbell				spll->pll_out_min = 64800;
1205254885Sdumbbell			else
1206254885Sdumbbell				spll->pll_out_min = 20000;
1207254885Sdumbbell		}
1208254885Sdumbbell
1209254885Sdumbbell		spll->pll_in_min =
1210254885Sdumbbell		    le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input);
1211254885Sdumbbell		spll->pll_in_max =
1212254885Sdumbbell		    le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input);
1213254885Sdumbbell
1214254885Sdumbbell		/* memory clock */
1215254885Sdumbbell		if (ASIC_IS_DCE4(rdev))
1216254885Sdumbbell			mpll->reference_freq =
1217254885Sdumbbell				le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock);
1218254885Sdumbbell		else
1219254885Sdumbbell			mpll->reference_freq =
1220254885Sdumbbell				le16_to_cpu(firmware_info->info.usReferenceClock);
1221254885Sdumbbell		mpll->reference_div = 0;
1222254885Sdumbbell
1223254885Sdumbbell		mpll->pll_out_min =
1224254885Sdumbbell		    le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output);
1225254885Sdumbbell		mpll->pll_out_max =
1226254885Sdumbbell		    le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output);
1227254885Sdumbbell
1228254885Sdumbbell		/* ??? */
1229254885Sdumbbell		if (mpll->pll_out_min == 0) {
1230254885Sdumbbell			if (ASIC_IS_AVIVO(rdev))
1231254885Sdumbbell				mpll->pll_out_min = 64800;
1232254885Sdumbbell			else
1233254885Sdumbbell				mpll->pll_out_min = 20000;
1234254885Sdumbbell		}
1235254885Sdumbbell
1236254885Sdumbbell		mpll->pll_in_min =
1237254885Sdumbbell		    le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input);
1238254885Sdumbbell		mpll->pll_in_max =
1239254885Sdumbbell		    le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input);
1240254885Sdumbbell
1241254885Sdumbbell		rdev->clock.default_sclk =
1242254885Sdumbbell		    le32_to_cpu(firmware_info->info.ulDefaultEngineClock);
1243254885Sdumbbell		rdev->clock.default_mclk =
1244254885Sdumbbell		    le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);
1245254885Sdumbbell
1246254885Sdumbbell		if (ASIC_IS_DCE4(rdev)) {
1247254885Sdumbbell			rdev->clock.default_dispclk =
1248254885Sdumbbell				le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);
1249254885Sdumbbell			if (rdev->clock.default_dispclk == 0) {
1250254885Sdumbbell				if (ASIC_IS_DCE5(rdev))
1251254885Sdumbbell					rdev->clock.default_dispclk = 54000; /* 540 Mhz */
1252254885Sdumbbell				else
1253254885Sdumbbell					rdev->clock.default_dispclk = 60000; /* 600 Mhz */
1254254885Sdumbbell			}
1255254885Sdumbbell			rdev->clock.dp_extclk =
1256254885Sdumbbell				le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
1257254885Sdumbbell		}
1258254885Sdumbbell		*dcpll = *p1pll;
1259254885Sdumbbell
1260254885Sdumbbell		rdev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock);
1261254885Sdumbbell		if (rdev->clock.max_pixel_clock == 0)
1262254885Sdumbbell			rdev->clock.max_pixel_clock = 40000;
1263254885Sdumbbell
1264254885Sdumbbell		/* not technically a clock, but... */
1265254885Sdumbbell		rdev->mode_info.firmware_flags =
1266254885Sdumbbell			le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);
1267254885Sdumbbell
1268254885Sdumbbell		return true;
1269254885Sdumbbell	}
1270254885Sdumbbell
1271254885Sdumbbell	return false;
1272254885Sdumbbell}
1273254885Sdumbbell
1274254885Sdumbbellunion igp_info {
1275254885Sdumbbell	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
1276254885Sdumbbell	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
1277254885Sdumbbell	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
1278254885Sdumbbell	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
1279254885Sdumbbell};
1280254885Sdumbbell
1281254885Sdumbbellbool radeon_atombios_sideport_present(struct radeon_device *rdev)
1282254885Sdumbbell{
1283254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1284254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1285254885Sdumbbell	union igp_info *igp_info;
1286254885Sdumbbell	u8 frev, crev;
1287254885Sdumbbell	u16 data_offset;
1288254885Sdumbbell
1289254885Sdumbbell	/* sideport is AMD only */
1290254885Sdumbbell	if (rdev->family == CHIP_RS600)
1291254885Sdumbbell		return false;
1292254885Sdumbbell
1293254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1294254885Sdumbbell				   &frev, &crev, &data_offset)) {
1295254885Sdumbbell		igp_info = (union igp_info *)((char *)mode_info->atom_context->bios +
1296254885Sdumbbell				      data_offset);
1297254885Sdumbbell		switch (crev) {
1298254885Sdumbbell		case 1:
1299254885Sdumbbell			if (le32_to_cpu(igp_info->info.ulBootUpMemoryClock))
1300254885Sdumbbell				return true;
1301254885Sdumbbell			break;
1302254885Sdumbbell		case 2:
1303254885Sdumbbell			if (le32_to_cpu(igp_info->info_2.ulBootUpSidePortClock))
1304254885Sdumbbell				return true;
1305254885Sdumbbell			break;
1306254885Sdumbbell		default:
1307254885Sdumbbell			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
1308254885Sdumbbell			break;
1309254885Sdumbbell		}
1310254885Sdumbbell	}
1311254885Sdumbbell	return false;
1312254885Sdumbbell}
1313254885Sdumbbell
1314254885Sdumbbellbool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,
1315254885Sdumbbell				   struct radeon_encoder_int_tmds *tmds)
1316254885Sdumbbell{
1317254885Sdumbbell	struct drm_device *dev = encoder->base.dev;
1318254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1319254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1320254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, TMDS_Info);
1321254885Sdumbbell	uint16_t data_offset;
1322254885Sdumbbell	struct _ATOM_TMDS_INFO *tmds_info;
1323254885Sdumbbell	uint8_t frev, crev;
1324254885Sdumbbell	uint16_t maxfreq;
1325254885Sdumbbell	int i;
1326254885Sdumbbell
1327254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1328254885Sdumbbell				   &frev, &crev, &data_offset)) {
1329254885Sdumbbell		tmds_info =
1330254885Sdumbbell			(struct _ATOM_TMDS_INFO *)((char *)mode_info->atom_context->bios +
1331254885Sdumbbell						   data_offset);
1332254885Sdumbbell
1333254885Sdumbbell		maxfreq = le16_to_cpu(tmds_info->usMaxFrequency);
1334254885Sdumbbell		for (i = 0; i < 4; i++) {
1335254885Sdumbbell			tmds->tmds_pll[i].freq =
1336254885Sdumbbell			    le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency);
1337254885Sdumbbell			tmds->tmds_pll[i].value =
1338254885Sdumbbell			    tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f;
1339254885Sdumbbell			tmds->tmds_pll[i].value |=
1340254885Sdumbbell			    (tmds_info->asMiscInfo[i].
1341254885Sdumbbell			     ucPLL_VCO_Gain & 0x3f) << 6;
1342254885Sdumbbell			tmds->tmds_pll[i].value |=
1343254885Sdumbbell			    (tmds_info->asMiscInfo[i].
1344254885Sdumbbell			     ucPLL_DutyCycle & 0xf) << 12;
1345254885Sdumbbell			tmds->tmds_pll[i].value |=
1346254885Sdumbbell			    (tmds_info->asMiscInfo[i].
1347254885Sdumbbell			     ucPLL_VoltageSwing & 0xf) << 16;
1348254885Sdumbbell
1349254885Sdumbbell			DRM_DEBUG_KMS("TMDS PLL From ATOMBIOS %u %x\n",
1350254885Sdumbbell				  tmds->tmds_pll[i].freq,
1351254885Sdumbbell				  tmds->tmds_pll[i].value);
1352254885Sdumbbell
1353254885Sdumbbell			if (maxfreq == tmds->tmds_pll[i].freq) {
1354254885Sdumbbell				tmds->tmds_pll[i].freq = 0xffffffff;
1355254885Sdumbbell				break;
1356254885Sdumbbell			}
1357254885Sdumbbell		}
1358254885Sdumbbell		return true;
1359254885Sdumbbell	}
1360254885Sdumbbell	return false;
1361254885Sdumbbell}
1362254885Sdumbbell
1363254885Sdumbbellbool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
1364254885Sdumbbell				      struct radeon_atom_ss *ss,
1365254885Sdumbbell				      int id)
1366254885Sdumbbell{
1367254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1368254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
1369254885Sdumbbell	uint16_t data_offset, size;
1370254885Sdumbbell	struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
1371254885Sdumbbell	uint8_t frev, crev;
1372254885Sdumbbell	int i, num_indices;
1373254885Sdumbbell
1374254885Sdumbbell	memset(ss, 0, sizeof(struct radeon_atom_ss));
1375254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, &size,
1376254885Sdumbbell				   &frev, &crev, &data_offset)) {
1377254885Sdumbbell		ss_info =
1378254885Sdumbbell			(struct _ATOM_SPREAD_SPECTRUM_INFO *)((char *)mode_info->atom_context->bios + data_offset);
1379254885Sdumbbell
1380254885Sdumbbell		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1381254885Sdumbbell			sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1382254885Sdumbbell
1383254885Sdumbbell		for (i = 0; i < num_indices; i++) {
1384254885Sdumbbell			if (ss_info->asSS_Info[i].ucSS_Id == id) {
1385254885Sdumbbell				ss->percentage =
1386254885Sdumbbell					le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage);
1387254885Sdumbbell				ss->type = ss_info->asSS_Info[i].ucSpreadSpectrumType;
1388254885Sdumbbell				ss->step = ss_info->asSS_Info[i].ucSS_Step;
1389254885Sdumbbell				ss->delay = ss_info->asSS_Info[i].ucSS_Delay;
1390254885Sdumbbell				ss->range = ss_info->asSS_Info[i].ucSS_Range;
1391254885Sdumbbell				ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div;
1392254885Sdumbbell				return true;
1393254885Sdumbbell			}
1394254885Sdumbbell		}
1395254885Sdumbbell	}
1396254885Sdumbbell	return false;
1397254885Sdumbbell}
1398254885Sdumbbell
1399254885Sdumbbellstatic void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
1400254885Sdumbbell						 struct radeon_atom_ss *ss,
1401254885Sdumbbell						 int id)
1402254885Sdumbbell{
1403254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1404254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1405254885Sdumbbell	u16 data_offset, size;
1406254885Sdumbbell	union igp_info *igp_info;
1407254885Sdumbbell	u8 frev, crev;
1408254885Sdumbbell	u16 percentage = 0, rate = 0;
1409254885Sdumbbell
1410254885Sdumbbell	/* get any igp specific overrides */
1411254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, &size,
1412254885Sdumbbell				   &frev, &crev, &data_offset)) {
1413254885Sdumbbell		igp_info = (union igp_info *)
1414254885Sdumbbell			((char *)mode_info->atom_context->bios + data_offset);
1415254885Sdumbbell		switch (crev) {
1416254885Sdumbbell		case 6:
1417254885Sdumbbell			switch (id) {
1418254885Sdumbbell			case ASIC_INTERNAL_SS_ON_TMDS:
1419254885Sdumbbell				percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage);
1420254885Sdumbbell				rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz);
1421254885Sdumbbell				break;
1422254885Sdumbbell			case ASIC_INTERNAL_SS_ON_HDMI:
1423254885Sdumbbell				percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage);
1424254885Sdumbbell				rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz);
1425254885Sdumbbell				break;
1426254885Sdumbbell			case ASIC_INTERNAL_SS_ON_LVDS:
1427254885Sdumbbell				percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage);
1428254885Sdumbbell				rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz);
1429254885Sdumbbell				break;
1430254885Sdumbbell			}
1431254885Sdumbbell			break;
1432254885Sdumbbell		case 7:
1433254885Sdumbbell			switch (id) {
1434254885Sdumbbell			case ASIC_INTERNAL_SS_ON_TMDS:
1435254885Sdumbbell				percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage);
1436254885Sdumbbell				rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz);
1437254885Sdumbbell				break;
1438254885Sdumbbell			case ASIC_INTERNAL_SS_ON_HDMI:
1439254885Sdumbbell				percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage);
1440254885Sdumbbell				rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz);
1441254885Sdumbbell				break;
1442254885Sdumbbell			case ASIC_INTERNAL_SS_ON_LVDS:
1443254885Sdumbbell				percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage);
1444254885Sdumbbell				rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz);
1445254885Sdumbbell				break;
1446254885Sdumbbell			}
1447254885Sdumbbell			break;
1448254885Sdumbbell		default:
1449254885Sdumbbell			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
1450254885Sdumbbell			break;
1451254885Sdumbbell		}
1452254885Sdumbbell		if (percentage)
1453254885Sdumbbell			ss->percentage = percentage;
1454254885Sdumbbell		if (rate)
1455254885Sdumbbell			ss->rate = rate;
1456254885Sdumbbell	}
1457254885Sdumbbell}
1458254885Sdumbbell
1459254885Sdumbbellunion asic_ss_info {
1460254885Sdumbbell	struct _ATOM_ASIC_INTERNAL_SS_INFO info;
1461254885Sdumbbell	struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
1462254885Sdumbbell	struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
1463254885Sdumbbell};
1464254885Sdumbbell
1465254885Sdumbbellbool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
1466254885Sdumbbell				      struct radeon_atom_ss *ss,
1467254885Sdumbbell				      int id, u32 clock)
1468254885Sdumbbell{
1469254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1470254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
1471254885Sdumbbell	uint16_t data_offset, size;
1472254885Sdumbbell	union asic_ss_info *ss_info;
1473254885Sdumbbell	uint8_t frev, crev;
1474254885Sdumbbell	int i, num_indices;
1475254885Sdumbbell
1476254885Sdumbbell	memset(ss, 0, sizeof(struct radeon_atom_ss));
1477254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, &size,
1478254885Sdumbbell				   &frev, &crev, &data_offset)) {
1479254885Sdumbbell
1480254885Sdumbbell		ss_info =
1481254885Sdumbbell			(union asic_ss_info *)((char *)mode_info->atom_context->bios + data_offset);
1482254885Sdumbbell
1483254885Sdumbbell		switch (frev) {
1484254885Sdumbbell		case 1:
1485254885Sdumbbell			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1486254885Sdumbbell				sizeof(ATOM_ASIC_SS_ASSIGNMENT);
1487254885Sdumbbell
1488254885Sdumbbell			for (i = 0; i < num_indices; i++) {
1489254885Sdumbbell				if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) &&
1490254885Sdumbbell				    (clock <= le32_to_cpu(ss_info->info.asSpreadSpectrum[i].ulTargetClockRange))) {
1491254885Sdumbbell					ss->percentage =
1492254885Sdumbbell						le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
1493254885Sdumbbell					ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
1494254885Sdumbbell					ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz);
1495254885Sdumbbell					return true;
1496254885Sdumbbell				}
1497254885Sdumbbell			}
1498254885Sdumbbell			break;
1499254885Sdumbbell		case 2:
1500254885Sdumbbell			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1501254885Sdumbbell				sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1502254885Sdumbbell			for (i = 0; i < num_indices; i++) {
1503254885Sdumbbell				if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) &&
1504254885Sdumbbell				    (clock <= le32_to_cpu(ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange))) {
1505254885Sdumbbell					ss->percentage =
1506254885Sdumbbell						le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
1507254885Sdumbbell					ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
1508254885Sdumbbell					ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
1509254885Sdumbbell					return true;
1510254885Sdumbbell				}
1511254885Sdumbbell			}
1512254885Sdumbbell			break;
1513254885Sdumbbell		case 3:
1514254885Sdumbbell			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1515254885Sdumbbell				sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
1516254885Sdumbbell			for (i = 0; i < num_indices; i++) {
1517254885Sdumbbell				if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) &&
1518254885Sdumbbell				    (clock <= le32_to_cpu(ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange))) {
1519254885Sdumbbell					ss->percentage =
1520254885Sdumbbell						le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
1521254885Sdumbbell					ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
1522254885Sdumbbell					ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
1523254885Sdumbbell					if (rdev->flags & RADEON_IS_IGP)
1524254885Sdumbbell						radeon_atombios_get_igp_ss_overrides(rdev, ss, id);
1525254885Sdumbbell					return true;
1526254885Sdumbbell				}
1527254885Sdumbbell			}
1528254885Sdumbbell			break;
1529254885Sdumbbell		default:
1530254885Sdumbbell			DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);
1531254885Sdumbbell			break;
1532254885Sdumbbell		}
1533254885Sdumbbell
1534254885Sdumbbell	}
1535254885Sdumbbell	return false;
1536254885Sdumbbell}
1537254885Sdumbbell
1538254885Sdumbbellunion lvds_info {
1539254885Sdumbbell	struct _ATOM_LVDS_INFO info;
1540254885Sdumbbell	struct _ATOM_LVDS_INFO_V12 info_12;
1541254885Sdumbbell};
1542254885Sdumbbell
1543254885Sdumbbellstruct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
1544254885Sdumbbell							      radeon_encoder
1545254885Sdumbbell							      *encoder)
1546254885Sdumbbell{
1547254885Sdumbbell	struct drm_device *dev = encoder->base.dev;
1548254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1549254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1550254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
1551254885Sdumbbell	uint16_t data_offset, misc;
1552254885Sdumbbell	union lvds_info *lvds_info;
1553254885Sdumbbell	uint8_t frev, crev;
1554254885Sdumbbell	struct radeon_encoder_atom_dig *lvds = NULL;
1555254885Sdumbbell	int encoder_enum = (encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
1556254885Sdumbbell
1557254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1558254885Sdumbbell				   &frev, &crev, &data_offset)) {
1559254885Sdumbbell		lvds_info =
1560254885Sdumbbell			(union lvds_info *)((char *)mode_info->atom_context->bios + data_offset);
1561254885Sdumbbell		lvds =
1562254885Sdumbbell		    malloc(sizeof(struct radeon_encoder_atom_dig),
1563282199Sdumbbell			DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
1564254885Sdumbbell
1565254885Sdumbbell		if (!lvds)
1566254885Sdumbbell			return NULL;
1567254885Sdumbbell
1568254885Sdumbbell		lvds->native_mode.clock =
1569254885Sdumbbell		    le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10;
1570254885Sdumbbell		lvds->native_mode.hdisplay =
1571254885Sdumbbell		    le16_to_cpu(lvds_info->info.sLCDTiming.usHActive);
1572254885Sdumbbell		lvds->native_mode.vdisplay =
1573254885Sdumbbell		    le16_to_cpu(lvds_info->info.sLCDTiming.usVActive);
1574254885Sdumbbell		lvds->native_mode.htotal = lvds->native_mode.hdisplay +
1575254885Sdumbbell			le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
1576254885Sdumbbell		lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
1577254885Sdumbbell			le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
1578254885Sdumbbell		lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
1579254885Sdumbbell			le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);
1580254885Sdumbbell		lvds->native_mode.vtotal = lvds->native_mode.vdisplay +
1581254885Sdumbbell			le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
1582254885Sdumbbell		lvds->native_mode.vsync_start = lvds->native_mode.vdisplay +
1583254885Sdumbbell			le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset);
1584254885Sdumbbell		lvds->native_mode.vsync_end = lvds->native_mode.vsync_start +
1585254885Sdumbbell			le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
1586254885Sdumbbell		lvds->panel_pwr_delay =
1587254885Sdumbbell		    le16_to_cpu(lvds_info->info.usOffDelayInMs);
1588254885Sdumbbell		lvds->lcd_misc = lvds_info->info.ucLVDS_Misc;
1589254885Sdumbbell
1590254885Sdumbbell		misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess);
1591254885Sdumbbell		if (misc & ATOM_VSYNC_POLARITY)
1592254885Sdumbbell			lvds->native_mode.flags |= DRM_MODE_FLAG_NVSYNC;
1593254885Sdumbbell		if (misc & ATOM_HSYNC_POLARITY)
1594254885Sdumbbell			lvds->native_mode.flags |= DRM_MODE_FLAG_NHSYNC;
1595254885Sdumbbell		if (misc & ATOM_COMPOSITESYNC)
1596254885Sdumbbell			lvds->native_mode.flags |= DRM_MODE_FLAG_CSYNC;
1597254885Sdumbbell		if (misc & ATOM_INTERLACE)
1598254885Sdumbbell			lvds->native_mode.flags |= DRM_MODE_FLAG_INTERLACE;
1599254885Sdumbbell		if (misc & ATOM_DOUBLE_CLOCK_MODE)
1600254885Sdumbbell			lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN;
1601254885Sdumbbell
1602254885Sdumbbell		lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize);
1603254885Sdumbbell		lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize);
1604254885Sdumbbell
1605254885Sdumbbell		/* set crtc values */
1606254885Sdumbbell		drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
1607254885Sdumbbell
1608254885Sdumbbell		lvds->lcd_ss_id = lvds_info->info.ucSS_Id;
1609254885Sdumbbell
1610254885Sdumbbell		encoder->native_mode = lvds->native_mode;
1611254885Sdumbbell
1612254885Sdumbbell		if (encoder_enum == 2)
1613254885Sdumbbell			lvds->linkb = true;
1614254885Sdumbbell		else
1615254885Sdumbbell			lvds->linkb = false;
1616254885Sdumbbell
1617254885Sdumbbell		/* parse the lcd record table */
1618254885Sdumbbell		if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) {
1619254885Sdumbbell			ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
1620254885Sdumbbell			ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
1621254885Sdumbbell			bool bad_record = false;
1622254885Sdumbbell			u8 *record;
1623254885Sdumbbell
1624254885Sdumbbell			if ((frev == 1) && (crev < 2))
1625254885Sdumbbell				/* absolute */
1626254885Sdumbbell				record = (u8 *)((char *)mode_info->atom_context->bios +
1627254885Sdumbbell						le16_to_cpu(lvds_info->info.usModePatchTableOffset));
1628254885Sdumbbell			else
1629254885Sdumbbell				/* relative */
1630254885Sdumbbell				record = (u8 *)((char *)mode_info->atom_context->bios +
1631254885Sdumbbell						data_offset +
1632254885Sdumbbell						le16_to_cpu(lvds_info->info.usModePatchTableOffset));
1633254885Sdumbbell			while (*record != ATOM_RECORD_END_TYPE) {
1634254885Sdumbbell				switch (*record) {
1635254885Sdumbbell				case LCD_MODE_PATCH_RECORD_MODE_TYPE:
1636254885Sdumbbell					record += sizeof(ATOM_PATCH_RECORD_MODE);
1637254885Sdumbbell					break;
1638254885Sdumbbell				case LCD_RTS_RECORD_TYPE:
1639254885Sdumbbell					record += sizeof(ATOM_LCD_RTS_RECORD);
1640254885Sdumbbell					break;
1641254885Sdumbbell				case LCD_CAP_RECORD_TYPE:
1642254885Sdumbbell					record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
1643254885Sdumbbell					break;
1644254885Sdumbbell				case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
1645254885Sdumbbell					fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
1646254885Sdumbbell					if (fake_edid_record->ucFakeEDIDLength) {
1647254885Sdumbbell						struct edid *edid;
1648254885Sdumbbell						int edid_size =
1649254885Sdumbbell							max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength);
1650282199Sdumbbell						edid = malloc(edid_size, DRM_MEM_KMS, M_NOWAIT);
1651254885Sdumbbell						if (edid) {
1652254885Sdumbbell							memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
1653254885Sdumbbell							       fake_edid_record->ucFakeEDIDLength);
1654254885Sdumbbell
1655254885Sdumbbell							if (drm_edid_is_valid(edid)) {
1656254885Sdumbbell								rdev->mode_info.bios_hardcoded_edid = edid;
1657254885Sdumbbell								rdev->mode_info.bios_hardcoded_edid_size = edid_size;
1658254885Sdumbbell							} else
1659254885Sdumbbell								free(edid, DRM_MEM_KMS);
1660254885Sdumbbell						}
1661254885Sdumbbell					}
1662254885Sdumbbell					record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD);
1663254885Sdumbbell					break;
1664254885Sdumbbell				case LCD_PANEL_RESOLUTION_RECORD_TYPE:
1665254885Sdumbbell					panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
1666254885Sdumbbell					lvds->native_mode.width_mm = panel_res_record->usHSize;
1667254885Sdumbbell					lvds->native_mode.height_mm = panel_res_record->usVSize;
1668254885Sdumbbell					record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
1669254885Sdumbbell					break;
1670254885Sdumbbell				default:
1671254885Sdumbbell					DRM_ERROR("Bad LCD record %d\n", *record);
1672254885Sdumbbell					bad_record = true;
1673254885Sdumbbell					break;
1674254885Sdumbbell				}
1675254885Sdumbbell				if (bad_record)
1676254885Sdumbbell					break;
1677254885Sdumbbell			}
1678254885Sdumbbell		}
1679254885Sdumbbell	}
1680254885Sdumbbell	return lvds;
1681254885Sdumbbell}
1682254885Sdumbbell
1683254885Sdumbbellstruct radeon_encoder_primary_dac *
1684254885Sdumbbellradeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder)
1685254885Sdumbbell{
1686254885Sdumbbell	struct drm_device *dev = encoder->base.dev;
1687254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1688254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1689254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, CompassionateData);
1690254885Sdumbbell	uint16_t data_offset;
1691254885Sdumbbell	struct _COMPASSIONATE_DATA *dac_info;
1692254885Sdumbbell	uint8_t frev, crev;
1693254885Sdumbbell	uint8_t bg, dac;
1694254885Sdumbbell	struct radeon_encoder_primary_dac *p_dac = NULL;
1695254885Sdumbbell
1696254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1697254885Sdumbbell				   &frev, &crev, &data_offset)) {
1698254885Sdumbbell		dac_info = (struct _COMPASSIONATE_DATA *)
1699254885Sdumbbell			((char *)mode_info->atom_context->bios + data_offset);
1700254885Sdumbbell
1701254885Sdumbbell		p_dac = malloc(sizeof(struct radeon_encoder_primary_dac),
1702282199Sdumbbell		    DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
1703254885Sdumbbell
1704254885Sdumbbell		if (!p_dac)
1705254885Sdumbbell			return NULL;
1706254885Sdumbbell
1707254885Sdumbbell		bg = dac_info->ucDAC1_BG_Adjustment;
1708254885Sdumbbell		dac = dac_info->ucDAC1_DAC_Adjustment;
1709254885Sdumbbell		p_dac->ps2_pdac_adj = (bg << 8) | (dac);
1710254885Sdumbbell
1711254885Sdumbbell	}
1712254885Sdumbbell	return p_dac;
1713254885Sdumbbell}
1714254885Sdumbbell
1715254885Sdumbbellbool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
1716254885Sdumbbell				struct drm_display_mode *mode)
1717254885Sdumbbell{
1718254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1719254885Sdumbbell	ATOM_ANALOG_TV_INFO *tv_info;
1720254885Sdumbbell	ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
1721254885Sdumbbell	ATOM_DTD_FORMAT *dtd_timings;
1722254885Sdumbbell	int data_index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
1723254885Sdumbbell	u8 frev, crev;
1724254885Sdumbbell	u16 data_offset, misc;
1725254885Sdumbbell
1726254885Sdumbbell	if (!atom_parse_data_header(mode_info->atom_context, data_index, NULL,
1727254885Sdumbbell				    &frev, &crev, &data_offset))
1728254885Sdumbbell		return false;
1729254885Sdumbbell
1730254885Sdumbbell	switch (crev) {
1731254885Sdumbbell	case 1:
1732254885Sdumbbell		tv_info = (ATOM_ANALOG_TV_INFO *)((char *)mode_info->atom_context->bios + data_offset);
1733254885Sdumbbell		if (index >= MAX_SUPPORTED_TV_TIMING)
1734254885Sdumbbell			return false;
1735254885Sdumbbell
1736254885Sdumbbell		mode->crtc_htotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
1737254885Sdumbbell		mode->crtc_hdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
1738254885Sdumbbell		mode->crtc_hsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
1739254885Sdumbbell		mode->crtc_hsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) +
1740254885Sdumbbell			le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
1741254885Sdumbbell
1742254885Sdumbbell		mode->crtc_vtotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
1743254885Sdumbbell		mode->crtc_vdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
1744254885Sdumbbell		mode->crtc_vsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
1745254885Sdumbbell		mode->crtc_vsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) +
1746254885Sdumbbell			le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
1747254885Sdumbbell
1748254885Sdumbbell		mode->flags = 0;
1749254885Sdumbbell		misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess);
1750254885Sdumbbell		if (misc & ATOM_VSYNC_POLARITY)
1751254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_NVSYNC;
1752254885Sdumbbell		if (misc & ATOM_HSYNC_POLARITY)
1753254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_NHSYNC;
1754254885Sdumbbell		if (misc & ATOM_COMPOSITESYNC)
1755254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_CSYNC;
1756254885Sdumbbell		if (misc & ATOM_INTERLACE)
1757254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_INTERLACE;
1758254885Sdumbbell		if (misc & ATOM_DOUBLE_CLOCK_MODE)
1759254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_DBLSCAN;
1760254885Sdumbbell
1761254885Sdumbbell		mode->clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
1762254885Sdumbbell
1763254885Sdumbbell		if (index == 1) {
1764254885Sdumbbell			/* PAL timings appear to have wrong values for totals */
1765254885Sdumbbell			mode->crtc_htotal -= 1;
1766254885Sdumbbell			mode->crtc_vtotal -= 1;
1767254885Sdumbbell		}
1768254885Sdumbbell		break;
1769254885Sdumbbell	case 2:
1770254885Sdumbbell		tv_info_v1_2 = (ATOM_ANALOG_TV_INFO_V1_2 *)((char *)mode_info->atom_context->bios + data_offset);
1771254885Sdumbbell		if (index >= MAX_SUPPORTED_TV_TIMING_V1_2)
1772254885Sdumbbell			return false;
1773254885Sdumbbell
1774254885Sdumbbell		dtd_timings = &tv_info_v1_2->aModeTimings[index];
1775254885Sdumbbell		mode->crtc_htotal = le16_to_cpu(dtd_timings->usHActive) +
1776254885Sdumbbell			le16_to_cpu(dtd_timings->usHBlanking_Time);
1777254885Sdumbbell		mode->crtc_hdisplay = le16_to_cpu(dtd_timings->usHActive);
1778254885Sdumbbell		mode->crtc_hsync_start = le16_to_cpu(dtd_timings->usHActive) +
1779254885Sdumbbell			le16_to_cpu(dtd_timings->usHSyncOffset);
1780254885Sdumbbell		mode->crtc_hsync_end = mode->crtc_hsync_start +
1781254885Sdumbbell			le16_to_cpu(dtd_timings->usHSyncWidth);
1782254885Sdumbbell
1783254885Sdumbbell		mode->crtc_vtotal = le16_to_cpu(dtd_timings->usVActive) +
1784254885Sdumbbell			le16_to_cpu(dtd_timings->usVBlanking_Time);
1785254885Sdumbbell		mode->crtc_vdisplay = le16_to_cpu(dtd_timings->usVActive);
1786254885Sdumbbell		mode->crtc_vsync_start = le16_to_cpu(dtd_timings->usVActive) +
1787254885Sdumbbell			le16_to_cpu(dtd_timings->usVSyncOffset);
1788254885Sdumbbell		mode->crtc_vsync_end = mode->crtc_vsync_start +
1789254885Sdumbbell			le16_to_cpu(dtd_timings->usVSyncWidth);
1790254885Sdumbbell
1791254885Sdumbbell		mode->flags = 0;
1792254885Sdumbbell		misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
1793254885Sdumbbell		if (misc & ATOM_VSYNC_POLARITY)
1794254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_NVSYNC;
1795254885Sdumbbell		if (misc & ATOM_HSYNC_POLARITY)
1796254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_NHSYNC;
1797254885Sdumbbell		if (misc & ATOM_COMPOSITESYNC)
1798254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_CSYNC;
1799254885Sdumbbell		if (misc & ATOM_INTERLACE)
1800254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_INTERLACE;
1801254885Sdumbbell		if (misc & ATOM_DOUBLE_CLOCK_MODE)
1802254885Sdumbbell			mode->flags |= DRM_MODE_FLAG_DBLSCAN;
1803254885Sdumbbell
1804254885Sdumbbell		mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
1805254885Sdumbbell		break;
1806254885Sdumbbell	}
1807254885Sdumbbell	return true;
1808254885Sdumbbell}
1809254885Sdumbbell
1810254885Sdumbbellenum radeon_tv_std
1811254885Sdumbbellradeon_atombios_get_tv_info(struct radeon_device *rdev)
1812254885Sdumbbell{
1813254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1814254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
1815254885Sdumbbell	uint16_t data_offset;
1816254885Sdumbbell	uint8_t frev, crev;
1817254885Sdumbbell	struct _ATOM_ANALOG_TV_INFO *tv_info;
1818254885Sdumbbell	enum radeon_tv_std tv_std = TV_STD_NTSC;
1819254885Sdumbbell
1820254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1821254885Sdumbbell				   &frev, &crev, &data_offset)) {
1822254885Sdumbbell
1823254885Sdumbbell		tv_info = (struct _ATOM_ANALOG_TV_INFO *)
1824254885Sdumbbell			((char *)mode_info->atom_context->bios + data_offset);
1825254885Sdumbbell
1826254885Sdumbbell		switch (tv_info->ucTV_BootUpDefaultStandard) {
1827254885Sdumbbell		case ATOM_TV_NTSC:
1828254885Sdumbbell			tv_std = TV_STD_NTSC;
1829254885Sdumbbell			DRM_DEBUG_KMS("Default TV standard: NTSC\n");
1830254885Sdumbbell			break;
1831254885Sdumbbell		case ATOM_TV_NTSCJ:
1832254885Sdumbbell			tv_std = TV_STD_NTSC_J;
1833254885Sdumbbell			DRM_DEBUG_KMS("Default TV standard: NTSC-J\n");
1834254885Sdumbbell			break;
1835254885Sdumbbell		case ATOM_TV_PAL:
1836254885Sdumbbell			tv_std = TV_STD_PAL;
1837254885Sdumbbell			DRM_DEBUG_KMS("Default TV standard: PAL\n");
1838254885Sdumbbell			break;
1839254885Sdumbbell		case ATOM_TV_PALM:
1840254885Sdumbbell			tv_std = TV_STD_PAL_M;
1841254885Sdumbbell			DRM_DEBUG_KMS("Default TV standard: PAL-M\n");
1842254885Sdumbbell			break;
1843254885Sdumbbell		case ATOM_TV_PALN:
1844254885Sdumbbell			tv_std = TV_STD_PAL_N;
1845254885Sdumbbell			DRM_DEBUG_KMS("Default TV standard: PAL-N\n");
1846254885Sdumbbell			break;
1847254885Sdumbbell		case ATOM_TV_PALCN:
1848254885Sdumbbell			tv_std = TV_STD_PAL_CN;
1849254885Sdumbbell			DRM_DEBUG_KMS("Default TV standard: PAL-CN\n");
1850254885Sdumbbell			break;
1851254885Sdumbbell		case ATOM_TV_PAL60:
1852254885Sdumbbell			tv_std = TV_STD_PAL_60;
1853254885Sdumbbell			DRM_DEBUG_KMS("Default TV standard: PAL-60\n");
1854254885Sdumbbell			break;
1855254885Sdumbbell		case ATOM_TV_SECAM:
1856254885Sdumbbell			tv_std = TV_STD_SECAM;
1857254885Sdumbbell			DRM_DEBUG_KMS("Default TV standard: SECAM\n");
1858254885Sdumbbell			break;
1859254885Sdumbbell		default:
1860254885Sdumbbell			tv_std = TV_STD_NTSC;
1861254885Sdumbbell			DRM_DEBUG_KMS("Unknown TV standard; defaulting to NTSC\n");
1862254885Sdumbbell			break;
1863254885Sdumbbell		}
1864254885Sdumbbell	}
1865254885Sdumbbell	return tv_std;
1866254885Sdumbbell}
1867254885Sdumbbell
1868254885Sdumbbellstruct radeon_encoder_tv_dac *
1869254885Sdumbbellradeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
1870254885Sdumbbell{
1871254885Sdumbbell	struct drm_device *dev = encoder->base.dev;
1872254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
1873254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
1874254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, CompassionateData);
1875254885Sdumbbell	uint16_t data_offset;
1876254885Sdumbbell	struct _COMPASSIONATE_DATA *dac_info;
1877254885Sdumbbell	uint8_t frev, crev;
1878254885Sdumbbell	uint8_t bg, dac;
1879254885Sdumbbell	struct radeon_encoder_tv_dac *tv_dac = NULL;
1880254885Sdumbbell
1881254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1882254885Sdumbbell				   &frev, &crev, &data_offset)) {
1883254885Sdumbbell
1884254885Sdumbbell		dac_info = (struct _COMPASSIONATE_DATA *)
1885254885Sdumbbell			((char *)mode_info->atom_context->bios + data_offset);
1886254885Sdumbbell
1887254885Sdumbbell		tv_dac = malloc(sizeof(struct radeon_encoder_tv_dac),
1888282199Sdumbbell		    DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
1889254885Sdumbbell
1890254885Sdumbbell		if (!tv_dac)
1891254885Sdumbbell			return NULL;
1892254885Sdumbbell
1893254885Sdumbbell		bg = dac_info->ucDAC2_CRT2_BG_Adjustment;
1894254885Sdumbbell		dac = dac_info->ucDAC2_CRT2_DAC_Adjustment;
1895254885Sdumbbell		tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1896254885Sdumbbell
1897254885Sdumbbell		bg = dac_info->ucDAC2_PAL_BG_Adjustment;
1898254885Sdumbbell		dac = dac_info->ucDAC2_PAL_DAC_Adjustment;
1899254885Sdumbbell		tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20);
1900254885Sdumbbell
1901254885Sdumbbell		bg = dac_info->ucDAC2_NTSC_BG_Adjustment;
1902254885Sdumbbell		dac = dac_info->ucDAC2_NTSC_DAC_Adjustment;
1903254885Sdumbbell		tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
1904254885Sdumbbell
1905254885Sdumbbell		tv_dac->tv_std = radeon_atombios_get_tv_info(rdev);
1906254885Sdumbbell	}
1907254885Sdumbbell	return tv_dac;
1908254885Sdumbbell}
1909254885Sdumbbell
1910254885Sdumbbellstatic const char *thermal_controller_names[] = {
1911254885Sdumbbell	"NONE",
1912254885Sdumbbell	"lm63",
1913254885Sdumbbell	"adm1032",
1914254885Sdumbbell	"adm1030",
1915254885Sdumbbell	"max6649",
1916254885Sdumbbell	"lm64",
1917254885Sdumbbell	"f75375",
1918254885Sdumbbell	"asc7xxx",
1919254885Sdumbbell};
1920254885Sdumbbell
1921254885Sdumbbellstatic const char *pp_lib_thermal_controller_names[] = {
1922254885Sdumbbell	"NONE",
1923254885Sdumbbell	"lm63",
1924254885Sdumbbell	"adm1032",
1925254885Sdumbbell	"adm1030",
1926254885Sdumbbell	"max6649",
1927254885Sdumbbell	"lm64",
1928254885Sdumbbell	"f75375",
1929254885Sdumbbell	"RV6xx",
1930254885Sdumbbell	"RV770",
1931254885Sdumbbell	"adt7473",
1932254885Sdumbbell	"NONE",
1933254885Sdumbbell	"External GPIO",
1934254885Sdumbbell	"Evergreen",
1935254885Sdumbbell	"emc2103",
1936254885Sdumbbell	"Sumo",
1937254885Sdumbbell	"Northern Islands",
1938254885Sdumbbell	"Southern Islands",
1939254885Sdumbbell	"lm96163",
1940254885Sdumbbell};
1941254885Sdumbbell
1942254885Sdumbbellunion power_info {
1943254885Sdumbbell	struct _ATOM_POWERPLAY_INFO info;
1944254885Sdumbbell	struct _ATOM_POWERPLAY_INFO_V2 info_2;
1945254885Sdumbbell	struct _ATOM_POWERPLAY_INFO_V3 info_3;
1946254885Sdumbbell	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
1947254885Sdumbbell	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
1948254885Sdumbbell	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
1949254885Sdumbbell};
1950254885Sdumbbell
1951254885Sdumbbellunion pplib_clock_info {
1952254885Sdumbbell	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
1953254885Sdumbbell	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
1954254885Sdumbbell	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
1955254885Sdumbbell	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
1956254885Sdumbbell	struct _ATOM_PPLIB_SI_CLOCK_INFO si;
1957254885Sdumbbell};
1958254885Sdumbbell
1959254885Sdumbbellunion pplib_power_state {
1960254885Sdumbbell	struct _ATOM_PPLIB_STATE v1;
1961254885Sdumbbell	struct _ATOM_PPLIB_STATE_V2 v2;
1962254885Sdumbbell};
1963254885Sdumbbell
1964254885Sdumbbellstatic void radeon_atombios_parse_misc_flags_1_3(struct radeon_device *rdev,
1965254885Sdumbbell						 int state_index,
1966254885Sdumbbell						 u32 misc, u32 misc2)
1967254885Sdumbbell{
1968254885Sdumbbell	rdev->pm.power_state[state_index].misc = misc;
1969254885Sdumbbell	rdev->pm.power_state[state_index].misc2 = misc2;
1970254885Sdumbbell	/* order matters! */
1971254885Sdumbbell	if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
1972254885Sdumbbell		rdev->pm.power_state[state_index].type =
1973254885Sdumbbell			POWER_STATE_TYPE_POWERSAVE;
1974254885Sdumbbell	if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
1975254885Sdumbbell		rdev->pm.power_state[state_index].type =
1976254885Sdumbbell			POWER_STATE_TYPE_BATTERY;
1977254885Sdumbbell	if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
1978254885Sdumbbell		rdev->pm.power_state[state_index].type =
1979254885Sdumbbell			POWER_STATE_TYPE_BATTERY;
1980254885Sdumbbell	if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
1981254885Sdumbbell		rdev->pm.power_state[state_index].type =
1982254885Sdumbbell			POWER_STATE_TYPE_BALANCED;
1983254885Sdumbbell	if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
1984254885Sdumbbell		rdev->pm.power_state[state_index].type =
1985254885Sdumbbell			POWER_STATE_TYPE_PERFORMANCE;
1986254885Sdumbbell		rdev->pm.power_state[state_index].flags &=
1987254885Sdumbbell			~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
1988254885Sdumbbell	}
1989254885Sdumbbell	if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
1990254885Sdumbbell		rdev->pm.power_state[state_index].type =
1991254885Sdumbbell			POWER_STATE_TYPE_BALANCED;
1992254885Sdumbbell	if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
1993254885Sdumbbell		rdev->pm.power_state[state_index].type =
1994254885Sdumbbell			POWER_STATE_TYPE_DEFAULT;
1995254885Sdumbbell		rdev->pm.default_power_state_index = state_index;
1996254885Sdumbbell		rdev->pm.power_state[state_index].default_clock_mode =
1997254885Sdumbbell			&rdev->pm.power_state[state_index].clock_info[0];
1998254885Sdumbbell	} else if (state_index == 0) {
1999254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[0].flags |=
2000254885Sdumbbell			RADEON_PM_MODE_NO_DISPLAY;
2001254885Sdumbbell	}
2002254885Sdumbbell}
2003254885Sdumbbell
2004254885Sdumbbellstatic int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
2005254885Sdumbbell{
2006254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
2007254885Sdumbbell	u32 misc, misc2 = 0;
2008254885Sdumbbell	int num_modes = 0, i;
2009254885Sdumbbell	int state_index = 0;
2010254885Sdumbbell	struct radeon_i2c_bus_rec i2c_bus;
2011254885Sdumbbell	union power_info *power_info;
2012254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2013254885Sdumbbell        u16 data_offset;
2014254885Sdumbbell	u8 frev, crev;
2015254885Sdumbbell
2016254885Sdumbbell	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
2017254885Sdumbbell				   &frev, &crev, &data_offset))
2018254885Sdumbbell		return state_index;
2019254885Sdumbbell	power_info = (union power_info *)((char *)mode_info->atom_context->bios + data_offset);
2020254885Sdumbbell
2021254885Sdumbbell	/* add the i2c bus for thermal/fan chip */
2022254885Sdumbbell	if ((power_info->info.ucOverdriveThermalController > 0) &&
2023282199Sdumbbell	    (power_info->info.ucOverdriveThermalController < ARRAY_SIZE(thermal_controller_names))) {
2024254885Sdumbbell		DRM_INFO("Possible %s thermal controller at 0x%02x\n",
2025254885Sdumbbell			 thermal_controller_names[power_info->info.ucOverdriveThermalController],
2026254885Sdumbbell			 power_info->info.ucOverdriveControllerAddress >> 1);
2027254885Sdumbbell		i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
2028254885Sdumbbell		rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
2029282199Sdumbbell#ifdef FREEBSD_WIP
2030254885Sdumbbell		if (rdev->pm.i2c_bus) {
2031254885Sdumbbell			struct i2c_board_info info = { };
2032254885Sdumbbell			const char *name = thermal_controller_names[power_info->info.
2033254885Sdumbbell								    ucOverdriveThermalController];
2034254885Sdumbbell			info.addr = power_info->info.ucOverdriveControllerAddress >> 1;
2035254885Sdumbbell			strlcpy(info.type, name, sizeof(info.type));
2036254885Sdumbbell			i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
2037254885Sdumbbell		}
2038282199Sdumbbell#endif /* FREEBSD_WIP */
2039254885Sdumbbell	}
2040254885Sdumbbell	num_modes = power_info->info.ucNumOfPowerModeEntries;
2041254885Sdumbbell	if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
2042254885Sdumbbell		num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
2043282199Sdumbbell	if (num_modes == 0)
2044282199Sdumbbell		return state_index;
2045254885Sdumbbell	rdev->pm.power_state = malloc(sizeof(struct radeon_power_state) * num_modes,
2046282199Sdumbbell	    DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
2047254885Sdumbbell	if (!rdev->pm.power_state)
2048254885Sdumbbell		return state_index;
2049254885Sdumbbell	/* last mode is usually default, array is low to high */
2050254885Sdumbbell	for (i = 0; i < num_modes; i++) {
2051254885Sdumbbell		rdev->pm.power_state[state_index].clock_info =
2052254885Sdumbbell			malloc(sizeof(struct radeon_pm_clock_info) * 1,
2053282199Sdumbbell			    DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
2054254885Sdumbbell		if (!rdev->pm.power_state[state_index].clock_info)
2055254885Sdumbbell			return state_index;
2056254885Sdumbbell		rdev->pm.power_state[state_index].num_clock_modes = 1;
2057254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
2058254885Sdumbbell		switch (frev) {
2059254885Sdumbbell		case 1:
2060254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].mclk =
2061254885Sdumbbell				le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock);
2062254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].sclk =
2063254885Sdumbbell				le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock);
2064254885Sdumbbell			/* skip invalid modes */
2065254885Sdumbbell			if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
2066254885Sdumbbell			    (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
2067254885Sdumbbell				continue;
2068254885Sdumbbell			rdev->pm.power_state[state_index].pcie_lanes =
2069254885Sdumbbell				power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
2070254885Sdumbbell			misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
2071254885Sdumbbell			if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
2072254885Sdumbbell			    (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
2073254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2074254885Sdumbbell					VOLTAGE_GPIO;
2075254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
2076254885Sdumbbell					radeon_lookup_gpio(rdev,
2077254885Sdumbbell							   power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
2078254885Sdumbbell				if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
2079254885Sdumbbell					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2080254885Sdumbbell						true;
2081254885Sdumbbell				else
2082254885Sdumbbell					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2083254885Sdumbbell						false;
2084254885Sdumbbell			} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
2085254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2086254885Sdumbbell					VOLTAGE_VDDC;
2087254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
2088254885Sdumbbell					power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
2089254885Sdumbbell			}
2090254885Sdumbbell			rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2091254885Sdumbbell			radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0);
2092254885Sdumbbell			state_index++;
2093254885Sdumbbell			break;
2094254885Sdumbbell		case 2:
2095254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].mclk =
2096254885Sdumbbell				le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
2097254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].sclk =
2098254885Sdumbbell				le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock);
2099254885Sdumbbell			/* skip invalid modes */
2100254885Sdumbbell			if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
2101254885Sdumbbell			    (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
2102254885Sdumbbell				continue;
2103254885Sdumbbell			rdev->pm.power_state[state_index].pcie_lanes =
2104254885Sdumbbell				power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
2105254885Sdumbbell			misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
2106254885Sdumbbell			misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
2107254885Sdumbbell			if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
2108254885Sdumbbell			    (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
2109254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2110254885Sdumbbell					VOLTAGE_GPIO;
2111254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
2112254885Sdumbbell					radeon_lookup_gpio(rdev,
2113254885Sdumbbell							   power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
2114254885Sdumbbell				if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
2115254885Sdumbbell					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2116254885Sdumbbell						true;
2117254885Sdumbbell				else
2118254885Sdumbbell					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2119254885Sdumbbell						false;
2120254885Sdumbbell			} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
2121254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2122254885Sdumbbell					VOLTAGE_VDDC;
2123254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
2124254885Sdumbbell					power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
2125254885Sdumbbell			}
2126254885Sdumbbell			rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2127254885Sdumbbell			radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
2128254885Sdumbbell			state_index++;
2129254885Sdumbbell			break;
2130254885Sdumbbell		case 3:
2131254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].mclk =
2132254885Sdumbbell				le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
2133254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].sclk =
2134254885Sdumbbell				le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock);
2135254885Sdumbbell			/* skip invalid modes */
2136254885Sdumbbell			if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
2137254885Sdumbbell			    (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
2138254885Sdumbbell				continue;
2139254885Sdumbbell			rdev->pm.power_state[state_index].pcie_lanes =
2140254885Sdumbbell				power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
2141254885Sdumbbell			misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
2142254885Sdumbbell			misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2);
2143254885Sdumbbell			if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
2144254885Sdumbbell			    (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
2145254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2146254885Sdumbbell					VOLTAGE_GPIO;
2147254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
2148254885Sdumbbell					radeon_lookup_gpio(rdev,
2149254885Sdumbbell							   power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
2150254885Sdumbbell				if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
2151254885Sdumbbell					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2152254885Sdumbbell						true;
2153254885Sdumbbell				else
2154254885Sdumbbell					rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2155254885Sdumbbell						false;
2156254885Sdumbbell			} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
2157254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2158254885Sdumbbell					VOLTAGE_VDDC;
2159254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
2160254885Sdumbbell					power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex;
2161254885Sdumbbell				if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) {
2162254885Sdumbbell					rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled =
2163254885Sdumbbell						true;
2164254885Sdumbbell					rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id =
2165254885Sdumbbell						power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
2166254885Sdumbbell				}
2167254885Sdumbbell			}
2168254885Sdumbbell			rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2169254885Sdumbbell			radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
2170254885Sdumbbell			state_index++;
2171254885Sdumbbell			break;
2172254885Sdumbbell		}
2173254885Sdumbbell	}
2174254885Sdumbbell	/* last mode is usually default */
2175254885Sdumbbell	if (rdev->pm.default_power_state_index == -1) {
2176254885Sdumbbell		rdev->pm.power_state[state_index - 1].type =
2177254885Sdumbbell			POWER_STATE_TYPE_DEFAULT;
2178254885Sdumbbell		rdev->pm.default_power_state_index = state_index - 1;
2179254885Sdumbbell		rdev->pm.power_state[state_index - 1].default_clock_mode =
2180254885Sdumbbell			&rdev->pm.power_state[state_index - 1].clock_info[0];
2181254885Sdumbbell		rdev->pm.power_state[state_index].flags &=
2182254885Sdumbbell			~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2183254885Sdumbbell		rdev->pm.power_state[state_index].misc = 0;
2184254885Sdumbbell		rdev->pm.power_state[state_index].misc2 = 0;
2185254885Sdumbbell	}
2186254885Sdumbbell	return state_index;
2187254885Sdumbbell}
2188254885Sdumbbell
2189254885Sdumbbellstatic void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *rdev,
2190254885Sdumbbell							 ATOM_PPLIB_THERMALCONTROLLER *controller)
2191254885Sdumbbell{
2192254885Sdumbbell	struct radeon_i2c_bus_rec i2c_bus;
2193254885Sdumbbell
2194254885Sdumbbell	/* add the i2c bus for thermal/fan chip */
2195254885Sdumbbell	if (controller->ucType > 0) {
2196254885Sdumbbell		if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
2197254885Sdumbbell			DRM_INFO("Internal thermal controller %s fan control\n",
2198254885Sdumbbell				 (controller->ucFanParameters &
2199254885Sdumbbell				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2200254885Sdumbbell			rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
2201254885Sdumbbell		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
2202254885Sdumbbell			DRM_INFO("Internal thermal controller %s fan control\n",
2203254885Sdumbbell				 (controller->ucFanParameters &
2204254885Sdumbbell				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2205254885Sdumbbell			rdev->pm.int_thermal_type = THERMAL_TYPE_RV770;
2206254885Sdumbbell		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
2207254885Sdumbbell			DRM_INFO("Internal thermal controller %s fan control\n",
2208254885Sdumbbell				 (controller->ucFanParameters &
2209254885Sdumbbell				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2210254885Sdumbbell			rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
2211254885Sdumbbell		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
2212254885Sdumbbell			DRM_INFO("Internal thermal controller %s fan control\n",
2213254885Sdumbbell				 (controller->ucFanParameters &
2214254885Sdumbbell				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2215254885Sdumbbell			rdev->pm.int_thermal_type = THERMAL_TYPE_SUMO;
2216254885Sdumbbell		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
2217254885Sdumbbell			DRM_INFO("Internal thermal controller %s fan control\n",
2218254885Sdumbbell				 (controller->ucFanParameters &
2219254885Sdumbbell				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2220254885Sdumbbell			rdev->pm.int_thermal_type = THERMAL_TYPE_NI;
2221254885Sdumbbell		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
2222254885Sdumbbell			DRM_INFO("Internal thermal controller %s fan control\n",
2223254885Sdumbbell				 (controller->ucFanParameters &
2224254885Sdumbbell				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2225254885Sdumbbell			rdev->pm.int_thermal_type = THERMAL_TYPE_SI;
2226254885Sdumbbell		} else if ((controller->ucType ==
2227254885Sdumbbell			    ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
2228254885Sdumbbell			   (controller->ucType ==
2229254885Sdumbbell			    ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) ||
2230254885Sdumbbell			   (controller->ucType ==
2231254885Sdumbbell			    ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) {
2232254885Sdumbbell			DRM_INFO("Special thermal controller config\n");
2233282199Sdumbbell		} else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
2234254885Sdumbbell			DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
2235254885Sdumbbell				 pp_lib_thermal_controller_names[controller->ucType],
2236254885Sdumbbell				 controller->ucI2cAddress >> 1,
2237254885Sdumbbell				 (controller->ucFanParameters &
2238254885Sdumbbell				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2239254885Sdumbbell			i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
2240254885Sdumbbell			rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
2241282199Sdumbbell#ifdef FREEBSD_WIP
2242254885Sdumbbell			if (rdev->pm.i2c_bus) {
2243254885Sdumbbell				struct i2c_board_info info = { };
2244254885Sdumbbell				const char *name = pp_lib_thermal_controller_names[controller->ucType];
2245254885Sdumbbell				info.addr = controller->ucI2cAddress >> 1;
2246254885Sdumbbell				strlcpy(info.type, name, sizeof(info.type));
2247254885Sdumbbell				i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
2248254885Sdumbbell			}
2249282199Sdumbbell#endif /* FREEBSD_WIP */
2250254885Sdumbbell		} else {
2251254885Sdumbbell			DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n",
2252254885Sdumbbell				 controller->ucType,
2253254885Sdumbbell				 controller->ucI2cAddress >> 1,
2254254885Sdumbbell				 (controller->ucFanParameters &
2255254885Sdumbbell				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2256254885Sdumbbell		}
2257254885Sdumbbell	}
2258254885Sdumbbell}
2259254885Sdumbbell
2260254885Sdumbbellstatic void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
2261254885Sdumbbell						 u16 *vddc, u16 *vddci)
2262254885Sdumbbell{
2263254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
2264254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
2265254885Sdumbbell	u8 frev, crev;
2266254885Sdumbbell	u16 data_offset;
2267254885Sdumbbell	union firmware_info *firmware_info;
2268254885Sdumbbell
2269254885Sdumbbell	*vddc = 0;
2270254885Sdumbbell	*vddci = 0;
2271254885Sdumbbell
2272254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
2273254885Sdumbbell				   &frev, &crev, &data_offset)) {
2274254885Sdumbbell		firmware_info =
2275254885Sdumbbell			(union firmware_info *)((char *)mode_info->atom_context->bios +
2276254885Sdumbbell						data_offset);
2277254885Sdumbbell		*vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
2278254885Sdumbbell		if ((frev == 2) && (crev >= 2))
2279254885Sdumbbell			*vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);
2280254885Sdumbbell	}
2281254885Sdumbbell}
2282254885Sdumbbell
2283254885Sdumbbellstatic void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev,
2284254885Sdumbbell						       int state_index, int mode_index,
2285254885Sdumbbell						       struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info)
2286254885Sdumbbell{
2287254885Sdumbbell	int j;
2288254885Sdumbbell	u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
2289254885Sdumbbell	u32 misc2 = le16_to_cpu(non_clock_info->usClassification);
2290254885Sdumbbell	u16 vddc, vddci;
2291254885Sdumbbell
2292254885Sdumbbell	radeon_atombios_get_default_voltages(rdev, &vddc, &vddci);
2293254885Sdumbbell
2294254885Sdumbbell	rdev->pm.power_state[state_index].misc = misc;
2295254885Sdumbbell	rdev->pm.power_state[state_index].misc2 = misc2;
2296254885Sdumbbell	rdev->pm.power_state[state_index].pcie_lanes =
2297254885Sdumbbell		((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
2298254885Sdumbbell		 ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
2299254885Sdumbbell	switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
2300254885Sdumbbell	case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
2301254885Sdumbbell		rdev->pm.power_state[state_index].type =
2302254885Sdumbbell			POWER_STATE_TYPE_BATTERY;
2303254885Sdumbbell		break;
2304254885Sdumbbell	case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
2305254885Sdumbbell		rdev->pm.power_state[state_index].type =
2306254885Sdumbbell			POWER_STATE_TYPE_BALANCED;
2307254885Sdumbbell		break;
2308254885Sdumbbell	case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
2309254885Sdumbbell		rdev->pm.power_state[state_index].type =
2310254885Sdumbbell			POWER_STATE_TYPE_PERFORMANCE;
2311254885Sdumbbell		break;
2312254885Sdumbbell	case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
2313254885Sdumbbell		if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
2314254885Sdumbbell			rdev->pm.power_state[state_index].type =
2315254885Sdumbbell				POWER_STATE_TYPE_PERFORMANCE;
2316254885Sdumbbell		break;
2317254885Sdumbbell	}
2318254885Sdumbbell	rdev->pm.power_state[state_index].flags = 0;
2319254885Sdumbbell	if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
2320254885Sdumbbell		rdev->pm.power_state[state_index].flags |=
2321254885Sdumbbell			RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2322254885Sdumbbell	if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
2323254885Sdumbbell		rdev->pm.power_state[state_index].type =
2324254885Sdumbbell			POWER_STATE_TYPE_DEFAULT;
2325254885Sdumbbell		rdev->pm.default_power_state_index = state_index;
2326254885Sdumbbell		rdev->pm.power_state[state_index].default_clock_mode =
2327254885Sdumbbell			&rdev->pm.power_state[state_index].clock_info[mode_index - 1];
2328254885Sdumbbell		if (ASIC_IS_DCE5(rdev) && !(rdev->flags & RADEON_IS_IGP)) {
2329254885Sdumbbell			/* NI chips post without MC ucode, so default clocks are strobe mode only */
2330254885Sdumbbell			rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk;
2331254885Sdumbbell			rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk;
2332254885Sdumbbell			rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage;
2333254885Sdumbbell			rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci;
2334254885Sdumbbell		} else {
2335254885Sdumbbell			/* patch the table values with the default slck/mclk from firmware info */
2336254885Sdumbbell			for (j = 0; j < mode_index; j++) {
2337254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[j].mclk =
2338254885Sdumbbell					rdev->clock.default_mclk;
2339254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[j].sclk =
2340254885Sdumbbell					rdev->clock.default_sclk;
2341254885Sdumbbell				if (vddc)
2342254885Sdumbbell					rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
2343254885Sdumbbell						vddc;
2344254885Sdumbbell			}
2345254885Sdumbbell		}
2346254885Sdumbbell	}
2347254885Sdumbbell}
2348254885Sdumbbell
2349254885Sdumbbellstatic bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
2350254885Sdumbbell						   int state_index, int mode_index,
2351254885Sdumbbell						   union pplib_clock_info *clock_info)
2352254885Sdumbbell{
2353254885Sdumbbell	u32 sclk, mclk;
2354254885Sdumbbell	u16 vddc;
2355254885Sdumbbell
2356254885Sdumbbell	if (rdev->flags & RADEON_IS_IGP) {
2357254885Sdumbbell		if (rdev->family >= CHIP_PALM) {
2358254885Sdumbbell			sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
2359254885Sdumbbell			sclk |= clock_info->sumo.ucEngineClockHigh << 16;
2360254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2361254885Sdumbbell		} else {
2362254885Sdumbbell			sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
2363254885Sdumbbell			sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
2364254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2365254885Sdumbbell		}
2366254885Sdumbbell	} else if (ASIC_IS_DCE6(rdev)) {
2367254885Sdumbbell		sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
2368254885Sdumbbell		sclk |= clock_info->si.ucEngineClockHigh << 16;
2369254885Sdumbbell		mclk = le16_to_cpu(clock_info->si.usMemoryClockLow);
2370254885Sdumbbell		mclk |= clock_info->si.ucMemoryClockHigh << 16;
2371254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2372254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2373254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2374254885Sdumbbell			VOLTAGE_SW;
2375254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
2376254885Sdumbbell			le16_to_cpu(clock_info->si.usVDDC);
2377254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
2378254885Sdumbbell			le16_to_cpu(clock_info->si.usVDDCI);
2379254885Sdumbbell	} else if (ASIC_IS_DCE4(rdev)) {
2380254885Sdumbbell		sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
2381254885Sdumbbell		sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
2382254885Sdumbbell		mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
2383254885Sdumbbell		mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
2384254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2385254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2386254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2387254885Sdumbbell			VOLTAGE_SW;
2388254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
2389254885Sdumbbell			le16_to_cpu(clock_info->evergreen.usVDDC);
2390254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
2391254885Sdumbbell			le16_to_cpu(clock_info->evergreen.usVDDCI);
2392254885Sdumbbell	} else {
2393254885Sdumbbell		sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
2394254885Sdumbbell		sclk |= clock_info->r600.ucEngineClockHigh << 16;
2395254885Sdumbbell		mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
2396254885Sdumbbell		mclk |= clock_info->r600.ucMemoryClockHigh << 16;
2397254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2398254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2399254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2400254885Sdumbbell			VOLTAGE_SW;
2401254885Sdumbbell		rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
2402254885Sdumbbell			le16_to_cpu(clock_info->r600.usVDDC);
2403254885Sdumbbell	}
2404254885Sdumbbell
2405254885Sdumbbell	/* patch up vddc if necessary */
2406254885Sdumbbell	switch (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage) {
2407254885Sdumbbell	case ATOM_VIRTUAL_VOLTAGE_ID0:
2408254885Sdumbbell	case ATOM_VIRTUAL_VOLTAGE_ID1:
2409254885Sdumbbell	case ATOM_VIRTUAL_VOLTAGE_ID2:
2410254885Sdumbbell	case ATOM_VIRTUAL_VOLTAGE_ID3:
2411254885Sdumbbell		if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC,
2412254885Sdumbbell					     rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage,
2413254885Sdumbbell					     &vddc) == 0)
2414254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = vddc;
2415254885Sdumbbell		break;
2416254885Sdumbbell	default:
2417254885Sdumbbell		break;
2418254885Sdumbbell	}
2419254885Sdumbbell
2420254885Sdumbbell	if (rdev->flags & RADEON_IS_IGP) {
2421254885Sdumbbell		/* skip invalid modes */
2422254885Sdumbbell		if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
2423254885Sdumbbell			return false;
2424254885Sdumbbell	} else {
2425254885Sdumbbell		/* skip invalid modes */
2426254885Sdumbbell		if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
2427254885Sdumbbell		    (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
2428254885Sdumbbell			return false;
2429254885Sdumbbell	}
2430254885Sdumbbell	return true;
2431254885Sdumbbell}
2432254885Sdumbbell
2433254885Sdumbbellstatic int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev)
2434254885Sdumbbell{
2435254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
2436254885Sdumbbell	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
2437254885Sdumbbell	union pplib_power_state *power_state;
2438254885Sdumbbell	int i, j;
2439254885Sdumbbell	int state_index = 0, mode_index = 0;
2440254885Sdumbbell	union pplib_clock_info *clock_info;
2441254885Sdumbbell	bool valid;
2442254885Sdumbbell	union power_info *power_info;
2443254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2444254885Sdumbbell        u16 data_offset;
2445254885Sdumbbell	u8 frev, crev;
2446254885Sdumbbell
2447254885Sdumbbell	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
2448254885Sdumbbell				   &frev, &crev, &data_offset))
2449254885Sdumbbell		return state_index;
2450254885Sdumbbell	power_info = (union power_info *)((char *)mode_info->atom_context->bios + data_offset);
2451254885Sdumbbell
2452254885Sdumbbell	radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
2453282199Sdumbbell	if (power_info->pplib.ucNumStates == 0)
2454282199Sdumbbell		return state_index;
2455254885Sdumbbell	rdev->pm.power_state = malloc(sizeof(struct radeon_power_state) *
2456254885Sdumbbell				       power_info->pplib.ucNumStates,
2457282199Sdumbbell				       DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
2458254885Sdumbbell	if (!rdev->pm.power_state)
2459254885Sdumbbell		return state_index;
2460254885Sdumbbell	/* first mode is usually default, followed by low to high */
2461254885Sdumbbell	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
2462254885Sdumbbell		mode_index = 0;
2463254885Sdumbbell		power_state = (union pplib_power_state *)
2464254885Sdumbbell			((char *)mode_info->atom_context->bios + data_offset +
2465254885Sdumbbell			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
2466254885Sdumbbell			 i * power_info->pplib.ucStateEntrySize);
2467254885Sdumbbell		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
2468254885Sdumbbell			((char *)mode_info->atom_context->bios + data_offset +
2469254885Sdumbbell			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
2470254885Sdumbbell			 (power_state->v1.ucNonClockStateIndex *
2471254885Sdumbbell			  power_info->pplib.ucNonClockSize));
2472254885Sdumbbell		rdev->pm.power_state[i].clock_info = malloc(sizeof(struct radeon_pm_clock_info) *
2473254885Sdumbbell							     ((power_info->pplib.ucStateEntrySize - 1) ?
2474254885Sdumbbell							      (power_info->pplib.ucStateEntrySize - 1) : 1),
2475282199Sdumbbell							     DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
2476254885Sdumbbell		if (!rdev->pm.power_state[i].clock_info)
2477254885Sdumbbell			return state_index;
2478254885Sdumbbell		if (power_info->pplib.ucStateEntrySize - 1) {
2479254885Sdumbbell			for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
2480254885Sdumbbell				clock_info = (union pplib_clock_info *)
2481254885Sdumbbell					((char *)mode_info->atom_context->bios + data_offset +
2482254885Sdumbbell					 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
2483254885Sdumbbell					 (power_state->v1.ucClockStateIndices[j] *
2484254885Sdumbbell					  power_info->pplib.ucClockInfoSize));
2485254885Sdumbbell				valid = radeon_atombios_parse_pplib_clock_info(rdev,
2486254885Sdumbbell									       state_index, mode_index,
2487254885Sdumbbell									       clock_info);
2488254885Sdumbbell				if (valid)
2489254885Sdumbbell					mode_index++;
2490254885Sdumbbell			}
2491254885Sdumbbell		} else {
2492254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].mclk =
2493254885Sdumbbell				rdev->clock.default_mclk;
2494254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].sclk =
2495254885Sdumbbell				rdev->clock.default_sclk;
2496254885Sdumbbell			mode_index++;
2497254885Sdumbbell		}
2498254885Sdumbbell		rdev->pm.power_state[state_index].num_clock_modes = mode_index;
2499254885Sdumbbell		if (mode_index) {
2500254885Sdumbbell			radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
2501254885Sdumbbell								   non_clock_info);
2502254885Sdumbbell			state_index++;
2503254885Sdumbbell		}
2504254885Sdumbbell	}
2505254885Sdumbbell	/* if multiple clock modes, mark the lowest as no display */
2506254885Sdumbbell	for (i = 0; i < state_index; i++) {
2507254885Sdumbbell		if (rdev->pm.power_state[i].num_clock_modes > 1)
2508254885Sdumbbell			rdev->pm.power_state[i].clock_info[0].flags |=
2509254885Sdumbbell				RADEON_PM_MODE_NO_DISPLAY;
2510254885Sdumbbell	}
2511254885Sdumbbell	/* first mode is usually default */
2512254885Sdumbbell	if (rdev->pm.default_power_state_index == -1) {
2513254885Sdumbbell		rdev->pm.power_state[0].type =
2514254885Sdumbbell			POWER_STATE_TYPE_DEFAULT;
2515254885Sdumbbell		rdev->pm.default_power_state_index = 0;
2516254885Sdumbbell		rdev->pm.power_state[0].default_clock_mode =
2517254885Sdumbbell			&rdev->pm.power_state[0].clock_info[0];
2518254885Sdumbbell	}
2519254885Sdumbbell	return state_index;
2520254885Sdumbbell}
2521254885Sdumbbell
2522254885Sdumbbellstatic int radeon_atombios_parse_power_table_6(struct radeon_device *rdev)
2523254885Sdumbbell{
2524254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
2525254885Sdumbbell	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
2526254885Sdumbbell	union pplib_power_state *power_state;
2527254885Sdumbbell	int i, j, non_clock_array_index, clock_array_index;
2528254885Sdumbbell	int state_index = 0, mode_index = 0;
2529254885Sdumbbell	union pplib_clock_info *clock_info;
2530254885Sdumbbell	struct _StateArray *state_array;
2531254885Sdumbbell	struct _ClockInfoArray *clock_info_array;
2532254885Sdumbbell	struct _NonClockInfoArray *non_clock_info_array;
2533254885Sdumbbell	bool valid;
2534254885Sdumbbell	union power_info *power_info;
2535254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2536254885Sdumbbell        u16 data_offset;
2537254885Sdumbbell	u8 frev, crev;
2538282199Sdumbbell	u8 *power_state_offset;
2539254885Sdumbbell
2540254885Sdumbbell	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
2541254885Sdumbbell				   &frev, &crev, &data_offset))
2542254885Sdumbbell		return state_index;
2543254885Sdumbbell	power_info = (union power_info *)((char *)mode_info->atom_context->bios + data_offset);
2544254885Sdumbbell
2545254885Sdumbbell	radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
2546254885Sdumbbell	state_array = (struct _StateArray *)
2547254885Sdumbbell		((char *)mode_info->atom_context->bios + data_offset +
2548254885Sdumbbell		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
2549254885Sdumbbell	clock_info_array = (struct _ClockInfoArray *)
2550254885Sdumbbell		((char *)mode_info->atom_context->bios + data_offset +
2551254885Sdumbbell		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
2552254885Sdumbbell	non_clock_info_array = (struct _NonClockInfoArray *)
2553254885Sdumbbell		((char *)mode_info->atom_context->bios + data_offset +
2554254885Sdumbbell		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
2555282199Sdumbbell	if (state_array->ucNumEntries == 0)
2556282199Sdumbbell		return state_index;
2557254885Sdumbbell	rdev->pm.power_state = malloc(sizeof(struct radeon_power_state) *
2558254885Sdumbbell				       state_array->ucNumEntries,
2559282199Sdumbbell				       DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
2560254885Sdumbbell	if (!rdev->pm.power_state)
2561254885Sdumbbell		return state_index;
2562282199Sdumbbell	power_state_offset = (u8 *)state_array->states;
2563254885Sdumbbell	for (i = 0; i < state_array->ucNumEntries; i++) {
2564254885Sdumbbell		mode_index = 0;
2565282199Sdumbbell		power_state = (union pplib_power_state *)power_state_offset;
2566282199Sdumbbell		non_clock_array_index = power_state->v2.nonClockInfoIndex;
2567254885Sdumbbell		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
2568254885Sdumbbell			&non_clock_info_array->nonClockInfo[non_clock_array_index];
2569254885Sdumbbell		rdev->pm.power_state[i].clock_info = malloc(sizeof(struct radeon_pm_clock_info) *
2570254885Sdumbbell							     (power_state->v2.ucNumDPMLevels ?
2571254885Sdumbbell							      power_state->v2.ucNumDPMLevels : 1),
2572282199Sdumbbell							     DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
2573254885Sdumbbell		if (!rdev->pm.power_state[i].clock_info)
2574254885Sdumbbell			return state_index;
2575254885Sdumbbell		if (power_state->v2.ucNumDPMLevels) {
2576254885Sdumbbell			for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
2577254885Sdumbbell				clock_array_index = power_state->v2.clockInfoIndex[j];
2578254885Sdumbbell				clock_info = (union pplib_clock_info *)
2579254885Sdumbbell					&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
2580254885Sdumbbell				valid = radeon_atombios_parse_pplib_clock_info(rdev,
2581254885Sdumbbell									       state_index, mode_index,
2582254885Sdumbbell									       clock_info);
2583254885Sdumbbell				if (valid)
2584254885Sdumbbell					mode_index++;
2585254885Sdumbbell			}
2586254885Sdumbbell		} else {
2587254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].mclk =
2588254885Sdumbbell				rdev->clock.default_mclk;
2589254885Sdumbbell			rdev->pm.power_state[state_index].clock_info[0].sclk =
2590254885Sdumbbell				rdev->clock.default_sclk;
2591254885Sdumbbell			mode_index++;
2592254885Sdumbbell		}
2593254885Sdumbbell		rdev->pm.power_state[state_index].num_clock_modes = mode_index;
2594254885Sdumbbell		if (mode_index) {
2595254885Sdumbbell			radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
2596254885Sdumbbell								   non_clock_info);
2597254885Sdumbbell			state_index++;
2598254885Sdumbbell		}
2599282199Sdumbbell		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
2600254885Sdumbbell	}
2601254885Sdumbbell	/* if multiple clock modes, mark the lowest as no display */
2602254885Sdumbbell	for (i = 0; i < state_index; i++) {
2603254885Sdumbbell		if (rdev->pm.power_state[i].num_clock_modes > 1)
2604254885Sdumbbell			rdev->pm.power_state[i].clock_info[0].flags |=
2605254885Sdumbbell				RADEON_PM_MODE_NO_DISPLAY;
2606254885Sdumbbell	}
2607254885Sdumbbell	/* first mode is usually default */
2608254885Sdumbbell	if (rdev->pm.default_power_state_index == -1) {
2609254885Sdumbbell		rdev->pm.power_state[0].type =
2610254885Sdumbbell			POWER_STATE_TYPE_DEFAULT;
2611254885Sdumbbell		rdev->pm.default_power_state_index = 0;
2612254885Sdumbbell		rdev->pm.power_state[0].default_clock_mode =
2613254885Sdumbbell			&rdev->pm.power_state[0].clock_info[0];
2614254885Sdumbbell	}
2615254885Sdumbbell	return state_index;
2616254885Sdumbbell}
2617254885Sdumbbell
2618254885Sdumbbellvoid radeon_atombios_get_power_modes(struct radeon_device *rdev)
2619254885Sdumbbell{
2620254885Sdumbbell	struct radeon_mode_info *mode_info = &rdev->mode_info;
2621254885Sdumbbell	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2622254885Sdumbbell	u16 data_offset;
2623254885Sdumbbell	u8 frev, crev;
2624254885Sdumbbell	int state_index = 0;
2625254885Sdumbbell
2626254885Sdumbbell	rdev->pm.default_power_state_index = -1;
2627254885Sdumbbell
2628254885Sdumbbell	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
2629254885Sdumbbell				   &frev, &crev, &data_offset)) {
2630254885Sdumbbell		switch (frev) {
2631254885Sdumbbell		case 1:
2632254885Sdumbbell		case 2:
2633254885Sdumbbell		case 3:
2634254885Sdumbbell			state_index = radeon_atombios_parse_power_table_1_3(rdev);
2635254885Sdumbbell			break;
2636254885Sdumbbell		case 4:
2637254885Sdumbbell		case 5:
2638254885Sdumbbell			state_index = radeon_atombios_parse_power_table_4_5(rdev);
2639254885Sdumbbell			break;
2640254885Sdumbbell		case 6:
2641254885Sdumbbell			state_index = radeon_atombios_parse_power_table_6(rdev);
2642254885Sdumbbell			break;
2643254885Sdumbbell		default:
2644254885Sdumbbell			break;
2645254885Sdumbbell		}
2646282199Sdumbbell	}
2647282199Sdumbbell
2648282199Sdumbbell	if (state_index == 0) {
2649254885Sdumbbell		rdev->pm.power_state = malloc(sizeof(struct radeon_power_state),
2650282199Sdumbbell		    DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
2651254885Sdumbbell		if (rdev->pm.power_state) {
2652254885Sdumbbell			rdev->pm.power_state[0].clock_info =
2653254885Sdumbbell				malloc(sizeof(struct radeon_pm_clock_info) * 1,
2654282199Sdumbbell				    DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
2655254885Sdumbbell			if (rdev->pm.power_state[0].clock_info) {
2656254885Sdumbbell				/* add the default mode */
2657254885Sdumbbell				rdev->pm.power_state[state_index].type =
2658254885Sdumbbell					POWER_STATE_TYPE_DEFAULT;
2659254885Sdumbbell				rdev->pm.power_state[state_index].num_clock_modes = 1;
2660254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
2661254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
2662254885Sdumbbell				rdev->pm.power_state[state_index].default_clock_mode =
2663254885Sdumbbell					&rdev->pm.power_state[state_index].clock_info[0];
2664254885Sdumbbell				rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
2665254885Sdumbbell				rdev->pm.power_state[state_index].pcie_lanes = 16;
2666254885Sdumbbell				rdev->pm.default_power_state_index = state_index;
2667254885Sdumbbell				rdev->pm.power_state[state_index].flags = 0;
2668254885Sdumbbell				state_index++;
2669254885Sdumbbell			}
2670254885Sdumbbell		}
2671254885Sdumbbell	}
2672254885Sdumbbell
2673254885Sdumbbell	rdev->pm.num_power_states = state_index;
2674254885Sdumbbell
2675254885Sdumbbell	rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
2676254885Sdumbbell	rdev->pm.current_clock_mode_index = 0;
2677254885Sdumbbell	if (rdev->pm.default_power_state_index >= 0)
2678254885Sdumbbell		rdev->pm.current_vddc =
2679254885Sdumbbell			rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
2680254885Sdumbbell	else
2681254885Sdumbbell		rdev->pm.current_vddc = 0;
2682254885Sdumbbell}
2683254885Sdumbbell
2684254885Sdumbbellvoid radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
2685254885Sdumbbell{
2686254885Sdumbbell	DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
2687254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
2688254885Sdumbbell
2689254885Sdumbbell	args.ucEnable = enable;
2690254885Sdumbbell
2691254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2692254885Sdumbbell}
2693254885Sdumbbell
2694254885Sdumbbelluint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev)
2695254885Sdumbbell{
2696254885Sdumbbell	GET_ENGINE_CLOCK_PS_ALLOCATION args;
2697254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock);
2698254885Sdumbbell
2699254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2700254885Sdumbbell	return le32_to_cpu(args.ulReturnEngineClock);
2701254885Sdumbbell}
2702254885Sdumbbell
2703254885Sdumbbelluint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev)
2704254885Sdumbbell{
2705254885Sdumbbell	GET_MEMORY_CLOCK_PS_ALLOCATION args;
2706254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock);
2707254885Sdumbbell
2708254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2709254885Sdumbbell	return le32_to_cpu(args.ulReturnMemoryClock);
2710254885Sdumbbell}
2711254885Sdumbbell
2712254885Sdumbbellvoid radeon_atom_set_engine_clock(struct radeon_device *rdev,
2713254885Sdumbbell				  uint32_t eng_clock)
2714254885Sdumbbell{
2715254885Sdumbbell	SET_ENGINE_CLOCK_PS_ALLOCATION args;
2716254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
2717254885Sdumbbell
2718254885Sdumbbell	args.ulTargetEngineClock = cpu_to_le32(eng_clock);	/* 10 khz */
2719254885Sdumbbell
2720254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2721254885Sdumbbell}
2722254885Sdumbbell
2723254885Sdumbbellvoid radeon_atom_set_memory_clock(struct radeon_device *rdev,
2724254885Sdumbbell				  uint32_t mem_clock)
2725254885Sdumbbell{
2726254885Sdumbbell	SET_MEMORY_CLOCK_PS_ALLOCATION args;
2727254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
2728254885Sdumbbell
2729254885Sdumbbell	if (rdev->flags & RADEON_IS_IGP)
2730254885Sdumbbell		return;
2731254885Sdumbbell
2732254885Sdumbbell	args.ulTargetMemoryClock = cpu_to_le32(mem_clock);	/* 10 khz */
2733254885Sdumbbell
2734254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2735254885Sdumbbell}
2736254885Sdumbbell
2737254885Sdumbbellunion set_voltage {
2738254885Sdumbbell	struct _SET_VOLTAGE_PS_ALLOCATION alloc;
2739254885Sdumbbell	struct _SET_VOLTAGE_PARAMETERS v1;
2740254885Sdumbbell	struct _SET_VOLTAGE_PARAMETERS_V2 v2;
2741254885Sdumbbell	struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;
2742254885Sdumbbell};
2743254885Sdumbbell
2744254885Sdumbbellvoid radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type)
2745254885Sdumbbell{
2746254885Sdumbbell	union set_voltage args;
2747254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
2748254885Sdumbbell	u8 frev, crev, volt_index = voltage_level;
2749254885Sdumbbell
2750254885Sdumbbell	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
2751254885Sdumbbell		return;
2752254885Sdumbbell
2753254885Sdumbbell	/* 0xff01 is a flag rather then an actual voltage */
2754254885Sdumbbell	if (voltage_level == 0xff01)
2755254885Sdumbbell		return;
2756254885Sdumbbell
2757254885Sdumbbell	switch (crev) {
2758254885Sdumbbell	case 1:
2759254885Sdumbbell		args.v1.ucVoltageType = voltage_type;
2760254885Sdumbbell		args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE;
2761254885Sdumbbell		args.v1.ucVoltageIndex = volt_index;
2762254885Sdumbbell		break;
2763254885Sdumbbell	case 2:
2764254885Sdumbbell		args.v2.ucVoltageType = voltage_type;
2765254885Sdumbbell		args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE;
2766254885Sdumbbell		args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
2767254885Sdumbbell		break;
2768254885Sdumbbell	case 3:
2769254885Sdumbbell		args.v3.ucVoltageType = voltage_type;
2770254885Sdumbbell		args.v3.ucVoltageMode = ATOM_SET_VOLTAGE;
2771254885Sdumbbell		args.v3.usVoltageLevel = cpu_to_le16(voltage_level);
2772254885Sdumbbell		break;
2773254885Sdumbbell	default:
2774254885Sdumbbell		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
2775254885Sdumbbell		return;
2776254885Sdumbbell	}
2777254885Sdumbbell
2778254885Sdumbbell	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2779254885Sdumbbell}
2780254885Sdumbbell
2781254885Sdumbbellstatic int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
2782254885Sdumbbell				    u16 voltage_id, u16 *voltage)
2783254885Sdumbbell{
2784254885Sdumbbell	union set_voltage args;
2785254885Sdumbbell	int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
2786254885Sdumbbell	u8 frev, crev;
2787254885Sdumbbell
2788254885Sdumbbell	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
2789254885Sdumbbell		return -EINVAL;
2790254885Sdumbbell
2791254885Sdumbbell	switch (crev) {
2792254885Sdumbbell	case 1:
2793254885Sdumbbell		return -EINVAL;
2794254885Sdumbbell	case 2:
2795254885Sdumbbell		args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;
2796254885Sdumbbell		args.v2.ucVoltageMode = 0;
2797254885Sdumbbell		args.v2.usVoltageLevel = 0;
2798254885Sdumbbell
2799254885Sdumbbell		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2800254885Sdumbbell
2801254885Sdumbbell		*voltage = le16_to_cpu(args.v2.usVoltageLevel);
2802254885Sdumbbell		break;
2803254885Sdumbbell	case 3:
2804254885Sdumbbell		args.v3.ucVoltageType = voltage_type;
2805254885Sdumbbell		args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;
2806254885Sdumbbell		args.v3.usVoltageLevel = cpu_to_le16(voltage_id);
2807254885Sdumbbell
2808254885Sdumbbell		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2809254885Sdumbbell
2810254885Sdumbbell		*voltage = le16_to_cpu(args.v3.usVoltageLevel);
2811254885Sdumbbell		break;
2812254885Sdumbbell	default:
2813254885Sdumbbell		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
2814254885Sdumbbell		return -EINVAL;
2815254885Sdumbbell	}
2816254885Sdumbbell
2817254885Sdumbbell	return 0;
2818254885Sdumbbell}
2819254885Sdumbbell
2820254885Sdumbbellvoid radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
2821254885Sdumbbell{
2822254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
2823254885Sdumbbell	uint32_t bios_2_scratch, bios_6_scratch;
2824254885Sdumbbell
2825254885Sdumbbell	if (rdev->family >= CHIP_R600) {
2826254885Sdumbbell		bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
2827254885Sdumbbell		bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
2828254885Sdumbbell	} else {
2829254885Sdumbbell		bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
2830254885Sdumbbell		bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
2831254885Sdumbbell	}
2832254885Sdumbbell
2833254885Sdumbbell	/* let the bios control the backlight */
2834254885Sdumbbell	bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;
2835254885Sdumbbell
2836254885Sdumbbell	/* tell the bios not to handle mode switching */
2837254885Sdumbbell	bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
2838254885Sdumbbell
2839254885Sdumbbell	if (rdev->family >= CHIP_R600) {
2840254885Sdumbbell		WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
2841254885Sdumbbell		WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
2842254885Sdumbbell	} else {
2843254885Sdumbbell		WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
2844254885Sdumbbell		WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
2845254885Sdumbbell	}
2846254885Sdumbbell
2847254885Sdumbbell}
2848254885Sdumbbell
2849254885Sdumbbellvoid radeon_save_bios_scratch_regs(struct radeon_device *rdev)
2850254885Sdumbbell{
2851254885Sdumbbell	uint32_t scratch_reg;
2852254885Sdumbbell	int i;
2853254885Sdumbbell
2854254885Sdumbbell	if (rdev->family >= CHIP_R600)
2855254885Sdumbbell		scratch_reg = R600_BIOS_0_SCRATCH;
2856254885Sdumbbell	else
2857254885Sdumbbell		scratch_reg = RADEON_BIOS_0_SCRATCH;
2858254885Sdumbbell
2859254885Sdumbbell	for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++)
2860254885Sdumbbell		rdev->bios_scratch[i] = RREG32(scratch_reg + (i * 4));
2861254885Sdumbbell}
2862254885Sdumbbell
2863254885Sdumbbellvoid radeon_restore_bios_scratch_regs(struct radeon_device *rdev)
2864254885Sdumbbell{
2865254885Sdumbbell	uint32_t scratch_reg;
2866254885Sdumbbell	int i;
2867254885Sdumbbell
2868254885Sdumbbell	if (rdev->family >= CHIP_R600)
2869254885Sdumbbell		scratch_reg = R600_BIOS_0_SCRATCH;
2870254885Sdumbbell	else
2871254885Sdumbbell		scratch_reg = RADEON_BIOS_0_SCRATCH;
2872254885Sdumbbell
2873254885Sdumbbell	for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++)
2874254885Sdumbbell		WREG32(scratch_reg + (i * 4), rdev->bios_scratch[i]);
2875254885Sdumbbell}
2876254885Sdumbbell
2877254885Sdumbbellvoid radeon_atom_output_lock(struct drm_encoder *encoder, bool lock)
2878254885Sdumbbell{
2879254885Sdumbbell	struct drm_device *dev = encoder->dev;
2880254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
2881254885Sdumbbell	uint32_t bios_6_scratch;
2882254885Sdumbbell
2883254885Sdumbbell	if (rdev->family >= CHIP_R600)
2884254885Sdumbbell		bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
2885254885Sdumbbell	else
2886254885Sdumbbell		bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
2887254885Sdumbbell
2888254885Sdumbbell	if (lock) {
2889254885Sdumbbell		bios_6_scratch |= ATOM_S6_CRITICAL_STATE;
2890254885Sdumbbell		bios_6_scratch &= ~ATOM_S6_ACC_MODE;
2891254885Sdumbbell	} else {
2892254885Sdumbbell		bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;
2893254885Sdumbbell		bios_6_scratch |= ATOM_S6_ACC_MODE;
2894254885Sdumbbell	}
2895254885Sdumbbell
2896254885Sdumbbell	if (rdev->family >= CHIP_R600)
2897254885Sdumbbell		WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
2898254885Sdumbbell	else
2899254885Sdumbbell		WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
2900254885Sdumbbell}
2901254885Sdumbbell
2902254885Sdumbbell/* at some point we may want to break this out into individual functions */
2903254885Sdumbbellvoid
2904254885Sdumbbellradeon_atombios_connected_scratch_regs(struct drm_connector *connector,
2905254885Sdumbbell				       struct drm_encoder *encoder,
2906254885Sdumbbell				       bool connected)
2907254885Sdumbbell{
2908254885Sdumbbell	struct drm_device *dev = connector->dev;
2909254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
2910254885Sdumbbell	struct radeon_connector *radeon_connector =
2911254885Sdumbbell	    to_radeon_connector(connector);
2912254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
2913254885Sdumbbell	uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch;
2914254885Sdumbbell
2915254885Sdumbbell	if (rdev->family >= CHIP_R600) {
2916254885Sdumbbell		bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH);
2917254885Sdumbbell		bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
2918254885Sdumbbell		bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
2919254885Sdumbbell	} else {
2920254885Sdumbbell		bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
2921254885Sdumbbell		bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
2922254885Sdumbbell		bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
2923254885Sdumbbell	}
2924254885Sdumbbell
2925254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) &&
2926254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) {
2927254885Sdumbbell		if (connected) {
2928254885Sdumbbell			DRM_DEBUG_KMS("TV1 connected\n");
2929254885Sdumbbell			bios_3_scratch |= ATOM_S3_TV1_ACTIVE;
2930254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_TV1;
2931254885Sdumbbell		} else {
2932254885Sdumbbell			DRM_DEBUG_KMS("TV1 disconnected\n");
2933254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_TV1_MASK;
2934254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE;
2935254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1;
2936254885Sdumbbell		}
2937254885Sdumbbell	}
2938254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) &&
2939254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) {
2940254885Sdumbbell		if (connected) {
2941254885Sdumbbell			DRM_DEBUG_KMS("CV connected\n");
2942254885Sdumbbell			bios_3_scratch |= ATOM_S3_CV_ACTIVE;
2943254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_CV;
2944254885Sdumbbell		} else {
2945254885Sdumbbell			DRM_DEBUG_KMS("CV disconnected\n");
2946254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_CV_MASK;
2947254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_CV_ACTIVE;
2948254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV;
2949254885Sdumbbell		}
2950254885Sdumbbell	}
2951254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
2952254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
2953254885Sdumbbell		if (connected) {
2954254885Sdumbbell			DRM_DEBUG_KMS("LCD1 connected\n");
2955254885Sdumbbell			bios_0_scratch |= ATOM_S0_LCD1;
2956254885Sdumbbell			bios_3_scratch |= ATOM_S3_LCD1_ACTIVE;
2957254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1;
2958254885Sdumbbell		} else {
2959254885Sdumbbell			DRM_DEBUG_KMS("LCD1 disconnected\n");
2960254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_LCD1;
2961254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE;
2962254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1;
2963254885Sdumbbell		}
2964254885Sdumbbell	}
2965254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
2966254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
2967254885Sdumbbell		if (connected) {
2968254885Sdumbbell			DRM_DEBUG_KMS("CRT1 connected\n");
2969254885Sdumbbell			bios_0_scratch |= ATOM_S0_CRT1_COLOR;
2970254885Sdumbbell			bios_3_scratch |= ATOM_S3_CRT1_ACTIVE;
2971254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1;
2972254885Sdumbbell		} else {
2973254885Sdumbbell			DRM_DEBUG_KMS("CRT1 disconnected\n");
2974254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_CRT1_MASK;
2975254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE;
2976254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1;
2977254885Sdumbbell		}
2978254885Sdumbbell	}
2979254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
2980254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
2981254885Sdumbbell		if (connected) {
2982254885Sdumbbell			DRM_DEBUG_KMS("CRT2 connected\n");
2983254885Sdumbbell			bios_0_scratch |= ATOM_S0_CRT2_COLOR;
2984254885Sdumbbell			bios_3_scratch |= ATOM_S3_CRT2_ACTIVE;
2985254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2;
2986254885Sdumbbell		} else {
2987254885Sdumbbell			DRM_DEBUG_KMS("CRT2 disconnected\n");
2988254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_CRT2_MASK;
2989254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE;
2990254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2;
2991254885Sdumbbell		}
2992254885Sdumbbell	}
2993254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
2994254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
2995254885Sdumbbell		if (connected) {
2996254885Sdumbbell			DRM_DEBUG_KMS("DFP1 connected\n");
2997254885Sdumbbell			bios_0_scratch |= ATOM_S0_DFP1;
2998254885Sdumbbell			bios_3_scratch |= ATOM_S3_DFP1_ACTIVE;
2999254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1;
3000254885Sdumbbell		} else {
3001254885Sdumbbell			DRM_DEBUG_KMS("DFP1 disconnected\n");
3002254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_DFP1;
3003254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE;
3004254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1;
3005254885Sdumbbell		}
3006254885Sdumbbell	}
3007254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
3008254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
3009254885Sdumbbell		if (connected) {
3010254885Sdumbbell			DRM_DEBUG_KMS("DFP2 connected\n");
3011254885Sdumbbell			bios_0_scratch |= ATOM_S0_DFP2;
3012254885Sdumbbell			bios_3_scratch |= ATOM_S3_DFP2_ACTIVE;
3013254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2;
3014254885Sdumbbell		} else {
3015254885Sdumbbell			DRM_DEBUG_KMS("DFP2 disconnected\n");
3016254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_DFP2;
3017254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE;
3018254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2;
3019254885Sdumbbell		}
3020254885Sdumbbell	}
3021254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) &&
3022254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) {
3023254885Sdumbbell		if (connected) {
3024254885Sdumbbell			DRM_DEBUG_KMS("DFP3 connected\n");
3025254885Sdumbbell			bios_0_scratch |= ATOM_S0_DFP3;
3026254885Sdumbbell			bios_3_scratch |= ATOM_S3_DFP3_ACTIVE;
3027254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3;
3028254885Sdumbbell		} else {
3029254885Sdumbbell			DRM_DEBUG_KMS("DFP3 disconnected\n");
3030254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_DFP3;
3031254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE;
3032254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3;
3033254885Sdumbbell		}
3034254885Sdumbbell	}
3035254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) &&
3036254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) {
3037254885Sdumbbell		if (connected) {
3038254885Sdumbbell			DRM_DEBUG_KMS("DFP4 connected\n");
3039254885Sdumbbell			bios_0_scratch |= ATOM_S0_DFP4;
3040254885Sdumbbell			bios_3_scratch |= ATOM_S3_DFP4_ACTIVE;
3041254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4;
3042254885Sdumbbell		} else {
3043254885Sdumbbell			DRM_DEBUG_KMS("DFP4 disconnected\n");
3044254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_DFP4;
3045254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE;
3046254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4;
3047254885Sdumbbell		}
3048254885Sdumbbell	}
3049254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) &&
3050254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) {
3051254885Sdumbbell		if (connected) {
3052254885Sdumbbell			DRM_DEBUG_KMS("DFP5 connected\n");
3053254885Sdumbbell			bios_0_scratch |= ATOM_S0_DFP5;
3054254885Sdumbbell			bios_3_scratch |= ATOM_S3_DFP5_ACTIVE;
3055254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5;
3056254885Sdumbbell		} else {
3057254885Sdumbbell			DRM_DEBUG_KMS("DFP5 disconnected\n");
3058254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_DFP5;
3059254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE;
3060254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5;
3061254885Sdumbbell		}
3062254885Sdumbbell	}
3063254885Sdumbbell	if ((radeon_encoder->devices & ATOM_DEVICE_DFP6_SUPPORT) &&
3064254885Sdumbbell	    (radeon_connector->devices & ATOM_DEVICE_DFP6_SUPPORT)) {
3065254885Sdumbbell		if (connected) {
3066254885Sdumbbell			DRM_DEBUG_KMS("DFP6 connected\n");
3067254885Sdumbbell			bios_0_scratch |= ATOM_S0_DFP6;
3068254885Sdumbbell			bios_3_scratch |= ATOM_S3_DFP6_ACTIVE;
3069254885Sdumbbell			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP6;
3070254885Sdumbbell		} else {
3071254885Sdumbbell			DRM_DEBUG_KMS("DFP6 disconnected\n");
3072254885Sdumbbell			bios_0_scratch &= ~ATOM_S0_DFP6;
3073254885Sdumbbell			bios_3_scratch &= ~ATOM_S3_DFP6_ACTIVE;
3074254885Sdumbbell			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP6;
3075254885Sdumbbell		}
3076254885Sdumbbell	}
3077254885Sdumbbell
3078254885Sdumbbell	if (rdev->family >= CHIP_R600) {
3079254885Sdumbbell		WREG32(R600_BIOS_0_SCRATCH, bios_0_scratch);
3080254885Sdumbbell		WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
3081254885Sdumbbell		WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
3082254885Sdumbbell	} else {
3083254885Sdumbbell		WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch);
3084254885Sdumbbell		WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
3085254885Sdumbbell		WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
3086254885Sdumbbell	}
3087254885Sdumbbell}
3088254885Sdumbbell
3089254885Sdumbbellvoid
3090254885Sdumbbellradeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc)
3091254885Sdumbbell{
3092254885Sdumbbell	struct drm_device *dev = encoder->dev;
3093254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
3094254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
3095254885Sdumbbell	uint32_t bios_3_scratch;
3096254885Sdumbbell
3097254885Sdumbbell	if (ASIC_IS_DCE4(rdev))
3098254885Sdumbbell		return;
3099254885Sdumbbell
3100254885Sdumbbell	if (rdev->family >= CHIP_R600)
3101254885Sdumbbell		bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
3102254885Sdumbbell	else
3103254885Sdumbbell		bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
3104254885Sdumbbell
3105254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
3106254885Sdumbbell		bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE;
3107254885Sdumbbell		bios_3_scratch |= (crtc << 18);
3108254885Sdumbbell	}
3109254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
3110254885Sdumbbell		bios_3_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE;
3111254885Sdumbbell		bios_3_scratch |= (crtc << 24);
3112254885Sdumbbell	}
3113254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
3114254885Sdumbbell		bios_3_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE;
3115254885Sdumbbell		bios_3_scratch |= (crtc << 16);
3116254885Sdumbbell	}
3117254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
3118254885Sdumbbell		bios_3_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE;
3119254885Sdumbbell		bios_3_scratch |= (crtc << 20);
3120254885Sdumbbell	}
3121254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
3122254885Sdumbbell		bios_3_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE;
3123254885Sdumbbell		bios_3_scratch |= (crtc << 17);
3124254885Sdumbbell	}
3125254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
3126254885Sdumbbell		bios_3_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE;
3127254885Sdumbbell		bios_3_scratch |= (crtc << 19);
3128254885Sdumbbell	}
3129254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
3130254885Sdumbbell		bios_3_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE;
3131254885Sdumbbell		bios_3_scratch |= (crtc << 23);
3132254885Sdumbbell	}
3133254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
3134254885Sdumbbell		bios_3_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE;
3135254885Sdumbbell		bios_3_scratch |= (crtc << 25);
3136254885Sdumbbell	}
3137254885Sdumbbell
3138254885Sdumbbell	if (rdev->family >= CHIP_R600)
3139254885Sdumbbell		WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
3140254885Sdumbbell	else
3141254885Sdumbbell		WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
3142254885Sdumbbell}
3143254885Sdumbbell
3144254885Sdumbbellvoid
3145254885Sdumbbellradeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on)
3146254885Sdumbbell{
3147254885Sdumbbell	struct drm_device *dev = encoder->dev;
3148254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
3149254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
3150254885Sdumbbell	uint32_t bios_2_scratch;
3151254885Sdumbbell
3152254885Sdumbbell	if (ASIC_IS_DCE4(rdev))
3153254885Sdumbbell		return;
3154254885Sdumbbell
3155254885Sdumbbell	if (rdev->family >= CHIP_R600)
3156254885Sdumbbell		bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
3157254885Sdumbbell	else
3158254885Sdumbbell		bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
3159254885Sdumbbell
3160254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
3161254885Sdumbbell		if (on)
3162254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE;
3163254885Sdumbbell		else
3164254885Sdumbbell			bios_2_scratch |= ATOM_S2_TV1_DPMS_STATE;
3165254885Sdumbbell	}
3166254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
3167254885Sdumbbell		if (on)
3168254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE;
3169254885Sdumbbell		else
3170254885Sdumbbell			bios_2_scratch |= ATOM_S2_CV_DPMS_STATE;
3171254885Sdumbbell	}
3172254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
3173254885Sdumbbell		if (on)
3174254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE;
3175254885Sdumbbell		else
3176254885Sdumbbell			bios_2_scratch |= ATOM_S2_CRT1_DPMS_STATE;
3177254885Sdumbbell	}
3178254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
3179254885Sdumbbell		if (on)
3180254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE;
3181254885Sdumbbell		else
3182254885Sdumbbell			bios_2_scratch |= ATOM_S2_CRT2_DPMS_STATE;
3183254885Sdumbbell	}
3184254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
3185254885Sdumbbell		if (on)
3186254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_LCD1_DPMS_STATE;
3187254885Sdumbbell		else
3188254885Sdumbbell			bios_2_scratch |= ATOM_S2_LCD1_DPMS_STATE;
3189254885Sdumbbell	}
3190254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
3191254885Sdumbbell		if (on)
3192254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE;
3193254885Sdumbbell		else
3194254885Sdumbbell			bios_2_scratch |= ATOM_S2_DFP1_DPMS_STATE;
3195254885Sdumbbell	}
3196254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
3197254885Sdumbbell		if (on)
3198254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE;
3199254885Sdumbbell		else
3200254885Sdumbbell			bios_2_scratch |= ATOM_S2_DFP2_DPMS_STATE;
3201254885Sdumbbell	}
3202254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
3203254885Sdumbbell		if (on)
3204254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE;
3205254885Sdumbbell		else
3206254885Sdumbbell			bios_2_scratch |= ATOM_S2_DFP3_DPMS_STATE;
3207254885Sdumbbell	}
3208254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) {
3209254885Sdumbbell		if (on)
3210254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_DFP4_DPMS_STATE;
3211254885Sdumbbell		else
3212254885Sdumbbell			bios_2_scratch |= ATOM_S2_DFP4_DPMS_STATE;
3213254885Sdumbbell	}
3214254885Sdumbbell	if (radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) {
3215254885Sdumbbell		if (on)
3216254885Sdumbbell			bios_2_scratch &= ~ATOM_S2_DFP5_DPMS_STATE;
3217254885Sdumbbell		else
3218254885Sdumbbell			bios_2_scratch |= ATOM_S2_DFP5_DPMS_STATE;
3219254885Sdumbbell	}
3220254885Sdumbbell
3221254885Sdumbbell	if (rdev->family >= CHIP_R600)
3222254885Sdumbbell		WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
3223254885Sdumbbell	else
3224254885Sdumbbell		WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
3225254885Sdumbbell}
3226