blob: ad913542ec1acd09f7bdf95fc3f910444577b144 [file] [log] [blame]
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001/*
2 * Copyright 2007-8 Advanced Micro Devices, Inc.
3 * Copyright 2008 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors: Dave Airlie
24 * Alex Deucher
25 */
David Howells760285e2012-10-02 18:01:07 +010026#include <drm/drmP.h>
27#include <drm/radeon_drm.h>
Jerome Glisse771fe6b2009-06-05 14:42:42 +020028#include "radeon.h"
29
30#include "atom.h"
31#include "atom-bits.h"
32
33/* from radeon_encoder.c */
34extern uint32_t
Alex Deucher5137ee92010-08-12 18:58:47 -040035radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device,
36 uint8_t dac);
Jerome Glisse771fe6b2009-06-05 14:42:42 +020037extern void radeon_link_encoder_connector(struct drm_device *dev);
38extern void
Alex Deucher5137ee92010-08-12 18:58:47 -040039radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum,
Alex Deucher36868bd2011-01-06 21:19:21 -050040 uint32_t supported_device, u16 caps);
Jerome Glisse771fe6b2009-06-05 14:42:42 +020041
42/* from radeon_connector.c */
43extern void
44radeon_add_atom_connector(struct drm_device *dev,
45 uint32_t connector_id,
46 uint32_t supported_device,
47 int connector_type,
48 struct radeon_i2c_bus_rec *i2c_bus,
Alex Deucher5137ee92010-08-12 18:58:47 -040049 uint32_t igp_lane_info,
Alex Deuchereed45b32009-12-04 14:45:27 -050050 uint16_t connector_object_id,
Alex Deucher26b5bc92010-08-05 21:21:18 -040051 struct radeon_hpd *hpd,
52 struct radeon_router *router);
Jerome Glisse771fe6b2009-06-05 14:42:42 +020053
54/* from radeon_legacy_encoder.c */
55extern void
Alex Deucher5137ee92010-08-12 18:58:47 -040056radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum,
Jerome Glisse771fe6b2009-06-05 14:42:42 +020057 uint32_t supported_device);
58
59union atom_supported_devices {
60 struct _ATOM_SUPPORTED_DEVICES_INFO info;
61 struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
62 struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1;
63};
64
Alex Deucher21240f92011-11-21 12:41:21 -050065static void radeon_lookup_i2c_gpio_quirks(struct radeon_device *rdev,
66 ATOM_GPIO_I2C_ASSIGMENT *gpio,
67 u8 index)
68{
69 /* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */
70 if ((rdev->family == CHIP_R420) ||
71 (rdev->family == CHIP_R423) ||
72 (rdev->family == CHIP_RV410)) {
73 if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) ||
74 (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) ||
75 (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) {
76 gpio->ucClkMaskShift = 0x19;
77 gpio->ucDataMaskShift = 0x18;
78 }
79 }
80
81 /* some evergreen boards have bad data for this entry */
82 if (ASIC_IS_DCE4(rdev)) {
83 if ((index == 7) &&
84 (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) &&
85 (gpio->sucI2cId.ucAccess == 0)) {
86 gpio->sucI2cId.ucAccess = 0x97;
87 gpio->ucDataMaskShift = 8;
88 gpio->ucDataEnShift = 8;
89 gpio->ucDataY_Shift = 8;
90 gpio->ucDataA_Shift = 8;
91 }
92 }
93
94 /* some DCE3 boards have bad data for this entry */
95 if (ASIC_IS_DCE3(rdev)) {
96 if ((index == 4) &&
97 (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) &&
98 (gpio->sucI2cId.ucAccess == 0x94))
99 gpio->sucI2cId.ucAccess = 0x14;
100 }
101}
102
103static struct radeon_i2c_bus_rec radeon_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio)
104{
105 struct radeon_i2c_bus_rec i2c;
106
107 memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
108
109 i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
110 i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
111 i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
112 i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
113 i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
114 i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
115 i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
116 i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
117 i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
118 i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
119 i2c.en_clk_mask = (1 << gpio->ucClkEnShift);
120 i2c.en_data_mask = (1 << gpio->ucDataEnShift);
121 i2c.y_clk_mask = (1 << gpio->ucClkY_Shift);
122 i2c.y_data_mask = (1 << gpio->ucDataY_Shift);
123 i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
124 i2c.a_data_mask = (1 << gpio->ucDataA_Shift);
125
126 if (gpio->sucI2cId.sbfAccess.bfHW_Capable)
127 i2c.hw_capable = true;
128 else
129 i2c.hw_capable = false;
130
131 if (gpio->sucI2cId.ucAccess == 0xa0)
132 i2c.mm_i2c = true;
133 else
134 i2c.mm_i2c = false;
135
136 i2c.i2c_id = gpio->sucI2cId.ucAccess;
137
138 if (i2c.mask_clk_reg)
139 i2c.valid = true;
140 else
141 i2c.valid = false;
142
143 return i2c;
144}
145
Andi Kleence580fa2011-10-13 16:08:47 -0700146static struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rdev,
Alex Deuchereed45b32009-12-04 14:45:27 -0500147 uint8_t id)
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200148{
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200149 struct atom_context *ctx = rdev->mode_info.atom_context;
Alex Deucher6a93cb22009-11-23 17:39:28 -0500150 ATOM_GPIO_I2C_ASSIGMENT *gpio;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200151 struct radeon_i2c_bus_rec i2c;
152 int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
153 struct _ATOM_GPIO_I2C_INFO *i2c_info;
Alex Deucher95beb692010-04-01 19:08:47 +0000154 uint16_t data_offset, size;
155 int i, num_indices;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200156
157 memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
158 i2c.valid = false;
159
Alex Deucher95beb692010-04-01 19:08:47 +0000160 if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
Alex Deuchera084e6e2010-03-18 01:04:01 -0400161 i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200162
Alex Deucher95beb692010-04-01 19:08:47 +0000163 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
164 sizeof(ATOM_GPIO_I2C_ASSIGMENT);
165
166 for (i = 0; i < num_indices; i++) {
Alex Deuchera084e6e2010-03-18 01:04:01 -0400167 gpio = &i2c_info->asGPIO_Info[i];
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200168
Alex Deucher21240f92011-11-21 12:41:21 -0500169 radeon_lookup_i2c_gpio_quirks(rdev, gpio, i);
Alex Deucher3074adc2010-11-30 00:15:10 -0500170
Alex Deuchera084e6e2010-03-18 01:04:01 -0400171 if (gpio->sucI2cId.ucAccess == id) {
Alex Deucher21240f92011-11-21 12:41:21 -0500172 i2c = radeon_get_bus_rec_for_i2c_gpio(gpio);
Alex Deuchera084e6e2010-03-18 01:04:01 -0400173 break;
174 }
Alex Deucherd3f420d2009-12-08 14:30:49 -0500175 }
176 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200177
178 return i2c;
179}
180
Alex Deucherf376b942010-08-05 21:21:16 -0400181void radeon_atombios_i2c_init(struct radeon_device *rdev)
182{
183 struct atom_context *ctx = rdev->mode_info.atom_context;
184 ATOM_GPIO_I2C_ASSIGMENT *gpio;
185 struct radeon_i2c_bus_rec i2c;
186 int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
187 struct _ATOM_GPIO_I2C_INFO *i2c_info;
188 uint16_t data_offset, size;
189 int i, num_indices;
190 char stmp[32];
191
Alex Deucherf376b942010-08-05 21:21:16 -0400192 if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
193 i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
194
195 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
196 sizeof(ATOM_GPIO_I2C_ASSIGMENT);
197
198 for (i = 0; i < num_indices; i++) {
199 gpio = &i2c_info->asGPIO_Info[i];
Alex Deucherea393022010-08-27 16:04:29 -0400200
Alex Deucher21240f92011-11-21 12:41:21 -0500201 radeon_lookup_i2c_gpio_quirks(rdev, gpio, i);
Alex Deucherd7245022011-11-21 12:10:14 -0500202
Alex Deucher21240f92011-11-21 12:41:21 -0500203 i2c = radeon_get_bus_rec_for_i2c_gpio(gpio);
Alex Deucherea393022010-08-27 16:04:29 -0400204
Alex Deucher21240f92011-11-21 12:41:21 -0500205 if (i2c.valid) {
Alex Deucherf376b942010-08-05 21:21:16 -0400206 sprintf(stmp, "0x%x", i2c.i2c_id);
207 rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp);
208 }
209 }
210 }
211}
212
Andi Kleence580fa2011-10-13 16:08:47 -0700213static struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
Alex Deuchercc8dbbb2013-08-14 01:03:41 -0400214 u8 id)
Alex Deuchereed45b32009-12-04 14:45:27 -0500215{
216 struct atom_context *ctx = rdev->mode_info.atom_context;
217 struct radeon_gpio_rec gpio;
218 int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT);
219 struct _ATOM_GPIO_PIN_LUT *gpio_info;
220 ATOM_GPIO_PIN_ASSIGNMENT *pin;
221 u16 data_offset, size;
222 int i, num_indices;
223
224 memset(&gpio, 0, sizeof(struct radeon_gpio_rec));
225 gpio.valid = false;
226
Alex Deuchera084e6e2010-03-18 01:04:01 -0400227 if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
228 gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset);
Alex Deuchereed45b32009-12-04 14:45:27 -0500229
Alex Deuchera084e6e2010-03-18 01:04:01 -0400230 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
231 sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
Alex Deuchereed45b32009-12-04 14:45:27 -0500232
Alex Deuchera084e6e2010-03-18 01:04:01 -0400233 for (i = 0; i < num_indices; i++) {
234 pin = &gpio_info->asGPIO_Pin[i];
235 if (id == pin->ucGPIO_ID) {
236 gpio.id = pin->ucGPIO_ID;
Cédric Cano45894332011-02-11 19:45:37 -0500237 gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4;
Alex Deuchera084e6e2010-03-18 01:04:01 -0400238 gpio.mask = (1 << pin->ucGpioPinBitShift);
239 gpio.valid = true;
240 break;
241 }
Alex Deuchereed45b32009-12-04 14:45:27 -0500242 }
243 }
244
245 return gpio;
246}
247
248static struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device *rdev,
249 struct radeon_gpio_rec *gpio)
250{
251 struct radeon_hpd hpd;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -0500252 u32 reg;
253
Jean Delvare1d978da2010-08-15 14:11:24 +0200254 memset(&hpd, 0, sizeof(struct radeon_hpd));
255
Alex Deucher82d118e2012-03-20 17:18:01 -0400256 if (ASIC_IS_DCE6(rdev))
257 reg = SI_DC_GPIO_HPD_A;
258 else if (ASIC_IS_DCE4(rdev))
Alex Deucherbcc1c2a2010-01-12 17:54:34 -0500259 reg = EVERGREEN_DC_GPIO_HPD_A;
260 else
261 reg = AVIVO_DC_GPIO_HPD_A;
262
Alex Deuchereed45b32009-12-04 14:45:27 -0500263 hpd.gpio = *gpio;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -0500264 if (gpio->reg == reg) {
Alex Deuchereed45b32009-12-04 14:45:27 -0500265 switch(gpio->mask) {
266 case (1 << 0):
267 hpd.hpd = RADEON_HPD_1;
268 break;
269 case (1 << 8):
270 hpd.hpd = RADEON_HPD_2;
271 break;
272 case (1 << 16):
273 hpd.hpd = RADEON_HPD_3;
274 break;
275 case (1 << 24):
276 hpd.hpd = RADEON_HPD_4;
277 break;
278 case (1 << 26):
279 hpd.hpd = RADEON_HPD_5;
280 break;
281 case (1 << 28):
282 hpd.hpd = RADEON_HPD_6;
283 break;
284 default:
285 hpd.hpd = RADEON_HPD_NONE;
286 break;
287 }
288 } else
289 hpd.hpd = RADEON_HPD_NONE;
290 return hpd;
291}
292
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200293static bool radeon_atom_apply_quirks(struct drm_device *dev,
294 uint32_t supported_device,
295 int *connector_type,
Alex Deucher848577e2009-07-08 16:15:30 -0400296 struct radeon_i2c_bus_rec *i2c_bus,
Alex Deuchereed45b32009-12-04 14:45:27 -0500297 uint16_t *line_mux,
298 struct radeon_hpd *hpd)
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200299{
300
301 /* Asus M2A-VM HDMI board lists the DVI port as HDMI */
302 if ((dev->pdev->device == 0x791e) &&
303 (dev->pdev->subsystem_vendor == 0x1043) &&
304 (dev->pdev->subsystem_device == 0x826d)) {
305 if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
306 (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
307 *connector_type = DRM_MODE_CONNECTOR_DVID;
308 }
309
Alex Deucherc86a9032010-02-18 14:14:58 -0500310 /* Asrock RS600 board lists the DVI port as HDMI */
311 if ((dev->pdev->device == 0x7941) &&
312 (dev->pdev->subsystem_vendor == 0x1849) &&
313 (dev->pdev->subsystem_device == 0x7941)) {
314 if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
315 (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
316 *connector_type = DRM_MODE_CONNECTOR_DVID;
317 }
318
Alex Deucherf36fce02010-09-27 11:33:00 -0400319 /* MSI K9A2GM V2/V3 board has no HDMI or DVI */
320 if ((dev->pdev->device == 0x796e) &&
321 (dev->pdev->subsystem_vendor == 0x1462) &&
322 (dev->pdev->subsystem_device == 0x7302)) {
323 if ((supported_device == ATOM_DEVICE_DFP2_SUPPORT) ||
324 (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
325 return false;
326 }
327
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200328 /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
329 if ((dev->pdev->device == 0x7941) &&
330 (dev->pdev->subsystem_vendor == 0x147b) &&
331 (dev->pdev->subsystem_device == 0x2412)) {
332 if (*connector_type == DRM_MODE_CONNECTOR_DVII)
333 return false;
334 }
335
336 /* Falcon NW laptop lists vga ddc line for LVDS */
337 if ((dev->pdev->device == 0x5653) &&
338 (dev->pdev->subsystem_vendor == 0x1462) &&
339 (dev->pdev->subsystem_device == 0x0291)) {
Alex Deucher848577e2009-07-08 16:15:30 -0400340 if (*connector_type == DRM_MODE_CONNECTOR_LVDS) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200341 i2c_bus->valid = false;
Alex Deucher848577e2009-07-08 16:15:30 -0400342 *line_mux = 53;
343 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200344 }
345
Alex Deucher4e3f9b782009-12-01 14:49:50 -0500346 /* HIS X1300 is DVI+VGA, not DVI+DVI */
347 if ((dev->pdev->device == 0x7146) &&
348 (dev->pdev->subsystem_vendor == 0x17af) &&
349 (dev->pdev->subsystem_device == 0x2058)) {
350 if (supported_device == ATOM_DEVICE_DFP1_SUPPORT)
351 return false;
352 }
353
Dave Airlieaa1a7502009-12-04 11:51:34 +1000354 /* Gigabyte X1300 is DVI+VGA, not DVI+DVI */
355 if ((dev->pdev->device == 0x7142) &&
356 (dev->pdev->subsystem_vendor == 0x1458) &&
357 (dev->pdev->subsystem_device == 0x2134)) {
358 if (supported_device == ATOM_DEVICE_DFP1_SUPPORT)
359 return false;
360 }
361
362
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200363 /* Funky macbooks */
364 if ((dev->pdev->device == 0x71C5) &&
365 (dev->pdev->subsystem_vendor == 0x106b) &&
366 (dev->pdev->subsystem_device == 0x0080)) {
367 if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) ||
368 (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
369 return false;
Alex Deuchere1e8a5d2010-03-26 17:14:37 -0400370 if (supported_device == ATOM_DEVICE_CRT2_SUPPORT)
371 *line_mux = 0x90;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200372 }
373
Alex Deucherbe23da82011-01-18 18:26:11 +0000374 /* mac rv630, rv730, others */
375 if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) &&
376 (*connector_type == DRM_MODE_CONNECTOR_DVII)) {
377 *connector_type = DRM_MODE_CONNECTOR_9PinDIN;
378 *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1;
Alex Deucherf598aa72011-01-04 00:43:39 -0500379 }
380
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200381 /* ASUS HD 3600 XT board lists the DVI port as HDMI */
382 if ((dev->pdev->device == 0x9598) &&
383 (dev->pdev->subsystem_vendor == 0x1043) &&
384 (dev->pdev->subsystem_device == 0x01da)) {
Alex Deucher705af9c2009-09-10 16:31:13 -0400385 if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
Alex Deucherd42571e2009-09-11 15:27:14 -0400386 *connector_type = DRM_MODE_CONNECTOR_DVII;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200387 }
388 }
389
Alex Deuchere153b702010-07-20 18:07:22 -0400390 /* ASUS HD 3600 board lists the DVI port as HDMI */
391 if ((dev->pdev->device == 0x9598) &&
392 (dev->pdev->subsystem_vendor == 0x1043) &&
393 (dev->pdev->subsystem_device == 0x01e4)) {
394 if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
395 *connector_type = DRM_MODE_CONNECTOR_DVII;
396 }
397 }
398
Alex Deucher705af9c2009-09-10 16:31:13 -0400399 /* ASUS HD 3450 board lists the DVI port as HDMI */
400 if ((dev->pdev->device == 0x95C5) &&
401 (dev->pdev->subsystem_vendor == 0x1043) &&
402 (dev->pdev->subsystem_device == 0x01e2)) {
403 if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
Alex Deucherd42571e2009-09-11 15:27:14 -0400404 *connector_type = DRM_MODE_CONNECTOR_DVII;
Alex Deucher705af9c2009-09-10 16:31:13 -0400405 }
406 }
407
408 /* some BIOSes seem to report DAC on HDMI - usually this is a board with
409 * HDMI + VGA reporting as HDMI
410 */
411 if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
412 if (supported_device & (ATOM_DEVICE_CRT_SUPPORT)) {
413 *connector_type = DRM_MODE_CONNECTOR_VGA;
414 *line_mux = 0;
415 }
416 }
417
Alex Deucher4f87af42011-05-04 11:41:47 -0400418 /* Acer laptop (Acer TravelMate 5730/5730G) has an HDMI port
Alex Deucher2f299d52011-01-04 17:42:20 -0500419 * on the laptop and a DVI port on the docking station and
420 * both share the same encoder, hpd pin, and ddc line.
421 * So while the bios table is technically correct,
422 * we drop the DVI port here since xrandr has no concept of
423 * encoders and will try and drive both connectors
424 * with different crtcs which isn't possible on the hardware
425 * side and leaves no crtcs for LVDS or VGA.
426 */
Alex Deucher4f87af42011-05-04 11:41:47 -0400427 if (((dev->pdev->device == 0x95c4) || (dev->pdev->device == 0x9591)) &&
Alex Deucher3e5f8ff2009-11-17 17:12:10 -0500428 (dev->pdev->subsystem_vendor == 0x1025) &&
429 (dev->pdev->subsystem_device == 0x013c)) {
430 if ((*connector_type == DRM_MODE_CONNECTOR_DVII) &&
Alex Deucher9ea2c4b2010-08-06 00:27:44 -0400431 (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) {
Alex Deucher2f299d52011-01-04 17:42:20 -0500432 /* actually it's a DVI-D port not DVI-I */
Alex Deucher3e5f8ff2009-11-17 17:12:10 -0500433 *connector_type = DRM_MODE_CONNECTOR_DVID;
Alex Deucher2f299d52011-01-04 17:42:20 -0500434 return false;
Alex Deucher9ea2c4b2010-08-06 00:27:44 -0400435 }
Alex Deucher3e5f8ff2009-11-17 17:12:10 -0500436 }
437
Dave Airlieefa84502010-02-09 09:06:00 +1000438 /* XFX Pine Group device rv730 reports no VGA DDC lines
439 * even though they are wired up to record 0x93
440 */
441 if ((dev->pdev->device == 0x9498) &&
442 (dev->pdev->subsystem_vendor == 0x1682) &&
Alex Deucher1ebf1692012-05-23 11:48:59 -0400443 (dev->pdev->subsystem_device == 0x2452) &&
444 (i2c_bus->valid == false) &&
445 !(supported_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))) {
Dave Airlieefa84502010-02-09 09:06:00 +1000446 struct radeon_device *rdev = dev->dev_private;
447 *i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93);
448 }
Alex Deucher4c1b2d22012-03-16 12:22:10 -0400449
450 /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */
Tvrtko Ursulin52e9b392012-08-20 15:16:04 +0100451 if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) &&
Alex Deucher4c1b2d22012-03-16 12:22:10 -0400452 (dev->pdev->subsystem_vendor == 0x1734) &&
453 (dev->pdev->subsystem_device == 0x11bd)) {
454 if (*connector_type == DRM_MODE_CONNECTOR_VGA) {
455 *connector_type = DRM_MODE_CONNECTOR_DVII;
456 *line_mux = 0x3103;
457 } else if (*connector_type == DRM_MODE_CONNECTOR_DVID) {
458 *connector_type = DRM_MODE_CONNECTOR_DVII;
459 }
460 }
461
462
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200463 return true;
464}
465
466const int supported_devices_connector_convert[] = {
467 DRM_MODE_CONNECTOR_Unknown,
468 DRM_MODE_CONNECTOR_VGA,
469 DRM_MODE_CONNECTOR_DVII,
470 DRM_MODE_CONNECTOR_DVID,
471 DRM_MODE_CONNECTOR_DVIA,
472 DRM_MODE_CONNECTOR_SVIDEO,
473 DRM_MODE_CONNECTOR_Composite,
474 DRM_MODE_CONNECTOR_LVDS,
475 DRM_MODE_CONNECTOR_Unknown,
476 DRM_MODE_CONNECTOR_Unknown,
477 DRM_MODE_CONNECTOR_HDMIA,
478 DRM_MODE_CONNECTOR_HDMIB,
479 DRM_MODE_CONNECTOR_Unknown,
480 DRM_MODE_CONNECTOR_Unknown,
481 DRM_MODE_CONNECTOR_9PinDIN,
482 DRM_MODE_CONNECTOR_DisplayPort
483};
484
Alex Deucherb75fad02009-11-05 13:16:01 -0500485const uint16_t supported_devices_connector_object_id_convert[] = {
486 CONNECTOR_OBJECT_ID_NONE,
487 CONNECTOR_OBJECT_ID_VGA,
488 CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, /* not all boards support DL */
489 CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D, /* not all boards support DL */
490 CONNECTOR_OBJECT_ID_VGA, /* technically DVI-A */
491 CONNECTOR_OBJECT_ID_COMPOSITE,
492 CONNECTOR_OBJECT_ID_SVIDEO,
493 CONNECTOR_OBJECT_ID_LVDS,
494 CONNECTOR_OBJECT_ID_9PIN_DIN,
495 CONNECTOR_OBJECT_ID_9PIN_DIN,
496 CONNECTOR_OBJECT_ID_DISPLAYPORT,
497 CONNECTOR_OBJECT_ID_HDMI_TYPE_A,
498 CONNECTOR_OBJECT_ID_HDMI_TYPE_B,
499 CONNECTOR_OBJECT_ID_SVIDEO
500};
501
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200502const int object_connector_convert[] = {
503 DRM_MODE_CONNECTOR_Unknown,
504 DRM_MODE_CONNECTOR_DVII,
505 DRM_MODE_CONNECTOR_DVII,
506 DRM_MODE_CONNECTOR_DVID,
507 DRM_MODE_CONNECTOR_DVID,
508 DRM_MODE_CONNECTOR_VGA,
509 DRM_MODE_CONNECTOR_Composite,
510 DRM_MODE_CONNECTOR_SVIDEO,
511 DRM_MODE_CONNECTOR_Unknown,
Alex Deucher705af9c2009-09-10 16:31:13 -0400512 DRM_MODE_CONNECTOR_Unknown,
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200513 DRM_MODE_CONNECTOR_9PinDIN,
514 DRM_MODE_CONNECTOR_Unknown,
515 DRM_MODE_CONNECTOR_HDMIA,
516 DRM_MODE_CONNECTOR_HDMIB,
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200517 DRM_MODE_CONNECTOR_LVDS,
518 DRM_MODE_CONNECTOR_9PinDIN,
519 DRM_MODE_CONNECTOR_Unknown,
520 DRM_MODE_CONNECTOR_Unknown,
521 DRM_MODE_CONNECTOR_Unknown,
Alex Deucher196c58d2010-01-07 14:22:32 -0500522 DRM_MODE_CONNECTOR_DisplayPort,
523 DRM_MODE_CONNECTOR_eDP,
524 DRM_MODE_CONNECTOR_Unknown
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200525};
526
527bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
528{
529 struct radeon_device *rdev = dev->dev_private;
530 struct radeon_mode_info *mode_info = &rdev->mode_info;
531 struct atom_context *ctx = mode_info->atom_context;
532 int index = GetIndexIntoMasterTable(DATA, Object_Header);
Alex Deuchereed45b32009-12-04 14:45:27 -0500533 u16 size, data_offset;
534 u8 frev, crev;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200535 ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
Alex Deucher36868bd2011-01-06 21:19:21 -0500536 ATOM_ENCODER_OBJECT_TABLE *enc_obj;
Alex Deucher26b5bc92010-08-05 21:21:18 -0400537 ATOM_OBJECT_TABLE *router_obj;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200538 ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
539 ATOM_OBJECT_HEADER *obj_header;
Alex Deucher26b5bc92010-08-05 21:21:18 -0400540 int i, j, k, path_size, device_support;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200541 int connector_type;
Alex Deuchereed45b32009-12-04 14:45:27 -0500542 u16 igp_lane_info, conn_id, connector_object_id;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200543 struct radeon_i2c_bus_rec ddc_bus;
Alex Deucher26b5bc92010-08-05 21:21:18 -0400544 struct radeon_router router;
Alex Deuchereed45b32009-12-04 14:45:27 -0500545 struct radeon_gpio_rec gpio;
546 struct radeon_hpd hpd;
547
Alex Deuchera084e6e2010-03-18 01:04:01 -0400548 if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200549 return false;
550
551 if (crev < 2)
552 return false;
553
554 obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
555 path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
556 (ctx->bios + data_offset +
557 le16_to_cpu(obj_header->usDisplayPathTableOffset));
558 con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
559 (ctx->bios + data_offset +
560 le16_to_cpu(obj_header->usConnectorObjectTableOffset));
Alex Deucher36868bd2011-01-06 21:19:21 -0500561 enc_obj = (ATOM_ENCODER_OBJECT_TABLE *)
562 (ctx->bios + data_offset +
563 le16_to_cpu(obj_header->usEncoderObjectTableOffset));
Alex Deucher26b5bc92010-08-05 21:21:18 -0400564 router_obj = (ATOM_OBJECT_TABLE *)
565 (ctx->bios + data_offset +
566 le16_to_cpu(obj_header->usRouterObjectTableOffset));
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200567 device_support = le16_to_cpu(obj_header->usDeviceSupport);
568
569 path_size = 0;
570 for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
571 uint8_t *addr = (uint8_t *) path_obj->asDispPath;
572 ATOM_DISPLAY_OBJECT_PATH *path;
573 addr += path_size;
574 path = (ATOM_DISPLAY_OBJECT_PATH *) addr;
575 path_size += le16_to_cpu(path->usSize);
Alex Deucher5137ee92010-08-12 18:58:47 -0400576
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200577 if (device_support & le16_to_cpu(path->usDeviceTag)) {
578 uint8_t con_obj_id, con_obj_num, con_obj_type;
579
580 con_obj_id =
581 (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK)
582 >> OBJECT_ID_SHIFT;
583 con_obj_num =
584 (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK)
585 >> ENUM_ID_SHIFT;
586 con_obj_type =
587 (le16_to_cpu(path->usConnObjectId) &
588 OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
589
Dave Airlie4bbd4972009-09-25 08:56:12 +1000590 /* TODO CV support */
591 if (le16_to_cpu(path->usDeviceTag) ==
592 ATOM_DEVICE_CV_SUPPORT)
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200593 continue;
594
Alex Deucheree59f2b2009-11-05 13:11:46 -0500595 /* IGP chips */
596 if ((rdev->flags & RADEON_IS_IGP) &&
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200597 (con_obj_id ==
598 CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
599 uint16_t igp_offset = 0;
600 ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj;
601
602 index =
603 GetIndexIntoMasterTable(DATA,
604 IntegratedSystemInfo);
605
Alex Deuchera084e6e2010-03-18 01:04:01 -0400606 if (atom_parse_data_header(ctx, index, &size, &frev,
607 &crev, &igp_offset)) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200608
Alex Deuchera084e6e2010-03-18 01:04:01 -0400609 if (crev >= 2) {
610 igp_obj =
611 (ATOM_INTEGRATED_SYSTEM_INFO_V2
612 *) (ctx->bios + igp_offset);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200613
Alex Deuchera084e6e2010-03-18 01:04:01 -0400614 if (igp_obj) {
615 uint32_t slot_config, ct;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200616
Alex Deuchera084e6e2010-03-18 01:04:01 -0400617 if (con_obj_num == 1)
618 slot_config =
619 igp_obj->
620 ulDDISlot1Config;
621 else
622 slot_config =
623 igp_obj->
624 ulDDISlot2Config;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200625
Alex Deuchera084e6e2010-03-18 01:04:01 -0400626 ct = (slot_config >> 16) & 0xff;
627 connector_type =
628 object_connector_convert
629 [ct];
630 connector_object_id = ct;
631 igp_lane_info =
632 slot_config & 0xffff;
633 } else
634 continue;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200635 } else
636 continue;
Alex Deuchera084e6e2010-03-18 01:04:01 -0400637 } else {
638 igp_lane_info = 0;
639 connector_type =
640 object_connector_convert[con_obj_id];
641 connector_object_id = con_obj_id;
642 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200643 } else {
644 igp_lane_info = 0;
645 connector_type =
646 object_connector_convert[con_obj_id];
Alex Deucherb75fad02009-11-05 13:16:01 -0500647 connector_object_id = con_obj_id;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200648 }
649
650 if (connector_type == DRM_MODE_CONNECTOR_Unknown)
651 continue;
652
Tyson Whiteheadbdd91b22010-11-08 16:08:30 +0000653 router.ddc_valid = false;
654 router.cd_valid = false;
Alex Deucher26b5bc92010-08-05 21:21:18 -0400655 for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
656 uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200657
Alex Deucher26b5bc92010-08-05 21:21:18 -0400658 grph_obj_id =
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200659 (le16_to_cpu(path->usGraphicObjIds[j]) &
660 OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
Alex Deucher26b5bc92010-08-05 21:21:18 -0400661 grph_obj_num =
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200662 (le16_to_cpu(path->usGraphicObjIds[j]) &
663 ENUM_ID_MASK) >> ENUM_ID_SHIFT;
Alex Deucher26b5bc92010-08-05 21:21:18 -0400664 grph_obj_type =
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200665 (le16_to_cpu(path->usGraphicObjIds[j]) &
666 OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
667
Alex Deucher26b5bc92010-08-05 21:21:18 -0400668 if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
Alex Deucher36868bd2011-01-06 21:19:21 -0500669 for (k = 0; k < enc_obj->ucNumberOfObjects; k++) {
670 u16 encoder_obj = le16_to_cpu(enc_obj->asObjects[k].usObjectID);
671 if (le16_to_cpu(path->usGraphicObjIds[j]) == encoder_obj) {
672 ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
673 (ctx->bios + data_offset +
674 le16_to_cpu(enc_obj->asObjects[k].usRecordOffset));
675 ATOM_ENCODER_CAP_RECORD *cap_record;
676 u16 caps = 0;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200677
John Lindgren97ea5302011-03-24 23:28:31 +0000678 while (record->ucRecordSize > 0 &&
679 record->ucRecordType > 0 &&
Alex Deucher36868bd2011-01-06 21:19:21 -0500680 record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
681 switch (record->ucRecordType) {
682 case ATOM_ENCODER_CAP_RECORD_TYPE:
683 cap_record =(ATOM_ENCODER_CAP_RECORD *)
684 record;
685 caps = le16_to_cpu(cap_record->usEncoderCap);
686 break;
687 }
688 record = (ATOM_COMMON_RECORD_HEADER *)
689 ((char *)record + record->ucRecordSize);
690 }
691 radeon_add_atom_encoder(dev,
692 encoder_obj,
693 le16_to_cpu
694 (path->
695 usDeviceTag),
696 caps);
697 }
698 }
Alex Deucher26b5bc92010-08-05 21:21:18 -0400699 } else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
Alex Deucher26b5bc92010-08-05 21:21:18 -0400700 for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
Tyson Whiteheadbdd91b22010-11-08 16:08:30 +0000701 u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID);
Alex Deucher26b5bc92010-08-05 21:21:18 -0400702 if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
703 ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
704 (ctx->bios + data_offset +
705 le16_to_cpu(router_obj->asObjects[k].usRecordOffset));
706 ATOM_I2C_RECORD *i2c_record;
707 ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
708 ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
Alex Deucherfb939df2010-11-08 16:08:29 +0000709 ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path;
Alex Deucher26b5bc92010-08-05 21:21:18 -0400710 ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
711 (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
712 (ctx->bios + data_offset +
713 le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset));
Alex Deucherfb93df12013-08-27 12:36:01 -0400714 u8 *num_dst_objs = (u8 *)
715 ((u8 *)router_src_dst_table + 1 +
716 (router_src_dst_table->ucNumberOfSrc * 2));
717 u16 *dst_objs = (u16 *)(num_dst_objs + 1);
Alex Deucher26b5bc92010-08-05 21:21:18 -0400718 int enum_id;
719
720 router.router_id = router_obj_id;
Alex Deucherfb93df12013-08-27 12:36:01 -0400721 for (enum_id = 0; enum_id < (*num_dst_objs); enum_id++) {
Alex Deucher26b5bc92010-08-05 21:21:18 -0400722 if (le16_to_cpu(path->usConnObjectId) ==
Alex Deucherfb93df12013-08-27 12:36:01 -0400723 le16_to_cpu(dst_objs[enum_id]))
Alex Deucher26b5bc92010-08-05 21:21:18 -0400724 break;
725 }
726
John Lindgren97ea5302011-03-24 23:28:31 +0000727 while (record->ucRecordSize > 0 &&
728 record->ucRecordType > 0 &&
Alex Deucher26b5bc92010-08-05 21:21:18 -0400729 record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
730 switch (record->ucRecordType) {
731 case ATOM_I2C_RECORD_TYPE:
732 i2c_record =
733 (ATOM_I2C_RECORD *)
734 record;
735 i2c_config =
736 (ATOM_I2C_ID_CONFIG_ACCESS *)
737 &i2c_record->sucI2cId;
738 router.i2c_info =
739 radeon_lookup_i2c_gpio(rdev,
740 i2c_config->
741 ucAccess);
742 router.i2c_addr = i2c_record->ucI2CAddr >> 1;
743 break;
744 case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
745 ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
746 record;
Alex Deucherfb939df2010-11-08 16:08:29 +0000747 router.ddc_valid = true;
748 router.ddc_mux_type = ddc_path->ucMuxType;
749 router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;
750 router.ddc_mux_state = ddc_path->ucMuxState[enum_id];
751 break;
752 case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
753 cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)
754 record;
755 router.cd_valid = true;
756 router.cd_mux_type = cd_path->ucMuxType;
757 router.cd_mux_control_pin = cd_path->ucMuxControlPin;
758 router.cd_mux_state = cd_path->ucMuxState[enum_id];
Alex Deucher26b5bc92010-08-05 21:21:18 -0400759 break;
760 }
761 record = (ATOM_COMMON_RECORD_HEADER *)
762 ((char *)record + record->ucRecordSize);
763 }
764 }
765 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200766 }
767 }
768
Alex Deuchereed45b32009-12-04 14:45:27 -0500769 /* look up gpio for ddc, hpd */
Alex Deucher2bfcc0f2010-05-18 19:26:46 -0400770 ddc_bus.valid = false;
771 hpd.hpd = RADEON_HPD_NONE;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200772 if ((le16_to_cpu(path->usDeviceTag) &
Alex Deuchereed45b32009-12-04 14:45:27 -0500773 (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200774 for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
775 if (le16_to_cpu(path->usConnObjectId) ==
776 le16_to_cpu(con_obj->asObjects[j].
777 usObjectID)) {
778 ATOM_COMMON_RECORD_HEADER
779 *record =
780 (ATOM_COMMON_RECORD_HEADER
781 *)
782 (ctx->bios + data_offset +
783 le16_to_cpu(con_obj->
784 asObjects[j].
785 usRecordOffset));
786 ATOM_I2C_RECORD *i2c_record;
Alex Deuchereed45b32009-12-04 14:45:27 -0500787 ATOM_HPD_INT_RECORD *hpd_record;
Alex Deucherd3f420d2009-12-08 14:30:49 -0500788 ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
Alex Deucher6a93cb22009-11-23 17:39:28 -0500789
John Lindgren97ea5302011-03-24 23:28:31 +0000790 while (record->ucRecordSize > 0 &&
791 record->ucRecordType > 0 &&
792 record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
Alex Deuchereed45b32009-12-04 14:45:27 -0500793 switch (record->ucRecordType) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200794 case ATOM_I2C_RECORD_TYPE:
795 i2c_record =
Alex Deuchereed45b32009-12-04 14:45:27 -0500796 (ATOM_I2C_RECORD *)
797 record;
Alex Deucherd3f420d2009-12-08 14:30:49 -0500798 i2c_config =
799 (ATOM_I2C_ID_CONFIG_ACCESS *)
800 &i2c_record->sucI2cId;
Alex Deuchereed45b32009-12-04 14:45:27 -0500801 ddc_bus = radeon_lookup_i2c_gpio(rdev,
Alex Deucherd3f420d2009-12-08 14:30:49 -0500802 i2c_config->
803 ucAccess);
Alex Deuchereed45b32009-12-04 14:45:27 -0500804 break;
805 case ATOM_HPD_INT_RECORD_TYPE:
806 hpd_record =
807 (ATOM_HPD_INT_RECORD *)
808 record;
809 gpio = radeon_lookup_gpio(rdev,
810 hpd_record->ucHPDIntGPIOID);
811 hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
812 hpd.plugged_state = hpd_record->ucPlugged_PinState;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200813 break;
814 }
815 record =
816 (ATOM_COMMON_RECORD_HEADER
817 *) ((char *)record
818 +
819 record->
820 ucRecordSize);
821 }
822 break;
823 }
824 }
Alex Deuchereed45b32009-12-04 14:45:27 -0500825 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200826
Alex Deucherbcc1c2a2010-01-12 17:54:34 -0500827 /* needed for aux chan transactions */
Alex Deucher8e36ed02010-05-18 19:26:47 -0400828 ddc_bus.hpd = hpd.hpd;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -0500829
Alex Deucher705af9c2009-09-10 16:31:13 -0400830 conn_id = le16_to_cpu(path->usConnObjectId);
831
832 if (!radeon_atom_apply_quirks
833 (dev, le16_to_cpu(path->usDeviceTag), &connector_type,
Alex Deuchereed45b32009-12-04 14:45:27 -0500834 &ddc_bus, &conn_id, &hpd))
Alex Deucher705af9c2009-09-10 16:31:13 -0400835 continue;
836
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200837 radeon_add_atom_connector(dev,
Alex Deucher705af9c2009-09-10 16:31:13 -0400838 conn_id,
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200839 le16_to_cpu(path->
840 usDeviceTag),
841 connector_type, &ddc_bus,
Alex Deucher5137ee92010-08-12 18:58:47 -0400842 igp_lane_info,
Alex Deuchereed45b32009-12-04 14:45:27 -0500843 connector_object_id,
Alex Deucher26b5bc92010-08-05 21:21:18 -0400844 &hpd,
845 &router);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200846
847 }
848 }
849
850 radeon_link_encoder_connector(dev);
851
852 return true;
853}
854
Alex Deucherb75fad02009-11-05 13:16:01 -0500855static uint16_t atombios_get_connector_object_id(struct drm_device *dev,
856 int connector_type,
857 uint16_t devices)
858{
859 struct radeon_device *rdev = dev->dev_private;
860
861 if (rdev->flags & RADEON_IS_IGP) {
862 return supported_devices_connector_object_id_convert
863 [connector_type];
864 } else if (((connector_type == DRM_MODE_CONNECTOR_DVII) ||
865 (connector_type == DRM_MODE_CONNECTOR_DVID)) &&
866 (devices & ATOM_DEVICE_DFP2_SUPPORT)) {
867 struct radeon_mode_info *mode_info = &rdev->mode_info;
868 struct atom_context *ctx = mode_info->atom_context;
869 int index = GetIndexIntoMasterTable(DATA, XTMDS_Info);
870 uint16_t size, data_offset;
871 uint8_t frev, crev;
872 ATOM_XTMDS_INFO *xtmds;
873
Alex Deuchera084e6e2010-03-18 01:04:01 -0400874 if (atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) {
875 xtmds = (ATOM_XTMDS_INFO *)(ctx->bios + data_offset);
Alex Deucherb75fad02009-11-05 13:16:01 -0500876
Alex Deuchera084e6e2010-03-18 01:04:01 -0400877 if (xtmds->ucSupportedLink & ATOM_XTMDS_SUPPORTED_DUALLINK) {
878 if (connector_type == DRM_MODE_CONNECTOR_DVII)
879 return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I;
880 else
881 return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D;
882 } else {
883 if (connector_type == DRM_MODE_CONNECTOR_DVII)
884 return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I;
885 else
886 return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D;
887 }
888 } else
889 return supported_devices_connector_object_id_convert
890 [connector_type];
Alex Deucherb75fad02009-11-05 13:16:01 -0500891 } else {
892 return supported_devices_connector_object_id_convert
893 [connector_type];
894 }
895}
896
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200897struct bios_connector {
898 bool valid;
Alex Deucher705af9c2009-09-10 16:31:13 -0400899 uint16_t line_mux;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200900 uint16_t devices;
901 int connector_type;
902 struct radeon_i2c_bus_rec ddc_bus;
Alex Deuchereed45b32009-12-04 14:45:27 -0500903 struct radeon_hpd hpd;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200904};
905
906bool radeon_get_atom_connector_info_from_supported_devices_table(struct
907 drm_device
908 *dev)
909{
910 struct radeon_device *rdev = dev->dev_private;
911 struct radeon_mode_info *mode_info = &rdev->mode_info;
912 struct atom_context *ctx = mode_info->atom_context;
913 int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo);
914 uint16_t size, data_offset;
915 uint8_t frev, crev;
916 uint16_t device_support;
917 uint8_t dac;
918 union atom_supported_devices *supported_devices;
Alex Deuchereed45b32009-12-04 14:45:27 -0500919 int i, j, max_device;
Prarit Bhargavaf49d2732010-05-24 10:24:07 +1000920 struct bios_connector *bios_connectors;
921 size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
Alex Deucher26b5bc92010-08-05 21:21:18 -0400922 struct radeon_router router;
923
Alex Deucherfb939df2010-11-08 16:08:29 +0000924 router.ddc_valid = false;
925 router.cd_valid = false;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200926
Prarit Bhargavaf49d2732010-05-24 10:24:07 +1000927 bios_connectors = kzalloc(bc_size, GFP_KERNEL);
928 if (!bios_connectors)
Alex Deuchera084e6e2010-03-18 01:04:01 -0400929 return false;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200930
Prarit Bhargavaf49d2732010-05-24 10:24:07 +1000931 if (!atom_parse_data_header(ctx, index, &size, &frev, &crev,
932 &data_offset)) {
933 kfree(bios_connectors);
934 return false;
935 }
936
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200937 supported_devices =
938 (union atom_supported_devices *)(ctx->bios + data_offset);
939
940 device_support = le16_to_cpu(supported_devices->info.usDeviceSupport);
941
Alex Deuchereed45b32009-12-04 14:45:27 -0500942 if (frev > 1)
943 max_device = ATOM_MAX_SUPPORTED_DEVICE;
944 else
945 max_device = ATOM_MAX_SUPPORTED_DEVICE_INFO;
946
947 for (i = 0; i < max_device; i++) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200948 ATOM_CONNECTOR_INFO_I2C ci =
949 supported_devices->info.asConnInfo[i];
950
951 bios_connectors[i].valid = false;
952
953 if (!(device_support & (1 << i))) {
954 continue;
955 }
956
957 if (i == ATOM_DEVICE_CV_INDEX) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +1000958 DRM_DEBUG_KMS("Skipping Component Video\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200959 continue;
960 }
961
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200962 bios_connectors[i].connector_type =
963 supported_devices_connector_convert[ci.sucConnectorInfo.
964 sbfAccess.
965 bfConnectorType];
966
967 if (bios_connectors[i].connector_type ==
968 DRM_MODE_CONNECTOR_Unknown)
969 continue;
970
971 dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC;
972
Alex Deucherd3f420d2009-12-08 14:30:49 -0500973 bios_connectors[i].line_mux =
974 ci.sucI2cId.ucAccess;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200975
976 /* give tv unique connector ids */
977 if (i == ATOM_DEVICE_TV1_INDEX) {
978 bios_connectors[i].ddc_bus.valid = false;
979 bios_connectors[i].line_mux = 50;
980 } else if (i == ATOM_DEVICE_TV2_INDEX) {
981 bios_connectors[i].ddc_bus.valid = false;
982 bios_connectors[i].line_mux = 51;
983 } else if (i == ATOM_DEVICE_CV_INDEX) {
984 bios_connectors[i].ddc_bus.valid = false;
985 bios_connectors[i].line_mux = 52;
986 } else
987 bios_connectors[i].ddc_bus =
Alex Deuchereed45b32009-12-04 14:45:27 -0500988 radeon_lookup_i2c_gpio(rdev,
989 bios_connectors[i].line_mux);
990
991 if ((crev > 1) && (frev > 1)) {
992 u8 isb = supported_devices->info_2d1.asIntSrcInfo[i].ucIntSrcBitmap;
993 switch (isb) {
994 case 0x4:
995 bios_connectors[i].hpd.hpd = RADEON_HPD_1;
996 break;
997 case 0xa:
998 bios_connectors[i].hpd.hpd = RADEON_HPD_2;
999 break;
1000 default:
1001 bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
1002 break;
1003 }
1004 } else {
1005 if (i == ATOM_DEVICE_DFP1_INDEX)
1006 bios_connectors[i].hpd.hpd = RADEON_HPD_1;
1007 else if (i == ATOM_DEVICE_DFP2_INDEX)
1008 bios_connectors[i].hpd.hpd = RADEON_HPD_2;
1009 else
1010 bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
1011 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001012
1013 /* Always set the connector type to VGA for CRT1/CRT2. if they are
1014 * shared with a DVI port, we'll pick up the DVI connector when we
1015 * merge the outputs. Some bioses incorrectly list VGA ports as DVI.
1016 */
1017 if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX)
1018 bios_connectors[i].connector_type =
1019 DRM_MODE_CONNECTOR_VGA;
1020
1021 if (!radeon_atom_apply_quirks
1022 (dev, (1 << i), &bios_connectors[i].connector_type,
Alex Deuchereed45b32009-12-04 14:45:27 -05001023 &bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux,
1024 &bios_connectors[i].hpd))
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001025 continue;
1026
1027 bios_connectors[i].valid = true;
1028 bios_connectors[i].devices = (1 << i);
1029
1030 if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom)
1031 radeon_add_atom_encoder(dev,
Alex Deucher5137ee92010-08-12 18:58:47 -04001032 radeon_get_encoder_enum(dev,
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001033 (1 << i),
1034 dac),
Alex Deucher36868bd2011-01-06 21:19:21 -05001035 (1 << i),
1036 0);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001037 else
1038 radeon_add_legacy_encoder(dev,
Alex Deucher5137ee92010-08-12 18:58:47 -04001039 radeon_get_encoder_enum(dev,
Alex Deucherf56cd642009-12-18 11:28:22 -05001040 (1 << i),
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001041 dac),
1042 (1 << i));
1043 }
1044
1045 /* combine shared connectors */
Alex Deuchereed45b32009-12-04 14:45:27 -05001046 for (i = 0; i < max_device; i++) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001047 if (bios_connectors[i].valid) {
Alex Deuchereed45b32009-12-04 14:45:27 -05001048 for (j = 0; j < max_device; j++) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001049 if (bios_connectors[j].valid && (i != j)) {
1050 if (bios_connectors[i].line_mux ==
1051 bios_connectors[j].line_mux) {
Alex Deucherf56cd642009-12-18 11:28:22 -05001052 /* make sure not to combine LVDS */
1053 if (bios_connectors[i].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1054 bios_connectors[i].line_mux = 53;
1055 bios_connectors[i].ddc_bus.valid = false;
1056 continue;
1057 }
1058 if (bios_connectors[j].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1059 bios_connectors[j].line_mux = 53;
1060 bios_connectors[j].ddc_bus.valid = false;
1061 continue;
1062 }
1063 /* combine analog and digital for DVI-I */
1064 if (((bios_connectors[i].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
1065 (bios_connectors[j].devices & (ATOM_DEVICE_CRT_SUPPORT))) ||
1066 ((bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
1067 (bios_connectors[i].devices & (ATOM_DEVICE_CRT_SUPPORT)))) {
1068 bios_connectors[i].devices |=
1069 bios_connectors[j].devices;
1070 bios_connectors[i].connector_type =
1071 DRM_MODE_CONNECTOR_DVII;
1072 if (bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT))
Alex Deuchereed45b32009-12-04 14:45:27 -05001073 bios_connectors[i].hpd =
1074 bios_connectors[j].hpd;
Alex Deucherf56cd642009-12-18 11:28:22 -05001075 bios_connectors[j].valid = false;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001076 }
1077 }
1078 }
1079 }
1080 }
1081 }
1082
1083 /* add the connectors */
Alex Deuchereed45b32009-12-04 14:45:27 -05001084 for (i = 0; i < max_device; i++) {
Alex Deucherb75fad02009-11-05 13:16:01 -05001085 if (bios_connectors[i].valid) {
1086 uint16_t connector_object_id =
1087 atombios_get_connector_object_id(dev,
1088 bios_connectors[i].connector_type,
1089 bios_connectors[i].devices);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001090 radeon_add_atom_connector(dev,
1091 bios_connectors[i].line_mux,
1092 bios_connectors[i].devices,
1093 bios_connectors[i].
1094 connector_type,
1095 &bios_connectors[i].ddc_bus,
Alex Deucher5137ee92010-08-12 18:58:47 -04001096 0,
Alex Deuchereed45b32009-12-04 14:45:27 -05001097 connector_object_id,
Alex Deucher26b5bc92010-08-05 21:21:18 -04001098 &bios_connectors[i].hpd,
1099 &router);
Alex Deucherb75fad02009-11-05 13:16:01 -05001100 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001101 }
1102
1103 radeon_link_encoder_connector(dev);
1104
Prarit Bhargavaf49d2732010-05-24 10:24:07 +10001105 kfree(bios_connectors);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001106 return true;
1107}
1108
1109union firmware_info {
1110 ATOM_FIRMWARE_INFO info;
1111 ATOM_FIRMWARE_INFO_V1_2 info_12;
1112 ATOM_FIRMWARE_INFO_V1_3 info_13;
1113 ATOM_FIRMWARE_INFO_V1_4 info_14;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001114 ATOM_FIRMWARE_INFO_V2_1 info_21;
Alex Deucherf82b3dd2011-01-06 21:19:15 -05001115 ATOM_FIRMWARE_INFO_V2_2 info_22;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001116};
1117
1118bool radeon_atom_get_clock_info(struct drm_device *dev)
1119{
1120 struct radeon_device *rdev = dev->dev_private;
1121 struct radeon_mode_info *mode_info = &rdev->mode_info;
1122 int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
1123 union firmware_info *firmware_info;
1124 uint8_t frev, crev;
1125 struct radeon_pll *p1pll = &rdev->clock.p1pll;
1126 struct radeon_pll *p2pll = &rdev->clock.p2pll;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001127 struct radeon_pll *dcpll = &rdev->clock.dcpll;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001128 struct radeon_pll *spll = &rdev->clock.spll;
1129 struct radeon_pll *mpll = &rdev->clock.mpll;
1130 uint16_t data_offset;
1131
Alex Deuchera084e6e2010-03-18 01:04:01 -04001132 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1133 &frev, &crev, &data_offset)) {
1134 firmware_info =
1135 (union firmware_info *)(mode_info->atom_context->bios +
1136 data_offset);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001137 /* pixel clocks */
1138 p1pll->reference_freq =
1139 le16_to_cpu(firmware_info->info.usReferenceClock);
1140 p1pll->reference_div = 0;
1141
Mathias Fröhlichbc293e52009-10-19 17:49:49 -04001142 if (crev < 2)
1143 p1pll->pll_out_min =
1144 le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
1145 else
1146 p1pll->pll_out_min =
1147 le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001148 p1pll->pll_out_max =
1149 le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
1150
Alex Deucher86cb2bb2010-03-08 12:55:16 -05001151 if (crev >= 4) {
1152 p1pll->lcd_pll_out_min =
1153 le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
1154 if (p1pll->lcd_pll_out_min == 0)
1155 p1pll->lcd_pll_out_min = p1pll->pll_out_min;
1156 p1pll->lcd_pll_out_max =
1157 le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
1158 if (p1pll->lcd_pll_out_max == 0)
1159 p1pll->lcd_pll_out_max = p1pll->pll_out_max;
1160 } else {
1161 p1pll->lcd_pll_out_min = p1pll->pll_out_min;
1162 p1pll->lcd_pll_out_max = p1pll->pll_out_max;
1163 }
1164
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001165 if (p1pll->pll_out_min == 0) {
1166 if (ASIC_IS_AVIVO(rdev))
1167 p1pll->pll_out_min = 64800;
1168 else
1169 p1pll->pll_out_min = 20000;
1170 }
1171
1172 p1pll->pll_in_min =
1173 le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input);
1174 p1pll->pll_in_max =
1175 le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input);
1176
1177 *p2pll = *p1pll;
1178
1179 /* system clock */
Alex Deucherf82b3dd2011-01-06 21:19:15 -05001180 if (ASIC_IS_DCE4(rdev))
1181 spll->reference_freq =
1182 le16_to_cpu(firmware_info->info_21.usCoreReferenceClock);
1183 else
1184 spll->reference_freq =
1185 le16_to_cpu(firmware_info->info.usReferenceClock);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001186 spll->reference_div = 0;
1187
1188 spll->pll_out_min =
1189 le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output);
1190 spll->pll_out_max =
1191 le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output);
1192
1193 /* ??? */
1194 if (spll->pll_out_min == 0) {
1195 if (ASIC_IS_AVIVO(rdev))
1196 spll->pll_out_min = 64800;
1197 else
1198 spll->pll_out_min = 20000;
1199 }
1200
1201 spll->pll_in_min =
1202 le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input);
1203 spll->pll_in_max =
1204 le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input);
1205
1206 /* memory clock */
Alex Deucherf82b3dd2011-01-06 21:19:15 -05001207 if (ASIC_IS_DCE4(rdev))
1208 mpll->reference_freq =
1209 le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock);
1210 else
1211 mpll->reference_freq =
1212 le16_to_cpu(firmware_info->info.usReferenceClock);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001213 mpll->reference_div = 0;
1214
1215 mpll->pll_out_min =
1216 le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output);
1217 mpll->pll_out_max =
1218 le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output);
1219
1220 /* ??? */
1221 if (mpll->pll_out_min == 0) {
1222 if (ASIC_IS_AVIVO(rdev))
1223 mpll->pll_out_min = 64800;
1224 else
1225 mpll->pll_out_min = 20000;
1226 }
1227
1228 mpll->pll_in_min =
1229 le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input);
1230 mpll->pll_in_max =
1231 le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input);
1232
1233 rdev->clock.default_sclk =
1234 le32_to_cpu(firmware_info->info.ulDefaultEngineClock);
1235 rdev->clock.default_mclk =
1236 le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);
1237
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001238 if (ASIC_IS_DCE4(rdev)) {
1239 rdev->clock.default_dispclk =
1240 le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);
Alex Deucherf82b3dd2011-01-06 21:19:15 -05001241 if (rdev->clock.default_dispclk == 0) {
1242 if (ASIC_IS_DCE5(rdev))
1243 rdev->clock.default_dispclk = 54000; /* 540 Mhz */
1244 else
1245 rdev->clock.default_dispclk = 60000; /* 600 Mhz */
1246 }
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001247 rdev->clock.dp_extclk =
1248 le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
Alex Deucher4489cd622013-03-22 15:59:10 -04001249 rdev->clock.current_dispclk = rdev->clock.default_dispclk;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001250 }
1251 *dcpll = *p1pll;
1252
Alex Deucherb20f9be2011-06-08 13:01:11 -04001253 rdev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock);
1254 if (rdev->clock.max_pixel_clock == 0)
1255 rdev->clock.max_pixel_clock = 40000;
1256
Alex Deucheraf7912e2012-07-26 09:50:57 -04001257 /* not technically a clock, but... */
1258 rdev->mode_info.firmware_flags =
1259 le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);
1260
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001261 return true;
1262 }
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001263
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001264 return false;
1265}
1266
Alex Deucher06b64762010-01-05 11:27:29 -05001267union igp_info {
1268 struct _ATOM_INTEGRATED_SYSTEM_INFO info;
1269 struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
Alex Deucher3838f462012-07-25 12:32:59 -04001270 struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
1271 struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
Alex Deucherc2037ad2012-07-25 12:45:16 -04001272 struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
Alex Deucher06b64762010-01-05 11:27:29 -05001273};
1274
1275bool radeon_atombios_sideport_present(struct radeon_device *rdev)
1276{
1277 struct radeon_mode_info *mode_info = &rdev->mode_info;
1278 int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1279 union igp_info *igp_info;
1280 u8 frev, crev;
1281 u16 data_offset;
1282
Alex Deucher4c70b2e2010-08-02 19:39:15 -04001283 /* sideport is AMD only */
1284 if (rdev->family == CHIP_RS600)
1285 return false;
1286
Alex Deuchera084e6e2010-03-18 01:04:01 -04001287 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1288 &frev, &crev, &data_offset)) {
1289 igp_info = (union igp_info *)(mode_info->atom_context->bios +
Alex Deucher06b64762010-01-05 11:27:29 -05001290 data_offset);
Alex Deucher06b64762010-01-05 11:27:29 -05001291 switch (crev) {
1292 case 1:
Cédric Cano45894332011-02-11 19:45:37 -05001293 if (le32_to_cpu(igp_info->info.ulBootUpMemoryClock))
Alex Deucher4c70b2e2010-08-02 19:39:15 -04001294 return true;
Alex Deucher06b64762010-01-05 11:27:29 -05001295 break;
1296 case 2:
Cédric Cano45894332011-02-11 19:45:37 -05001297 if (le32_to_cpu(igp_info->info_2.ulBootUpSidePortClock))
Alex Deucher06b64762010-01-05 11:27:29 -05001298 return true;
1299 break;
1300 default:
1301 DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
1302 break;
1303 }
1304 }
1305 return false;
1306}
1307
Dave Airlie445282d2009-09-09 17:40:54 +10001308bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,
1309 struct radeon_encoder_int_tmds *tmds)
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001310{
1311 struct drm_device *dev = encoder->base.dev;
1312 struct radeon_device *rdev = dev->dev_private;
1313 struct radeon_mode_info *mode_info = &rdev->mode_info;
1314 int index = GetIndexIntoMasterTable(DATA, TMDS_Info);
1315 uint16_t data_offset;
1316 struct _ATOM_TMDS_INFO *tmds_info;
1317 uint8_t frev, crev;
1318 uint16_t maxfreq;
1319 int i;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001320
Alex Deuchera084e6e2010-03-18 01:04:01 -04001321 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1322 &frev, &crev, &data_offset)) {
1323 tmds_info =
1324 (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios +
1325 data_offset);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001326
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001327 maxfreq = le16_to_cpu(tmds_info->usMaxFrequency);
1328 for (i = 0; i < 4; i++) {
1329 tmds->tmds_pll[i].freq =
1330 le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency);
1331 tmds->tmds_pll[i].value =
1332 tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f;
1333 tmds->tmds_pll[i].value |=
1334 (tmds_info->asMiscInfo[i].
1335 ucPLL_VCO_Gain & 0x3f) << 6;
1336 tmds->tmds_pll[i].value |=
1337 (tmds_info->asMiscInfo[i].
1338 ucPLL_DutyCycle & 0xf) << 12;
1339 tmds->tmds_pll[i].value |=
1340 (tmds_info->asMiscInfo[i].
1341 ucPLL_VoltageSwing & 0xf) << 16;
1342
Dave Airlied9fdaaf2010-08-02 10:42:55 +10001343 DRM_DEBUG_KMS("TMDS PLL From ATOMBIOS %u %x\n",
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001344 tmds->tmds_pll[i].freq,
1345 tmds->tmds_pll[i].value);
1346
1347 if (maxfreq == tmds->tmds_pll[i].freq) {
1348 tmds->tmds_pll[i].freq = 0xffffffff;
1349 break;
1350 }
1351 }
Dave Airlie445282d2009-09-09 17:40:54 +10001352 return true;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001353 }
Dave Airlie445282d2009-09-09 17:40:54 +10001354 return false;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001355}
1356
Alex Deucherba032a52010-10-04 17:13:01 -04001357bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
1358 struct radeon_atom_ss *ss,
1359 int id)
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001360{
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001361 struct radeon_mode_info *mode_info = &rdev->mode_info;
1362 int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
Alex Deucherba032a52010-10-04 17:13:01 -04001363 uint16_t data_offset, size;
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001364 struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
1365 uint8_t frev, crev;
Alex Deucherba032a52010-10-04 17:13:01 -04001366 int i, num_indices;
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001367
Alex Deucherba032a52010-10-04 17:13:01 -04001368 memset(ss, 0, sizeof(struct radeon_atom_ss));
1369 if (atom_parse_data_header(mode_info->atom_context, index, &size,
Alex Deuchera084e6e2010-03-18 01:04:01 -04001370 &frev, &crev, &data_offset)) {
1371 ss_info =
1372 (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset);
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001373
Alex Deucherba032a52010-10-04 17:13:01 -04001374 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1375 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001376
Alex Deucherba032a52010-10-04 17:13:01 -04001377 for (i = 0; i < num_indices; i++) {
Alex Deucher279b2152009-12-08 14:07:03 -05001378 if (ss_info->asSS_Info[i].ucSS_Id == id) {
1379 ss->percentage =
1380 le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage);
1381 ss->type = ss_info->asSS_Info[i].ucSpreadSpectrumType;
1382 ss->step = ss_info->asSS_Info[i].ucSS_Step;
1383 ss->delay = ss_info->asSS_Info[i].ucSS_Delay;
1384 ss->range = ss_info->asSS_Info[i].ucSS_Range;
1385 ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div;
Alex Deucherba032a52010-10-04 17:13:01 -04001386 return true;
Alex Deucher279b2152009-12-08 14:07:03 -05001387 }
1388 }
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001389 }
Alex Deucherba032a52010-10-04 17:13:01 -04001390 return false;
1391}
1392
Alex Deucher4339c442010-11-22 17:56:25 -05001393static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
1394 struct radeon_atom_ss *ss,
1395 int id)
1396{
1397 struct radeon_mode_info *mode_info = &rdev->mode_info;
1398 int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1399 u16 data_offset, size;
Alex Deucher3838f462012-07-25 12:32:59 -04001400 union igp_info *igp_info;
Alex Deucher4339c442010-11-22 17:56:25 -05001401 u8 frev, crev;
1402 u16 percentage = 0, rate = 0;
1403
1404 /* get any igp specific overrides */
1405 if (atom_parse_data_header(mode_info->atom_context, index, &size,
1406 &frev, &crev, &data_offset)) {
Alex Deucher3838f462012-07-25 12:32:59 -04001407 igp_info = (union igp_info *)
Alex Deucher4339c442010-11-22 17:56:25 -05001408 (mode_info->atom_context->bios + data_offset);
Alex Deucher3838f462012-07-25 12:32:59 -04001409 switch (crev) {
1410 case 6:
1411 switch (id) {
1412 case ASIC_INTERNAL_SS_ON_TMDS:
1413 percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage);
1414 rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz);
1415 break;
1416 case ASIC_INTERNAL_SS_ON_HDMI:
1417 percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage);
1418 rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz);
1419 break;
1420 case ASIC_INTERNAL_SS_ON_LVDS:
1421 percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage);
1422 rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz);
1423 break;
1424 }
Alex Deucher4339c442010-11-22 17:56:25 -05001425 break;
Alex Deucher3838f462012-07-25 12:32:59 -04001426 case 7:
1427 switch (id) {
1428 case ASIC_INTERNAL_SS_ON_TMDS:
1429 percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage);
1430 rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz);
1431 break;
1432 case ASIC_INTERNAL_SS_ON_HDMI:
1433 percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage);
1434 rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz);
1435 break;
1436 case ASIC_INTERNAL_SS_ON_LVDS:
1437 percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage);
1438 rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz);
1439 break;
1440 }
Alex Deucher4339c442010-11-22 17:56:25 -05001441 break;
Alex Deucherc2037ad2012-07-25 12:45:16 -04001442 case 8:
1443 switch (id) {
1444 case ASIC_INTERNAL_SS_ON_TMDS:
1445 percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage);
1446 rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz);
1447 break;
1448 case ASIC_INTERNAL_SS_ON_HDMI:
1449 percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage);
1450 rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz);
1451 break;
1452 case ASIC_INTERNAL_SS_ON_LVDS:
1453 percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage);
1454 rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz);
1455 break;
1456 }
1457 break;
Alex Deucher3838f462012-07-25 12:32:59 -04001458 default:
1459 DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
Alex Deucher4339c442010-11-22 17:56:25 -05001460 break;
1461 }
1462 if (percentage)
1463 ss->percentage = percentage;
1464 if (rate)
1465 ss->rate = rate;
1466 }
1467}
1468
Alex Deucherba032a52010-10-04 17:13:01 -04001469union asic_ss_info {
1470 struct _ATOM_ASIC_INTERNAL_SS_INFO info;
1471 struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
1472 struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
1473};
1474
1475bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
1476 struct radeon_atom_ss *ss,
1477 int id, u32 clock)
1478{
1479 struct radeon_mode_info *mode_info = &rdev->mode_info;
1480 int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
1481 uint16_t data_offset, size;
1482 union asic_ss_info *ss_info;
1483 uint8_t frev, crev;
1484 int i, num_indices;
1485
Alex Deucher9cb84ab2013-08-19 19:06:19 -04001486 if (id == ASIC_INTERNAL_MEMORY_SS) {
1487 if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT))
1488 return false;
1489 }
1490 if (id == ASIC_INTERNAL_ENGINE_SS) {
1491 if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT))
1492 return false;
1493 }
1494
Alex Deucherba032a52010-10-04 17:13:01 -04001495 memset(ss, 0, sizeof(struct radeon_atom_ss));
1496 if (atom_parse_data_header(mode_info->atom_context, index, &size,
1497 &frev, &crev, &data_offset)) {
1498
1499 ss_info =
1500 (union asic_ss_info *)(mode_info->atom_context->bios + data_offset);
1501
1502 switch (frev) {
1503 case 1:
1504 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1505 sizeof(ATOM_ASIC_SS_ASSIGNMENT);
1506
1507 for (i = 0; i < num_indices; i++) {
1508 if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) &&
Cédric Cano45894332011-02-11 19:45:37 -05001509 (clock <= le32_to_cpu(ss_info->info.asSpreadSpectrum[i].ulTargetClockRange))) {
Alex Deucherba032a52010-10-04 17:13:01 -04001510 ss->percentage =
1511 le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
1512 ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
1513 ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz);
1514 return true;
1515 }
1516 }
1517 break;
1518 case 2:
1519 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1520 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1521 for (i = 0; i < num_indices; i++) {
1522 if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) &&
Cédric Cano45894332011-02-11 19:45:37 -05001523 (clock <= le32_to_cpu(ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange))) {
Alex Deucherba032a52010-10-04 17:13:01 -04001524 ss->percentage =
1525 le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
1526 ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
1527 ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
Alex Deucherae5b0ab2013-06-24 10:50:34 -04001528 if ((crev == 2) &&
1529 ((id == ASIC_INTERNAL_ENGINE_SS) ||
1530 (id == ASIC_INTERNAL_MEMORY_SS)))
1531 ss->rate /= 100;
Alex Deucherba032a52010-10-04 17:13:01 -04001532 return true;
1533 }
1534 }
1535 break;
1536 case 3:
1537 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1538 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
1539 for (i = 0; i < num_indices; i++) {
1540 if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) &&
Cédric Cano45894332011-02-11 19:45:37 -05001541 (clock <= le32_to_cpu(ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange))) {
Alex Deucherba032a52010-10-04 17:13:01 -04001542 ss->percentage =
1543 le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
1544 ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
1545 ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
Alex Deucherae5b0ab2013-06-24 10:50:34 -04001546 if ((id == ASIC_INTERNAL_ENGINE_SS) ||
1547 (id == ASIC_INTERNAL_MEMORY_SS))
1548 ss->rate /= 100;
Alex Deucher4339c442010-11-22 17:56:25 -05001549 if (rdev->flags & RADEON_IS_IGP)
1550 radeon_atombios_get_igp_ss_overrides(rdev, ss, id);
Alex Deucherba032a52010-10-04 17:13:01 -04001551 return true;
1552 }
1553 }
1554 break;
1555 default:
1556 DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);
1557 break;
1558 }
1559
1560 }
1561 return false;
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001562}
1563
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001564union lvds_info {
1565 struct _ATOM_LVDS_INFO info;
1566 struct _ATOM_LVDS_INFO_V12 info_12;
1567};
1568
1569struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
1570 radeon_encoder
1571 *encoder)
1572{
1573 struct drm_device *dev = encoder->base.dev;
1574 struct radeon_device *rdev = dev->dev_private;
1575 struct radeon_mode_info *mode_info = &rdev->mode_info;
1576 int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
Alex Deucher7dde8a192009-11-30 01:40:24 -05001577 uint16_t data_offset, misc;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001578 union lvds_info *lvds_info;
1579 uint8_t frev, crev;
1580 struct radeon_encoder_atom_dig *lvds = NULL;
Alex Deucher5137ee92010-08-12 18:58:47 -04001581 int encoder_enum = (encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001582
Alex Deuchera084e6e2010-03-18 01:04:01 -04001583 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1584 &frev, &crev, &data_offset)) {
1585 lvds_info =
1586 (union lvds_info *)(mode_info->atom_context->bios + data_offset);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001587 lvds =
1588 kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL);
1589
1590 if (!lvds)
1591 return NULL;
1592
Alex Deucherde2103e2009-10-09 15:14:30 -04001593 lvds->native_mode.clock =
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001594 le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10;
Alex Deucherde2103e2009-10-09 15:14:30 -04001595 lvds->native_mode.hdisplay =
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001596 le16_to_cpu(lvds_info->info.sLCDTiming.usHActive);
Alex Deucherde2103e2009-10-09 15:14:30 -04001597 lvds->native_mode.vdisplay =
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001598 le16_to_cpu(lvds_info->info.sLCDTiming.usVActive);
Alex Deucherde2103e2009-10-09 15:14:30 -04001599 lvds->native_mode.htotal = lvds->native_mode.hdisplay +
1600 le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
1601 lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
1602 le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
1603 lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
1604 le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);
1605 lvds->native_mode.vtotal = lvds->native_mode.vdisplay +
1606 le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
1607 lvds->native_mode.vsync_start = lvds->native_mode.vdisplay +
Alex Deucher1ff26a32010-05-18 00:23:15 -04001608 le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset);
Alex Deucherde2103e2009-10-09 15:14:30 -04001609 lvds->native_mode.vsync_end = lvds->native_mode.vsync_start +
1610 le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001611 lvds->panel_pwr_delay =
1612 le16_to_cpu(lvds_info->info.usOffDelayInMs);
Alex Deucherba032a52010-10-04 17:13:01 -04001613 lvds->lcd_misc = lvds_info->info.ucLVDS_Misc;
Alex Deucher7dde8a192009-11-30 01:40:24 -05001614
1615 misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess);
1616 if (misc & ATOM_VSYNC_POLARITY)
1617 lvds->native_mode.flags |= DRM_MODE_FLAG_NVSYNC;
1618 if (misc & ATOM_HSYNC_POLARITY)
1619 lvds->native_mode.flags |= DRM_MODE_FLAG_NHSYNC;
1620 if (misc & ATOM_COMPOSITESYNC)
1621 lvds->native_mode.flags |= DRM_MODE_FLAG_CSYNC;
1622 if (misc & ATOM_INTERLACE)
1623 lvds->native_mode.flags |= DRM_MODE_FLAG_INTERLACE;
1624 if (misc & ATOM_DOUBLE_CLOCK_MODE)
1625 lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN;
1626
Cédric Cano45894332011-02-11 19:45:37 -05001627 lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize);
1628 lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize);
Alex Deucher7a868e12010-12-08 22:13:05 -05001629
Alex Deucherde2103e2009-10-09 15:14:30 -04001630 /* set crtc values */
1631 drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001632
Alex Deucherba032a52010-10-04 17:13:01 -04001633 lvds->lcd_ss_id = lvds_info->info.ucSS_Id;
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001634
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001635 encoder->native_mode = lvds->native_mode;
Alex Deucher5137ee92010-08-12 18:58:47 -04001636
1637 if (encoder_enum == 2)
1638 lvds->linkb = true;
1639 else
1640 lvds->linkb = false;
1641
Alex Deucherc324acd2010-12-08 22:13:06 -05001642 /* parse the lcd record table */
Cédric Cano45894332011-02-11 19:45:37 -05001643 if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) {
Alex Deucherc324acd2010-12-08 22:13:06 -05001644 ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
1645 ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
1646 bool bad_record = false;
Alex Deucher05fa7ea2011-05-11 14:02:07 -04001647 u8 *record;
1648
1649 if ((frev == 1) && (crev < 2))
1650 /* absolute */
1651 record = (u8 *)(mode_info->atom_context->bios +
1652 le16_to_cpu(lvds_info->info.usModePatchTableOffset));
1653 else
1654 /* relative */
1655 record = (u8 *)(mode_info->atom_context->bios +
1656 data_offset +
1657 le16_to_cpu(lvds_info->info.usModePatchTableOffset));
Alex Deucherc324acd2010-12-08 22:13:06 -05001658 while (*record != ATOM_RECORD_END_TYPE) {
1659 switch (*record) {
1660 case LCD_MODE_PATCH_RECORD_MODE_TYPE:
1661 record += sizeof(ATOM_PATCH_RECORD_MODE);
1662 break;
1663 case LCD_RTS_RECORD_TYPE:
1664 record += sizeof(ATOM_LCD_RTS_RECORD);
1665 break;
1666 case LCD_CAP_RECORD_TYPE:
1667 record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
1668 break;
1669 case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
1670 fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
1671 if (fake_edid_record->ucFakeEDIDLength) {
1672 struct edid *edid;
1673 int edid_size =
1674 max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength);
1675 edid = kmalloc(edid_size, GFP_KERNEL);
1676 if (edid) {
1677 memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
1678 fake_edid_record->ucFakeEDIDLength);
1679
Dave Airlieeaa4f5e2011-05-01 20:16:30 +10001680 if (drm_edid_is_valid(edid)) {
Alex Deucherc324acd2010-12-08 22:13:06 -05001681 rdev->mode_info.bios_hardcoded_edid = edid;
Dave Airlieeaa4f5e2011-05-01 20:16:30 +10001682 rdev->mode_info.bios_hardcoded_edid_size = edid_size;
1683 } else
Alex Deucherc324acd2010-12-08 22:13:06 -05001684 kfree(edid);
1685 }
1686 }
Alex Deucher95663942013-08-20 14:59:01 -04001687 record += fake_edid_record->ucFakeEDIDLength ?
1688 fake_edid_record->ucFakeEDIDLength + 2 :
1689 sizeof(ATOM_FAKE_EDID_PATCH_RECORD);
Alex Deucherc324acd2010-12-08 22:13:06 -05001690 break;
1691 case LCD_PANEL_RESOLUTION_RECORD_TYPE:
1692 panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
1693 lvds->native_mode.width_mm = panel_res_record->usHSize;
1694 lvds->native_mode.height_mm = panel_res_record->usVSize;
1695 record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
1696 break;
1697 default:
1698 DRM_ERROR("Bad LCD record %d\n", *record);
1699 bad_record = true;
1700 break;
1701 }
1702 if (bad_record)
1703 break;
1704 }
1705 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001706 }
1707 return lvds;
1708}
1709
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001710struct radeon_encoder_primary_dac *
1711radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder)
1712{
1713 struct drm_device *dev = encoder->base.dev;
1714 struct radeon_device *rdev = dev->dev_private;
1715 struct radeon_mode_info *mode_info = &rdev->mode_info;
1716 int index = GetIndexIntoMasterTable(DATA, CompassionateData);
1717 uint16_t data_offset;
1718 struct _COMPASSIONATE_DATA *dac_info;
1719 uint8_t frev, crev;
1720 uint8_t bg, dac;
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001721 struct radeon_encoder_primary_dac *p_dac = NULL;
1722
Alex Deuchera084e6e2010-03-18 01:04:01 -04001723 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1724 &frev, &crev, &data_offset)) {
1725 dac_info = (struct _COMPASSIONATE_DATA *)
1726 (mode_info->atom_context->bios + data_offset);
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001727
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001728 p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), GFP_KERNEL);
1729
1730 if (!p_dac)
1731 return NULL;
1732
1733 bg = dac_info->ucDAC1_BG_Adjustment;
1734 dac = dac_info->ucDAC1_DAC_Adjustment;
1735 p_dac->ps2_pdac_adj = (bg << 8) | (dac);
1736
1737 }
1738 return p_dac;
1739}
1740
Dave Airlie4ce001a2009-08-13 16:32:14 +10001741bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001742 struct drm_display_mode *mode)
Dave Airlie4ce001a2009-08-13 16:32:14 +10001743{
1744 struct radeon_mode_info *mode_info = &rdev->mode_info;
1745 ATOM_ANALOG_TV_INFO *tv_info;
1746 ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
1747 ATOM_DTD_FORMAT *dtd_timings;
1748 int data_index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
1749 u8 frev, crev;
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001750 u16 data_offset, misc;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001751
Alex Deuchera084e6e2010-03-18 01:04:01 -04001752 if (!atom_parse_data_header(mode_info->atom_context, data_index, NULL,
1753 &frev, &crev, &data_offset))
1754 return false;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001755
1756 switch (crev) {
1757 case 1:
1758 tv_info = (ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset);
Dan Carpenter0031c412010-04-27 14:11:04 -07001759 if (index >= MAX_SUPPORTED_TV_TIMING)
Dave Airlie4ce001a2009-08-13 16:32:14 +10001760 return false;
1761
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001762 mode->crtc_htotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
1763 mode->crtc_hdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
1764 mode->crtc_hsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
1765 mode->crtc_hsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) +
1766 le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
Dave Airlie4ce001a2009-08-13 16:32:14 +10001767
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001768 mode->crtc_vtotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
1769 mode->crtc_vdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
1770 mode->crtc_vsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
1771 mode->crtc_vsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) +
1772 le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
Dave Airlie4ce001a2009-08-13 16:32:14 +10001773
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001774 mode->flags = 0;
1775 misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess);
1776 if (misc & ATOM_VSYNC_POLARITY)
1777 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1778 if (misc & ATOM_HSYNC_POLARITY)
1779 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1780 if (misc & ATOM_COMPOSITESYNC)
1781 mode->flags |= DRM_MODE_FLAG_CSYNC;
1782 if (misc & ATOM_INTERLACE)
1783 mode->flags |= DRM_MODE_FLAG_INTERLACE;
1784 if (misc & ATOM_DOUBLE_CLOCK_MODE)
1785 mode->flags |= DRM_MODE_FLAG_DBLSCAN;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001786
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001787 mode->clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001788
1789 if (index == 1) {
1790 /* PAL timings appear to have wrong values for totals */
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001791 mode->crtc_htotal -= 1;
1792 mode->crtc_vtotal -= 1;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001793 }
1794 break;
1795 case 2:
1796 tv_info_v1_2 = (ATOM_ANALOG_TV_INFO_V1_2 *)(mode_info->atom_context->bios + data_offset);
Dan Carpenter0031c412010-04-27 14:11:04 -07001797 if (index >= MAX_SUPPORTED_TV_TIMING_V1_2)
Dave Airlie4ce001a2009-08-13 16:32:14 +10001798 return false;
1799
1800 dtd_timings = &tv_info_v1_2->aModeTimings[index];
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001801 mode->crtc_htotal = le16_to_cpu(dtd_timings->usHActive) +
1802 le16_to_cpu(dtd_timings->usHBlanking_Time);
1803 mode->crtc_hdisplay = le16_to_cpu(dtd_timings->usHActive);
1804 mode->crtc_hsync_start = le16_to_cpu(dtd_timings->usHActive) +
1805 le16_to_cpu(dtd_timings->usHSyncOffset);
1806 mode->crtc_hsync_end = mode->crtc_hsync_start +
1807 le16_to_cpu(dtd_timings->usHSyncWidth);
Dave Airlie4ce001a2009-08-13 16:32:14 +10001808
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001809 mode->crtc_vtotal = le16_to_cpu(dtd_timings->usVActive) +
1810 le16_to_cpu(dtd_timings->usVBlanking_Time);
1811 mode->crtc_vdisplay = le16_to_cpu(dtd_timings->usVActive);
1812 mode->crtc_vsync_start = le16_to_cpu(dtd_timings->usVActive) +
1813 le16_to_cpu(dtd_timings->usVSyncOffset);
1814 mode->crtc_vsync_end = mode->crtc_vsync_start +
1815 le16_to_cpu(dtd_timings->usVSyncWidth);
1816
1817 mode->flags = 0;
1818 misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
1819 if (misc & ATOM_VSYNC_POLARITY)
1820 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1821 if (misc & ATOM_HSYNC_POLARITY)
1822 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1823 if (misc & ATOM_COMPOSITESYNC)
1824 mode->flags |= DRM_MODE_FLAG_CSYNC;
1825 if (misc & ATOM_INTERLACE)
1826 mode->flags |= DRM_MODE_FLAG_INTERLACE;
1827 if (misc & ATOM_DOUBLE_CLOCK_MODE)
1828 mode->flags |= DRM_MODE_FLAG_DBLSCAN;
1829
1830 mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001831 break;
1832 }
1833 return true;
1834}
1835
Alex Deucherd79766f2009-12-17 19:00:29 -05001836enum radeon_tv_std
1837radeon_atombios_get_tv_info(struct radeon_device *rdev)
1838{
1839 struct radeon_mode_info *mode_info = &rdev->mode_info;
1840 int index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
1841 uint16_t data_offset;
1842 uint8_t frev, crev;
1843 struct _ATOM_ANALOG_TV_INFO *tv_info;
1844 enum radeon_tv_std tv_std = TV_STD_NTSC;
1845
Alex Deuchera084e6e2010-03-18 01:04:01 -04001846 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1847 &frev, &crev, &data_offset)) {
Alex Deucherd79766f2009-12-17 19:00:29 -05001848
Alex Deuchera084e6e2010-03-18 01:04:01 -04001849 tv_info = (struct _ATOM_ANALOG_TV_INFO *)
1850 (mode_info->atom_context->bios + data_offset);
Alex Deucherd79766f2009-12-17 19:00:29 -05001851
Alex Deuchera084e6e2010-03-18 01:04:01 -04001852 switch (tv_info->ucTV_BootUpDefaultStandard) {
1853 case ATOM_TV_NTSC:
1854 tv_std = TV_STD_NTSC;
Alex Deucher40f76d82010-10-07 22:38:42 -04001855 DRM_DEBUG_KMS("Default TV standard: NTSC\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001856 break;
1857 case ATOM_TV_NTSCJ:
1858 tv_std = TV_STD_NTSC_J;
Alex Deucher40f76d82010-10-07 22:38:42 -04001859 DRM_DEBUG_KMS("Default TV standard: NTSC-J\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001860 break;
1861 case ATOM_TV_PAL:
1862 tv_std = TV_STD_PAL;
Alex Deucher40f76d82010-10-07 22:38:42 -04001863 DRM_DEBUG_KMS("Default TV standard: PAL\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001864 break;
1865 case ATOM_TV_PALM:
1866 tv_std = TV_STD_PAL_M;
Alex Deucher40f76d82010-10-07 22:38:42 -04001867 DRM_DEBUG_KMS("Default TV standard: PAL-M\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001868 break;
1869 case ATOM_TV_PALN:
1870 tv_std = TV_STD_PAL_N;
Alex Deucher40f76d82010-10-07 22:38:42 -04001871 DRM_DEBUG_KMS("Default TV standard: PAL-N\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001872 break;
1873 case ATOM_TV_PALCN:
1874 tv_std = TV_STD_PAL_CN;
Alex Deucher40f76d82010-10-07 22:38:42 -04001875 DRM_DEBUG_KMS("Default TV standard: PAL-CN\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001876 break;
1877 case ATOM_TV_PAL60:
1878 tv_std = TV_STD_PAL_60;
Alex Deucher40f76d82010-10-07 22:38:42 -04001879 DRM_DEBUG_KMS("Default TV standard: PAL-60\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001880 break;
1881 case ATOM_TV_SECAM:
1882 tv_std = TV_STD_SECAM;
Alex Deucher40f76d82010-10-07 22:38:42 -04001883 DRM_DEBUG_KMS("Default TV standard: SECAM\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001884 break;
1885 default:
1886 tv_std = TV_STD_NTSC;
Alex Deucher40f76d82010-10-07 22:38:42 -04001887 DRM_DEBUG_KMS("Unknown TV standard; defaulting to NTSC\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001888 break;
1889 }
Alex Deucherd79766f2009-12-17 19:00:29 -05001890 }
1891 return tv_std;
1892}
1893
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001894struct radeon_encoder_tv_dac *
1895radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
1896{
1897 struct drm_device *dev = encoder->base.dev;
1898 struct radeon_device *rdev = dev->dev_private;
1899 struct radeon_mode_info *mode_info = &rdev->mode_info;
1900 int index = GetIndexIntoMasterTable(DATA, CompassionateData);
1901 uint16_t data_offset;
1902 struct _COMPASSIONATE_DATA *dac_info;
1903 uint8_t frev, crev;
1904 uint8_t bg, dac;
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001905 struct radeon_encoder_tv_dac *tv_dac = NULL;
1906
Alex Deuchera084e6e2010-03-18 01:04:01 -04001907 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1908 &frev, &crev, &data_offset)) {
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001909
Alex Deuchera084e6e2010-03-18 01:04:01 -04001910 dac_info = (struct _COMPASSIONATE_DATA *)
1911 (mode_info->atom_context->bios + data_offset);
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001912
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001913 tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL);
1914
1915 if (!tv_dac)
1916 return NULL;
1917
1918 bg = dac_info->ucDAC2_CRT2_BG_Adjustment;
1919 dac = dac_info->ucDAC2_CRT2_DAC_Adjustment;
1920 tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1921
1922 bg = dac_info->ucDAC2_PAL_BG_Adjustment;
1923 dac = dac_info->ucDAC2_PAL_DAC_Adjustment;
1924 tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20);
1925
1926 bg = dac_info->ucDAC2_NTSC_BG_Adjustment;
1927 dac = dac_info->ucDAC2_NTSC_DAC_Adjustment;
1928 tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
1929
Alex Deucherd79766f2009-12-17 19:00:29 -05001930 tv_dac->tv_std = radeon_atombios_get_tv_info(rdev);
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001931 }
1932 return tv_dac;
1933}
1934
Alex Deucher29fb52c2010-03-11 10:01:17 -05001935static const char *thermal_controller_names[] = {
1936 "NONE",
Alex Deucher678e7dfa2010-04-22 14:17:56 -04001937 "lm63",
1938 "adm1032",
1939 "adm1030",
1940 "max6649",
1941 "lm64",
1942 "f75375",
1943 "asc7xxx",
Alex Deucher29fb52c2010-03-11 10:01:17 -05001944};
1945
1946static const char *pp_lib_thermal_controller_names[] = {
1947 "NONE",
Alex Deucher678e7dfa2010-04-22 14:17:56 -04001948 "lm63",
1949 "adm1032",
1950 "adm1030",
1951 "max6649",
1952 "lm64",
1953 "f75375",
Alex Deucher29fb52c2010-03-11 10:01:17 -05001954 "RV6xx",
1955 "RV770",
Alex Deucher678e7dfa2010-04-22 14:17:56 -04001956 "adt7473",
Alex Deucher560154e2010-11-22 17:56:34 -05001957 "NONE",
Alex Deucher49f65982010-03-24 16:39:45 -04001958 "External GPIO",
1959 "Evergreen",
Alex Deucherb0e66412010-11-22 17:56:35 -05001960 "emc2103",
1961 "Sumo",
Alex Deucher4fddba12011-01-06 21:19:22 -05001962 "Northern Islands",
Alex Deucher14607d02012-03-20 17:18:09 -04001963 "Southern Islands",
1964 "lm96163",
Alex Deucher51150202012-12-18 22:07:14 -05001965 "Sea Islands",
Alex Deucher29fb52c2010-03-11 10:01:17 -05001966};
1967
Alex Deucher56278a82009-12-28 13:58:44 -05001968union power_info {
1969 struct _ATOM_POWERPLAY_INFO info;
1970 struct _ATOM_POWERPLAY_INFO_V2 info_2;
1971 struct _ATOM_POWERPLAY_INFO_V3 info_3;
Alex Deucher560154e2010-11-22 17:56:34 -05001972 struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
Alex Deucherb0e66412010-11-22 17:56:35 -05001973 struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
1974 struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
Alex Deucher56278a82009-12-28 13:58:44 -05001975};
1976
Alex Deucher560154e2010-11-22 17:56:34 -05001977union pplib_clock_info {
1978 struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
1979 struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
1980 struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
Alex Deucherb0e66412010-11-22 17:56:35 -05001981 struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
Alex Deucher14607d02012-03-20 17:18:09 -04001982 struct _ATOM_PPLIB_SI_CLOCK_INFO si;
Alex Deucherbc19f592013-06-07 11:41:05 -04001983 struct _ATOM_PPLIB_CI_CLOCK_INFO ci;
Alex Deucher560154e2010-11-22 17:56:34 -05001984};
1985
1986union pplib_power_state {
1987 struct _ATOM_PPLIB_STATE v1;
1988 struct _ATOM_PPLIB_STATE_V2 v2;
1989};
1990
1991static void radeon_atombios_parse_misc_flags_1_3(struct radeon_device *rdev,
1992 int state_index,
1993 u32 misc, u32 misc2)
1994{
1995 rdev->pm.power_state[state_index].misc = misc;
1996 rdev->pm.power_state[state_index].misc2 = misc2;
1997 /* order matters! */
1998 if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
1999 rdev->pm.power_state[state_index].type =
2000 POWER_STATE_TYPE_POWERSAVE;
2001 if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
2002 rdev->pm.power_state[state_index].type =
2003 POWER_STATE_TYPE_BATTERY;
2004 if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
2005 rdev->pm.power_state[state_index].type =
2006 POWER_STATE_TYPE_BATTERY;
2007 if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
2008 rdev->pm.power_state[state_index].type =
2009 POWER_STATE_TYPE_BALANCED;
2010 if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
2011 rdev->pm.power_state[state_index].type =
2012 POWER_STATE_TYPE_PERFORMANCE;
2013 rdev->pm.power_state[state_index].flags &=
2014 ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2015 }
2016 if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
2017 rdev->pm.power_state[state_index].type =
2018 POWER_STATE_TYPE_BALANCED;
2019 if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
2020 rdev->pm.power_state[state_index].type =
2021 POWER_STATE_TYPE_DEFAULT;
2022 rdev->pm.default_power_state_index = state_index;
2023 rdev->pm.power_state[state_index].default_clock_mode =
2024 &rdev->pm.power_state[state_index].clock_info[0];
2025 } else if (state_index == 0) {
2026 rdev->pm.power_state[state_index].clock_info[0].flags |=
2027 RADEON_PM_MODE_NO_DISPLAY;
2028 }
2029}
2030
2031static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
2032{
2033 struct radeon_mode_info *mode_info = &rdev->mode_info;
2034 u32 misc, misc2 = 0;
2035 int num_modes = 0, i;
2036 int state_index = 0;
2037 struct radeon_i2c_bus_rec i2c_bus;
2038 union power_info *power_info;
2039 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2040 u16 data_offset;
2041 u8 frev, crev;
2042
2043 if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
2044 &frev, &crev, &data_offset))
2045 return state_index;
2046 power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
2047
2048 /* add the i2c bus for thermal/fan chip */
Alex Deucher4755fab2012-08-30 13:30:49 -04002049 if ((power_info->info.ucOverdriveThermalController > 0) &&
2050 (power_info->info.ucOverdriveThermalController < ARRAY_SIZE(thermal_controller_names))) {
Alex Deucher560154e2010-11-22 17:56:34 -05002051 DRM_INFO("Possible %s thermal controller at 0x%02x\n",
2052 thermal_controller_names[power_info->info.ucOverdriveThermalController],
2053 power_info->info.ucOverdriveControllerAddress >> 1);
2054 i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
2055 rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
2056 if (rdev->pm.i2c_bus) {
2057 struct i2c_board_info info = { };
2058 const char *name = thermal_controller_names[power_info->info.
2059 ucOverdriveThermalController];
2060 info.addr = power_info->info.ucOverdriveControllerAddress >> 1;
2061 strlcpy(info.type, name, sizeof(info.type));
2062 i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
2063 }
2064 }
2065 num_modes = power_info->info.ucNumOfPowerModeEntries;
2066 if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
2067 num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
Alex Deucherf8e6bfc2013-04-25 09:29:17 -04002068 if (num_modes == 0)
2069 return state_index;
Alex Deucher0975b162011-02-02 18:42:03 -05002070 rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL);
2071 if (!rdev->pm.power_state)
2072 return state_index;
Alex Deucher560154e2010-11-22 17:56:34 -05002073 /* last mode is usually default, array is low to high */
2074 for (i = 0; i < num_modes; i++) {
Alex Deucher6991b8f2011-11-14 17:52:51 -05002075 rdev->pm.power_state[state_index].clock_info =
2076 kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL);
2077 if (!rdev->pm.power_state[state_index].clock_info)
2078 return state_index;
2079 rdev->pm.power_state[state_index].num_clock_modes = 1;
Alex Deucher560154e2010-11-22 17:56:34 -05002080 rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
2081 switch (frev) {
2082 case 1:
Alex Deucher560154e2010-11-22 17:56:34 -05002083 rdev->pm.power_state[state_index].clock_info[0].mclk =
2084 le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock);
2085 rdev->pm.power_state[state_index].clock_info[0].sclk =
2086 le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock);
2087 /* skip invalid modes */
2088 if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
2089 (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
2090 continue;
2091 rdev->pm.power_state[state_index].pcie_lanes =
2092 power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
2093 misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
2094 if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
2095 (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
2096 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2097 VOLTAGE_GPIO;
2098 rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
2099 radeon_lookup_gpio(rdev,
2100 power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
2101 if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
2102 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2103 true;
2104 else
2105 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2106 false;
2107 } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
2108 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2109 VOLTAGE_VDDC;
2110 rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
2111 power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
2112 }
2113 rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2114 radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0);
2115 state_index++;
2116 break;
2117 case 2:
Alex Deucher560154e2010-11-22 17:56:34 -05002118 rdev->pm.power_state[state_index].clock_info[0].mclk =
2119 le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
2120 rdev->pm.power_state[state_index].clock_info[0].sclk =
2121 le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock);
2122 /* skip invalid modes */
2123 if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
2124 (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
2125 continue;
2126 rdev->pm.power_state[state_index].pcie_lanes =
2127 power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
2128 misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
2129 misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
2130 if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
2131 (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
2132 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2133 VOLTAGE_GPIO;
2134 rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
2135 radeon_lookup_gpio(rdev,
2136 power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
2137 if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
2138 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2139 true;
2140 else
2141 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2142 false;
2143 } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
2144 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2145 VOLTAGE_VDDC;
2146 rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
2147 power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
2148 }
2149 rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2150 radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
2151 state_index++;
2152 break;
2153 case 3:
Alex Deucher560154e2010-11-22 17:56:34 -05002154 rdev->pm.power_state[state_index].clock_info[0].mclk =
2155 le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
2156 rdev->pm.power_state[state_index].clock_info[0].sclk =
2157 le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock);
2158 /* skip invalid modes */
2159 if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
2160 (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
2161 continue;
2162 rdev->pm.power_state[state_index].pcie_lanes =
2163 power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
2164 misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
2165 misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2);
2166 if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
2167 (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
2168 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2169 VOLTAGE_GPIO;
2170 rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
2171 radeon_lookup_gpio(rdev,
2172 power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
2173 if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
2174 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2175 true;
2176 else
2177 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2178 false;
2179 } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
2180 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2181 VOLTAGE_VDDC;
2182 rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
2183 power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex;
2184 if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) {
2185 rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled =
2186 true;
2187 rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id =
2188 power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
2189 }
2190 }
2191 rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2192 radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
2193 state_index++;
2194 break;
2195 }
2196 }
2197 /* last mode is usually default */
2198 if (rdev->pm.default_power_state_index == -1) {
2199 rdev->pm.power_state[state_index - 1].type =
2200 POWER_STATE_TYPE_DEFAULT;
2201 rdev->pm.default_power_state_index = state_index - 1;
2202 rdev->pm.power_state[state_index - 1].default_clock_mode =
2203 &rdev->pm.power_state[state_index - 1].clock_info[0];
2204 rdev->pm.power_state[state_index].flags &=
2205 ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2206 rdev->pm.power_state[state_index].misc = 0;
2207 rdev->pm.power_state[state_index].misc2 = 0;
2208 }
2209 return state_index;
2210}
2211
2212static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *rdev,
2213 ATOM_PPLIB_THERMALCONTROLLER *controller)
2214{
2215 struct radeon_i2c_bus_rec i2c_bus;
2216
2217 /* add the i2c bus for thermal/fan chip */
2218 if (controller->ucType > 0) {
2219 if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
2220 DRM_INFO("Internal thermal controller %s fan control\n",
2221 (controller->ucFanParameters &
2222 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2223 rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
2224 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
2225 DRM_INFO("Internal thermal controller %s fan control\n",
2226 (controller->ucFanParameters &
2227 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2228 rdev->pm.int_thermal_type = THERMAL_TYPE_RV770;
2229 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
2230 DRM_INFO("Internal thermal controller %s fan control\n",
2231 (controller->ucFanParameters &
2232 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2233 rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
Alex Deucherb0e66412010-11-22 17:56:35 -05002234 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
2235 DRM_INFO("Internal thermal controller %s fan control\n",
2236 (controller->ucFanParameters &
2237 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2238 rdev->pm.int_thermal_type = THERMAL_TYPE_SUMO;
Alex Deucher4fddba12011-01-06 21:19:22 -05002239 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
2240 DRM_INFO("Internal thermal controller %s fan control\n",
2241 (controller->ucFanParameters &
2242 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2243 rdev->pm.int_thermal_type = THERMAL_TYPE_NI;
Alex Deucher14607d02012-03-20 17:18:09 -04002244 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
2245 DRM_INFO("Internal thermal controller %s fan control\n",
2246 (controller->ucFanParameters &
2247 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2248 rdev->pm.int_thermal_type = THERMAL_TYPE_SI;
Alex Deucher51150202012-12-18 22:07:14 -05002249 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
2250 DRM_INFO("Internal thermal controller %s fan control\n",
2251 (controller->ucFanParameters &
2252 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2253 rdev->pm.int_thermal_type = THERMAL_TYPE_CI;
Alex Deucher16fbe002013-04-22 21:41:26 -04002254 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) {
2255 DRM_INFO("Internal thermal controller %s fan control\n",
2256 (controller->ucFanParameters &
2257 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2258 rdev->pm.int_thermal_type = THERMAL_TYPE_KV;
Alex Deucher560154e2010-11-22 17:56:34 -05002259 } else if ((controller->ucType ==
2260 ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
2261 (controller->ucType ==
Alex Deucherb0e66412010-11-22 17:56:35 -05002262 ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) ||
2263 (controller->ucType ==
2264 ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) {
Alex Deucher560154e2010-11-22 17:56:34 -05002265 DRM_INFO("Special thermal controller config\n");
Alex Deucher4755fab2012-08-30 13:30:49 -04002266 } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
Alex Deucher560154e2010-11-22 17:56:34 -05002267 DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
2268 pp_lib_thermal_controller_names[controller->ucType],
2269 controller->ucI2cAddress >> 1,
2270 (controller->ucFanParameters &
2271 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2272 i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
2273 rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
2274 if (rdev->pm.i2c_bus) {
2275 struct i2c_board_info info = { };
2276 const char *name = pp_lib_thermal_controller_names[controller->ucType];
2277 info.addr = controller->ucI2cAddress >> 1;
2278 strlcpy(info.type, name, sizeof(info.type));
2279 i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
2280 }
Alex Deucher4755fab2012-08-30 13:30:49 -04002281 } else {
2282 DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n",
2283 controller->ucType,
2284 controller->ucI2cAddress >> 1,
2285 (controller->ucFanParameters &
2286 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
Alex Deucher560154e2010-11-22 17:56:34 -05002287 }
2288 }
2289}
2290
Alex Deucher4a6369e2013-04-12 14:04:10 -04002291void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
Alex Deucher2abba662013-03-25 12:47:23 -04002292 u16 *vddc, u16 *vddci, u16 *mvdd)
Alex Deucher560154e2010-11-22 17:56:34 -05002293{
2294 struct radeon_mode_info *mode_info = &rdev->mode_info;
2295 int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
2296 u8 frev, crev;
2297 u16 data_offset;
2298 union firmware_info *firmware_info;
Alex Deucher2feea492011-04-12 14:49:24 -04002299
2300 *vddc = 0;
2301 *vddci = 0;
Alex Deucher2abba662013-03-25 12:47:23 -04002302 *mvdd = 0;
Alex Deucher560154e2010-11-22 17:56:34 -05002303
2304 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
2305 &frev, &crev, &data_offset)) {
2306 firmware_info =
2307 (union firmware_info *)(mode_info->atom_context->bios +
2308 data_offset);
Alex Deucher2feea492011-04-12 14:49:24 -04002309 *vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
Alex Deucher2abba662013-03-25 12:47:23 -04002310 if ((frev == 2) && (crev >= 2)) {
Alex Deucher2feea492011-04-12 14:49:24 -04002311 *vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);
Alex Deucher2abba662013-03-25 12:47:23 -04002312 *mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage);
2313 }
Alex Deucher560154e2010-11-22 17:56:34 -05002314 }
Alex Deucher560154e2010-11-22 17:56:34 -05002315}
2316
2317static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev,
2318 int state_index, int mode_index,
2319 struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info)
2320{
2321 int j;
2322 u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
2323 u32 misc2 = le16_to_cpu(non_clock_info->usClassification);
Alex Deucher2abba662013-03-25 12:47:23 -04002324 u16 vddc, vddci, mvdd;
Alex Deucher2feea492011-04-12 14:49:24 -04002325
Alex Deucher2abba662013-03-25 12:47:23 -04002326 radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd);
Alex Deucher560154e2010-11-22 17:56:34 -05002327
2328 rdev->pm.power_state[state_index].misc = misc;
2329 rdev->pm.power_state[state_index].misc2 = misc2;
2330 rdev->pm.power_state[state_index].pcie_lanes =
2331 ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
2332 ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
2333 switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
2334 case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
2335 rdev->pm.power_state[state_index].type =
2336 POWER_STATE_TYPE_BATTERY;
2337 break;
2338 case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
2339 rdev->pm.power_state[state_index].type =
2340 POWER_STATE_TYPE_BALANCED;
2341 break;
2342 case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
2343 rdev->pm.power_state[state_index].type =
2344 POWER_STATE_TYPE_PERFORMANCE;
2345 break;
2346 case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
2347 if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
2348 rdev->pm.power_state[state_index].type =
2349 POWER_STATE_TYPE_PERFORMANCE;
2350 break;
2351 }
2352 rdev->pm.power_state[state_index].flags = 0;
2353 if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
2354 rdev->pm.power_state[state_index].flags |=
2355 RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2356 if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
2357 rdev->pm.power_state[state_index].type =
2358 POWER_STATE_TYPE_DEFAULT;
2359 rdev->pm.default_power_state_index = state_index;
2360 rdev->pm.power_state[state_index].default_clock_mode =
2361 &rdev->pm.power_state[state_index].clock_info[mode_index - 1];
Alex Deucher982cb322013-04-29 10:51:26 -04002362 if ((rdev->family >= CHIP_BARTS) && !(rdev->flags & RADEON_IS_IGP)) {
Alex Deucher9ace9f72011-01-06 21:19:26 -05002363 /* NI chips post without MC ucode, so default clocks are strobe mode only */
2364 rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk;
2365 rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk;
2366 rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage;
Alex Deucher2feea492011-04-12 14:49:24 -04002367 rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci;
Alex Deucher9ace9f72011-01-06 21:19:26 -05002368 } else {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04002369 u16 max_vddci = 0;
2370
2371 if (ASIC_IS_DCE4(rdev))
2372 radeon_atom_get_max_voltage(rdev,
2373 SET_VOLTAGE_TYPE_ASIC_VDDCI,
2374 &max_vddci);
2375 /* patch the table values with the default sclk/mclk from firmware info */
Alex Deucher9ace9f72011-01-06 21:19:26 -05002376 for (j = 0; j < mode_index; j++) {
2377 rdev->pm.power_state[state_index].clock_info[j].mclk =
2378 rdev->clock.default_mclk;
2379 rdev->pm.power_state[state_index].clock_info[j].sclk =
2380 rdev->clock.default_sclk;
2381 if (vddc)
2382 rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
2383 vddc;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04002384 if (max_vddci)
2385 rdev->pm.power_state[state_index].clock_info[j].voltage.vddci =
2386 max_vddci;
Alex Deucher9ace9f72011-01-06 21:19:26 -05002387 }
Alex Deucher560154e2010-11-22 17:56:34 -05002388 }
2389 }
2390}
2391
2392static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
2393 int state_index, int mode_index,
2394 union pplib_clock_info *clock_info)
2395{
2396 u32 sclk, mclk;
Alex Deuchere83753b2012-03-20 17:18:08 -04002397 u16 vddc;
Alex Deucher560154e2010-11-22 17:56:34 -05002398
2399 if (rdev->flags & RADEON_IS_IGP) {
Alex Deucherb0e66412010-11-22 17:56:35 -05002400 if (rdev->family >= CHIP_PALM) {
2401 sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
2402 sclk |= clock_info->sumo.ucEngineClockHigh << 16;
2403 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2404 } else {
2405 sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
2406 sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
2407 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2408 }
Alex Deucherbc19f592013-06-07 11:41:05 -04002409 } else if (rdev->family >= CHIP_BONAIRE) {
2410 sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
2411 sclk |= clock_info->ci.ucEngineClockHigh << 16;
2412 mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
2413 mclk |= clock_info->ci.ucMemoryClockHigh << 16;
2414 rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2415 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2416 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2417 VOLTAGE_NONE;
Alex Deucher982cb322013-04-29 10:51:26 -04002418 } else if (rdev->family >= CHIP_TAHITI) {
Alex Deucher14607d02012-03-20 17:18:09 -04002419 sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
2420 sclk |= clock_info->si.ucEngineClockHigh << 16;
2421 mclk = le16_to_cpu(clock_info->si.usMemoryClockLow);
2422 mclk |= clock_info->si.ucMemoryClockHigh << 16;
2423 rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2424 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2425 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2426 VOLTAGE_SW;
2427 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
2428 le16_to_cpu(clock_info->si.usVDDC);
2429 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
2430 le16_to_cpu(clock_info->si.usVDDCI);
Alex Deucher982cb322013-04-29 10:51:26 -04002431 } else if (rdev->family >= CHIP_CEDAR) {
Alex Deucher560154e2010-11-22 17:56:34 -05002432 sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
2433 sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
2434 mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
2435 mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
2436 rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2437 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2438 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2439 VOLTAGE_SW;
2440 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
Cédric Cano45894332011-02-11 19:45:37 -05002441 le16_to_cpu(clock_info->evergreen.usVDDC);
Alex Deucher2feea492011-04-12 14:49:24 -04002442 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
2443 le16_to_cpu(clock_info->evergreen.usVDDCI);
Alex Deucher560154e2010-11-22 17:56:34 -05002444 } else {
2445 sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
2446 sclk |= clock_info->r600.ucEngineClockHigh << 16;
2447 mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
2448 mclk |= clock_info->r600.ucMemoryClockHigh << 16;
2449 rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2450 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2451 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2452 VOLTAGE_SW;
2453 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
Cédric Cano45894332011-02-11 19:45:37 -05002454 le16_to_cpu(clock_info->r600.usVDDC);
Alex Deucher560154e2010-11-22 17:56:34 -05002455 }
2456
Alex Deucheree4017f2011-06-23 12:19:32 -04002457 /* patch up vddc if necessary */
Alex Deuchere83753b2012-03-20 17:18:08 -04002458 switch (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage) {
2459 case ATOM_VIRTUAL_VOLTAGE_ID0:
2460 case ATOM_VIRTUAL_VOLTAGE_ID1:
2461 case ATOM_VIRTUAL_VOLTAGE_ID2:
2462 case ATOM_VIRTUAL_VOLTAGE_ID3:
Alex Deucherc6cf7772013-07-05 13:14:30 -04002463 case ATOM_VIRTUAL_VOLTAGE_ID4:
2464 case ATOM_VIRTUAL_VOLTAGE_ID5:
2465 case ATOM_VIRTUAL_VOLTAGE_ID6:
2466 case ATOM_VIRTUAL_VOLTAGE_ID7:
Alex Deuchere83753b2012-03-20 17:18:08 -04002467 if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC,
2468 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage,
2469 &vddc) == 0)
Alex Deucheree4017f2011-06-23 12:19:32 -04002470 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = vddc;
Alex Deuchere83753b2012-03-20 17:18:08 -04002471 break;
2472 default:
2473 break;
Alex Deucheree4017f2011-06-23 12:19:32 -04002474 }
2475
Alex Deucher560154e2010-11-22 17:56:34 -05002476 if (rdev->flags & RADEON_IS_IGP) {
2477 /* skip invalid modes */
2478 if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
2479 return false;
2480 } else {
2481 /* skip invalid modes */
2482 if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
2483 (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
2484 return false;
2485 }
2486 return true;
2487}
2488
2489static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev)
2490{
2491 struct radeon_mode_info *mode_info = &rdev->mode_info;
2492 struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
2493 union pplib_power_state *power_state;
2494 int i, j;
2495 int state_index = 0, mode_index = 0;
2496 union pplib_clock_info *clock_info;
2497 bool valid;
2498 union power_info *power_info;
2499 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2500 u16 data_offset;
2501 u8 frev, crev;
2502
2503 if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
2504 &frev, &crev, &data_offset))
2505 return state_index;
2506 power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
2507
2508 radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
Alex Deucherf8e6bfc2013-04-25 09:29:17 -04002509 if (power_info->pplib.ucNumStates == 0)
2510 return state_index;
Alex Deucher0975b162011-02-02 18:42:03 -05002511 rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) *
2512 power_info->pplib.ucNumStates, GFP_KERNEL);
2513 if (!rdev->pm.power_state)
2514 return state_index;
Alex Deucher560154e2010-11-22 17:56:34 -05002515 /* first mode is usually default, followed by low to high */
2516 for (i = 0; i < power_info->pplib.ucNumStates; i++) {
2517 mode_index = 0;
2518 power_state = (union pplib_power_state *)
2519 (mode_info->atom_context->bios + data_offset +
2520 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
2521 i * power_info->pplib.ucStateEntrySize);
2522 non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
2523 (mode_info->atom_context->bios + data_offset +
2524 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
2525 (power_state->v1.ucNonClockStateIndex *
2526 power_info->pplib.ucNonClockSize));
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002527 rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) *
2528 ((power_info->pplib.ucStateEntrySize - 1) ?
2529 (power_info->pplib.ucStateEntrySize - 1) : 1),
2530 GFP_KERNEL);
2531 if (!rdev->pm.power_state[i].clock_info)
2532 return state_index;
2533 if (power_info->pplib.ucStateEntrySize - 1) {
2534 for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
2535 clock_info = (union pplib_clock_info *)
2536 (mode_info->atom_context->bios + data_offset +
2537 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
2538 (power_state->v1.ucClockStateIndices[j] *
2539 power_info->pplib.ucClockInfoSize));
2540 valid = radeon_atombios_parse_pplib_clock_info(rdev,
2541 state_index, mode_index,
2542 clock_info);
2543 if (valid)
2544 mode_index++;
2545 }
2546 } else {
2547 rdev->pm.power_state[state_index].clock_info[0].mclk =
2548 rdev->clock.default_mclk;
2549 rdev->pm.power_state[state_index].clock_info[0].sclk =
2550 rdev->clock.default_sclk;
2551 mode_index++;
Alex Deucher560154e2010-11-22 17:56:34 -05002552 }
2553 rdev->pm.power_state[state_index].num_clock_modes = mode_index;
2554 if (mode_index) {
2555 radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
2556 non_clock_info);
2557 state_index++;
2558 }
2559 }
2560 /* if multiple clock modes, mark the lowest as no display */
2561 for (i = 0; i < state_index; i++) {
2562 if (rdev->pm.power_state[i].num_clock_modes > 1)
2563 rdev->pm.power_state[i].clock_info[0].flags |=
2564 RADEON_PM_MODE_NO_DISPLAY;
2565 }
2566 /* first mode is usually default */
2567 if (rdev->pm.default_power_state_index == -1) {
2568 rdev->pm.power_state[0].type =
2569 POWER_STATE_TYPE_DEFAULT;
2570 rdev->pm.default_power_state_index = 0;
2571 rdev->pm.power_state[0].default_clock_mode =
2572 &rdev->pm.power_state[0].clock_info[0];
2573 }
2574 return state_index;
2575}
2576
Alex Deucherb0e66412010-11-22 17:56:35 -05002577static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev)
2578{
2579 struct radeon_mode_info *mode_info = &rdev->mode_info;
2580 struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
2581 union pplib_power_state *power_state;
2582 int i, j, non_clock_array_index, clock_array_index;
2583 int state_index = 0, mode_index = 0;
2584 union pplib_clock_info *clock_info;
Alex Deucherf7346882012-03-20 17:17:58 -04002585 struct _StateArray *state_array;
2586 struct _ClockInfoArray *clock_info_array;
2587 struct _NonClockInfoArray *non_clock_info_array;
Alex Deucherb0e66412010-11-22 17:56:35 -05002588 bool valid;
2589 union power_info *power_info;
2590 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2591 u16 data_offset;
2592 u8 frev, crev;
Alex Deucher441e76c2013-05-01 14:34:54 -04002593 u8 *power_state_offset;
Alex Deucherb0e66412010-11-22 17:56:35 -05002594
2595 if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
2596 &frev, &crev, &data_offset))
2597 return state_index;
2598 power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
2599
2600 radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
Alex Deucherf7346882012-03-20 17:17:58 -04002601 state_array = (struct _StateArray *)
Alex Deucherb0e66412010-11-22 17:56:35 -05002602 (mode_info->atom_context->bios + data_offset +
Cédric Cano45894332011-02-11 19:45:37 -05002603 le16_to_cpu(power_info->pplib.usStateArrayOffset));
Alex Deucherf7346882012-03-20 17:17:58 -04002604 clock_info_array = (struct _ClockInfoArray *)
Alex Deucherb0e66412010-11-22 17:56:35 -05002605 (mode_info->atom_context->bios + data_offset +
Cédric Cano45894332011-02-11 19:45:37 -05002606 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
Alex Deucherf7346882012-03-20 17:17:58 -04002607 non_clock_info_array = (struct _NonClockInfoArray *)
Alex Deucherb0e66412010-11-22 17:56:35 -05002608 (mode_info->atom_context->bios + data_offset +
Cédric Cano45894332011-02-11 19:45:37 -05002609 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
Alex Deucherf8e6bfc2013-04-25 09:29:17 -04002610 if (state_array->ucNumEntries == 0)
2611 return state_index;
Alex Deucher0975b162011-02-02 18:42:03 -05002612 rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) *
2613 state_array->ucNumEntries, GFP_KERNEL);
2614 if (!rdev->pm.power_state)
2615 return state_index;
Alex Deucher441e76c2013-05-01 14:34:54 -04002616 power_state_offset = (u8 *)state_array->states;
Alex Deucherb0e66412010-11-22 17:56:35 -05002617 for (i = 0; i < state_array->ucNumEntries; i++) {
2618 mode_index = 0;
Alex Deucher441e76c2013-05-01 14:34:54 -04002619 power_state = (union pplib_power_state *)power_state_offset;
2620 non_clock_array_index = power_state->v2.nonClockInfoIndex;
Alex Deucherb0e66412010-11-22 17:56:35 -05002621 non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
2622 &non_clock_info_array->nonClockInfo[non_clock_array_index];
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002623 rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) *
2624 (power_state->v2.ucNumDPMLevels ?
2625 power_state->v2.ucNumDPMLevels : 1),
2626 GFP_KERNEL);
2627 if (!rdev->pm.power_state[i].clock_info)
2628 return state_index;
2629 if (power_state->v2.ucNumDPMLevels) {
2630 for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
2631 clock_array_index = power_state->v2.clockInfoIndex[j];
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002632 clock_info = (union pplib_clock_info *)
Alex Deucherf7346882012-03-20 17:17:58 -04002633 &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002634 valid = radeon_atombios_parse_pplib_clock_info(rdev,
2635 state_index, mode_index,
2636 clock_info);
2637 if (valid)
2638 mode_index++;
2639 }
2640 } else {
2641 rdev->pm.power_state[state_index].clock_info[0].mclk =
2642 rdev->clock.default_mclk;
2643 rdev->pm.power_state[state_index].clock_info[0].sclk =
2644 rdev->clock.default_sclk;
2645 mode_index++;
Alex Deucherb0e66412010-11-22 17:56:35 -05002646 }
2647 rdev->pm.power_state[state_index].num_clock_modes = mode_index;
2648 if (mode_index) {
2649 radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
2650 non_clock_info);
2651 state_index++;
2652 }
Alex Deucher441e76c2013-05-01 14:34:54 -04002653 power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
Alex Deucherb0e66412010-11-22 17:56:35 -05002654 }
2655 /* if multiple clock modes, mark the lowest as no display */
2656 for (i = 0; i < state_index; i++) {
2657 if (rdev->pm.power_state[i].num_clock_modes > 1)
2658 rdev->pm.power_state[i].clock_info[0].flags |=
2659 RADEON_PM_MODE_NO_DISPLAY;
2660 }
2661 /* first mode is usually default */
2662 if (rdev->pm.default_power_state_index == -1) {
2663 rdev->pm.power_state[0].type =
2664 POWER_STATE_TYPE_DEFAULT;
2665 rdev->pm.default_power_state_index = 0;
2666 rdev->pm.power_state[0].default_clock_mode =
2667 &rdev->pm.power_state[0].clock_info[0];
2668 }
2669 return state_index;
2670}
2671
Alex Deucher56278a82009-12-28 13:58:44 -05002672void radeon_atombios_get_power_modes(struct radeon_device *rdev)
2673{
2674 struct radeon_mode_info *mode_info = &rdev->mode_info;
2675 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2676 u16 data_offset;
2677 u8 frev, crev;
Alex Deucher560154e2010-11-22 17:56:34 -05002678 int state_index = 0;
Alex Deucher56278a82009-12-28 13:58:44 -05002679
Alex Deuchera48b9b42010-04-22 14:03:55 -04002680 rdev->pm.default_power_state_index = -1;
Alex Deucher56278a82009-12-28 13:58:44 -05002681
Alex Deuchera084e6e2010-03-18 01:04:01 -04002682 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
2683 &frev, &crev, &data_offset)) {
Alex Deucher560154e2010-11-22 17:56:34 -05002684 switch (frev) {
2685 case 1:
2686 case 2:
2687 case 3:
2688 state_index = radeon_atombios_parse_power_table_1_3(rdev);
2689 break;
2690 case 4:
2691 case 5:
2692 state_index = radeon_atombios_parse_power_table_4_5(rdev);
2693 break;
Alex Deucherb0e66412010-11-22 17:56:35 -05002694 case 6:
2695 state_index = radeon_atombios_parse_power_table_6(rdev);
2696 break;
Alex Deucher560154e2010-11-22 17:56:34 -05002697 default:
2698 break;
Alex Deucher56278a82009-12-28 13:58:44 -05002699 }
Alex Deucherf8e6bfc2013-04-25 09:29:17 -04002700 }
2701
2702 if (state_index == 0) {
Alex Deucher0975b162011-02-02 18:42:03 -05002703 rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL);
2704 if (rdev->pm.power_state) {
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002705 rdev->pm.power_state[0].clock_info =
2706 kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL);
2707 if (rdev->pm.power_state[0].clock_info) {
2708 /* add the default mode */
2709 rdev->pm.power_state[state_index].type =
2710 POWER_STATE_TYPE_DEFAULT;
2711 rdev->pm.power_state[state_index].num_clock_modes = 1;
2712 rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
2713 rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
2714 rdev->pm.power_state[state_index].default_clock_mode =
2715 &rdev->pm.power_state[state_index].clock_info[0];
2716 rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
2717 rdev->pm.power_state[state_index].pcie_lanes = 16;
2718 rdev->pm.default_power_state_index = state_index;
2719 rdev->pm.power_state[state_index].flags = 0;
2720 state_index++;
2721 }
Alex Deucher0975b162011-02-02 18:42:03 -05002722 }
Alex Deucher56278a82009-12-28 13:58:44 -05002723 }
Alex Deucher02b17cc2010-04-22 13:25:06 -04002724
Alex Deucher56278a82009-12-28 13:58:44 -05002725 rdev->pm.num_power_states = state_index;
Rafał Miłecki9038dfd2010-02-20 23:15:04 +00002726
Alex Deuchera48b9b42010-04-22 14:03:55 -04002727 rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
2728 rdev->pm.current_clock_mode_index = 0;
Alexander Müller4376eee2011-12-30 12:55:48 -05002729 if (rdev->pm.default_power_state_index >= 0)
2730 rdev->pm.current_vddc =
2731 rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
2732 else
2733 rdev->pm.current_vddc = 0;
Alex Deucher56278a82009-12-28 13:58:44 -05002734}
2735
Christian König7062ab62013-04-08 12:41:31 +02002736union get_clock_dividers {
2737 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1;
2738 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2;
2739 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3;
2740 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4;
2741 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5;
Alex Deucher9219ed62013-02-19 14:35:34 -05002742 struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in;
2743 struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out;
Christian König7062ab62013-04-08 12:41:31 +02002744};
2745
2746int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
2747 u8 clock_type,
2748 u32 clock,
2749 bool strobe_mode,
2750 struct atom_clock_dividers *dividers)
2751{
2752 union get_clock_dividers args;
2753 int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL);
2754 u8 frev, crev;
2755
2756 memset(&args, 0, sizeof(args));
2757 memset(dividers, 0, sizeof(struct atom_clock_dividers));
2758
2759 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
2760 return -EINVAL;
2761
2762 switch (crev) {
2763 case 1:
2764 /* r4xx, r5xx */
2765 args.v1.ucAction = clock_type;
2766 args.v1.ulClock = cpu_to_le32(clock); /* 10 khz */
2767
2768 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2769
2770 dividers->post_div = args.v1.ucPostDiv;
2771 dividers->fb_div = args.v1.ucFbDiv;
2772 dividers->enable_post_div = true;
2773 break;
2774 case 2:
2775 case 3:
Alex Deucher360b1f52013-06-07 11:50:12 -04002776 case 5:
2777 /* r6xx, r7xx, evergreen, ni, si */
Christian König7062ab62013-04-08 12:41:31 +02002778 if (rdev->family <= CHIP_RV770) {
2779 args.v2.ucAction = clock_type;
2780 args.v2.ulClock = cpu_to_le32(clock); /* 10 khz */
2781
2782 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2783
2784 dividers->post_div = args.v2.ucPostDiv;
2785 dividers->fb_div = le16_to_cpu(args.v2.usFbDiv);
2786 dividers->ref_div = args.v2.ucAction;
2787 if (rdev->family == CHIP_RV770) {
2788 dividers->enable_post_div = (le32_to_cpu(args.v2.ulClock) & (1 << 24)) ?
2789 true : false;
2790 dividers->vco_mode = (le32_to_cpu(args.v2.ulClock) & (1 << 25)) ? 1 : 0;
2791 } else
2792 dividers->enable_post_div = (dividers->fb_div & 1) ? true : false;
2793 } else {
2794 if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {
Alex Deucherf4a25962013-04-22 09:59:01 -04002795 args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
Christian König7062ab62013-04-08 12:41:31 +02002796
2797 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2798
2799 dividers->post_div = args.v3.ucPostDiv;
2800 dividers->enable_post_div = (args.v3.ucCntlFlag &
2801 ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
2802 dividers->enable_dithen = (args.v3.ucCntlFlag &
2803 ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
Alex Deucher20fab642013-07-28 12:33:56 -04002804 dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
Christian König7062ab62013-04-08 12:41:31 +02002805 dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
2806 dividers->ref_div = args.v3.ucRefDiv;
2807 dividers->vco_mode = (args.v3.ucCntlFlag &
2808 ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
2809 } else {
Alex Deucher360b1f52013-06-07 11:50:12 -04002810 /* for SI we use ComputeMemoryClockParam for memory plls */
2811 if (rdev->family >= CHIP_TAHITI)
2812 return -EINVAL;
Alex Deucherf4a25962013-04-22 09:59:01 -04002813 args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
Christian König7062ab62013-04-08 12:41:31 +02002814 if (strobe_mode)
2815 args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
2816
2817 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2818
2819 dividers->post_div = args.v5.ucPostDiv;
2820 dividers->enable_post_div = (args.v5.ucCntlFlag &
2821 ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
2822 dividers->enable_dithen = (args.v5.ucCntlFlag &
2823 ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
2824 dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv);
2825 dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac);
2826 dividers->ref_div = args.v5.ucRefDiv;
2827 dividers->vco_mode = (args.v5.ucCntlFlag &
2828 ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
2829 }
2830 }
2831 break;
2832 case 4:
2833 /* fusion */
2834 args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */
2835
2836 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2837
Alex Deucher9219ed62013-02-19 14:35:34 -05002838 dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;
Christian König7062ab62013-04-08 12:41:31 +02002839 dividers->real_clock = le32_to_cpu(args.v4.ulClock);
2840 break;
Alex Deucher9219ed62013-02-19 14:35:34 -05002841 case 6:
2842 /* CI */
2843 /* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */
2844 args.v6_in.ulClock.ulComputeClockFlag = clock_type;
2845 args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */
2846
2847 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2848
2849 dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);
2850 dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);
2851 dividers->ref_div = args.v6_out.ucPllRefDiv;
2852 dividers->post_div = args.v6_out.ucPllPostDiv;
2853 dividers->flags = args.v6_out.ucPllCntlFlag;
2854 dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock);
2855 dividers->post_divider = args.v6_out.ulClock.ucPostDiv;
2856 break;
Christian König7062ab62013-04-08 12:41:31 +02002857 default:
2858 return -EINVAL;
2859 }
2860 return 0;
2861}
2862
Alex Deuchereaa778a2013-02-13 16:38:25 -05002863int radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev,
2864 u32 clock,
2865 bool strobe_mode,
2866 struct atom_mpll_param *mpll_param)
2867{
2868 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 args;
2869 int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam);
2870 u8 frev, crev;
2871
2872 memset(&args, 0, sizeof(args));
2873 memset(mpll_param, 0, sizeof(struct atom_mpll_param));
2874
2875 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
2876 return -EINVAL;
2877
2878 switch (frev) {
2879 case 2:
2880 switch (crev) {
2881 case 1:
2882 /* SI */
2883 args.ulClock = cpu_to_le32(clock); /* 10 khz */
2884 args.ucInputFlag = 0;
2885 if (strobe_mode)
2886 args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN;
2887
2888 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2889
2890 mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac);
2891 mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv);
2892 mpll_param->post_div = args.ucPostDiv;
2893 mpll_param->dll_speed = args.ucDllSpeed;
2894 mpll_param->bwcntl = args.ucBWCntl;
2895 mpll_param->vco_mode =
2896 (args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK) ? 1 : 0;
2897 mpll_param->yclk_sel =
2898 (args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0;
2899 mpll_param->qdr =
2900 (args.ucPllCntlFlag & MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0;
2901 mpll_param->half_rate =
2902 (args.ucPllCntlFlag & MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0;
2903 break;
2904 default:
2905 return -EINVAL;
2906 }
2907 break;
2908 default:
2909 return -EINVAL;
2910 }
2911 return 0;
2912}
2913
Jerome Glisse771fe6b2009-06-05 14:42:42 +02002914void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
2915{
2916 DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
2917 int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
2918
2919 args.ucEnable = enable;
2920
2921 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2922}
2923
Rafał Miłecki74338742009-11-03 00:53:02 +01002924uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev)
2925{
2926 GET_ENGINE_CLOCK_PS_ALLOCATION args;
2927 int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock);
2928
2929 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
Cédric Cano45894332011-02-11 19:45:37 -05002930 return le32_to_cpu(args.ulReturnEngineClock);
Rafał Miłecki74338742009-11-03 00:53:02 +01002931}
2932
2933uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev)
2934{
2935 GET_MEMORY_CLOCK_PS_ALLOCATION args;
2936 int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock);
2937
2938 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
Cédric Cano45894332011-02-11 19:45:37 -05002939 return le32_to_cpu(args.ulReturnMemoryClock);
Rafał Miłecki74338742009-11-03 00:53:02 +01002940}
2941
Jerome Glisse771fe6b2009-06-05 14:42:42 +02002942void radeon_atom_set_engine_clock(struct radeon_device *rdev,
2943 uint32_t eng_clock)
2944{
2945 SET_ENGINE_CLOCK_PS_ALLOCATION args;
2946 int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
2947
Cédric Cano45894332011-02-11 19:45:37 -05002948 args.ulTargetEngineClock = cpu_to_le32(eng_clock); /* 10 khz */
Jerome Glisse771fe6b2009-06-05 14:42:42 +02002949
2950 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2951}
2952
2953void radeon_atom_set_memory_clock(struct radeon_device *rdev,
2954 uint32_t mem_clock)
2955{
2956 SET_MEMORY_CLOCK_PS_ALLOCATION args;
2957 int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
2958
2959 if (rdev->flags & RADEON_IS_IGP)
2960 return;
2961
Cédric Cano45894332011-02-11 19:45:37 -05002962 args.ulTargetMemoryClock = cpu_to_le32(mem_clock); /* 10 khz */
Jerome Glisse771fe6b2009-06-05 14:42:42 +02002963
2964 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2965}
2966
Alex Deucherae5b0ab2013-06-24 10:50:34 -04002967void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev,
2968 u32 eng_clock, u32 mem_clock)
2969{
2970 SET_ENGINE_CLOCK_PS_ALLOCATION args;
2971 int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
2972 u32 tmp;
2973
2974 memset(&args, 0, sizeof(args));
2975
2976 tmp = eng_clock & SET_CLOCK_FREQ_MASK;
2977 tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24);
2978
2979 args.ulTargetEngineClock = cpu_to_le32(tmp);
2980 if (mem_clock)
2981 args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK);
2982
2983 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2984}
2985
2986void radeon_atom_update_memory_dll(struct radeon_device *rdev,
2987 u32 mem_clock)
2988{
2989 u32 args;
2990 int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
2991
2992 args = cpu_to_le32(mem_clock); /* 10 khz */
2993
2994 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2995}
2996
2997void radeon_atom_set_ac_timing(struct radeon_device *rdev,
2998 u32 mem_clock)
2999{
3000 SET_MEMORY_CLOCK_PS_ALLOCATION args;
3001 int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
3002 u32 tmp = mem_clock | (COMPUTE_MEMORY_PLL_PARAM << 24);
3003
3004 args.ulTargetMemoryClock = cpu_to_le32(tmp); /* 10 khz */
3005
3006 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3007}
3008
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003009union set_voltage {
3010 struct _SET_VOLTAGE_PS_ALLOCATION alloc;
3011 struct _SET_VOLTAGE_PARAMETERS v1;
3012 struct _SET_VOLTAGE_PARAMETERS_V2 v2;
Alex Deuchere83753b2012-03-20 17:18:08 -04003013 struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003014};
3015
Alex Deucher8a83ec52011-04-12 14:49:23 -04003016void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type)
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003017{
3018 union set_voltage args;
3019 int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
Alex Deucher8a83ec52011-04-12 14:49:23 -04003020 u8 frev, crev, volt_index = voltage_level;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003021
3022 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
3023 return;
3024
Alex Deuchera377e182011-06-20 13:00:31 -04003025 /* 0xff01 is a flag rather then an actual voltage */
3026 if (voltage_level == 0xff01)
3027 return;
3028
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003029 switch (crev) {
3030 case 1:
Alex Deucher8a83ec52011-04-12 14:49:23 -04003031 args.v1.ucVoltageType = voltage_type;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003032 args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE;
3033 args.v1.ucVoltageIndex = volt_index;
3034 break;
3035 case 2:
Alex Deucher8a83ec52011-04-12 14:49:23 -04003036 args.v2.ucVoltageType = voltage_type;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003037 args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE;
Alex Deucher8a83ec52011-04-12 14:49:23 -04003038 args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003039 break;
Alex Deuchere83753b2012-03-20 17:18:08 -04003040 case 3:
3041 args.v3.ucVoltageType = voltage_type;
3042 args.v3.ucVoltageMode = ATOM_SET_VOLTAGE;
3043 args.v3.usVoltageLevel = cpu_to_le16(voltage_level);
3044 break;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003045 default:
3046 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3047 return;
3048 }
3049
3050 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3051}
3052
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003053int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
3054 u16 voltage_id, u16 *voltage)
Alex Deucheree4017f2011-06-23 12:19:32 -04003055{
3056 union set_voltage args;
3057 int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
3058 u8 frev, crev;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003059
Alex Deucheree4017f2011-06-23 12:19:32 -04003060 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
3061 return -EINVAL;
3062
3063 switch (crev) {
3064 case 1:
3065 return -EINVAL;
3066 case 2:
3067 args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;
3068 args.v2.ucVoltageMode = 0;
3069 args.v2.usVoltageLevel = 0;
3070
3071 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3072
3073 *voltage = le16_to_cpu(args.v2.usVoltageLevel);
3074 break;
Alex Deuchere83753b2012-03-20 17:18:08 -04003075 case 3:
3076 args.v3.ucVoltageType = voltage_type;
3077 args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;
3078 args.v3.usVoltageLevel = cpu_to_le16(voltage_id);
3079
3080 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3081
3082 *voltage = le16_to_cpu(args.v3.usVoltageLevel);
3083 break;
Alex Deucheree4017f2011-06-23 12:19:32 -04003084 default:
3085 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3086 return -EINVAL;
3087 }
3088
3089 return 0;
3090}
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003091
Alex Deucherbeb79f42013-02-19 17:14:43 -05003092int radeon_atom_get_leakage_vddc_based_on_leakage_idx(struct radeon_device *rdev,
3093 u16 *voltage,
3094 u16 leakage_idx)
3095{
3096 return radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage);
3097}
3098
Alex Deucher62c35fd72013-02-19 18:15:06 -05003099int radeon_atom_get_leakage_id_from_vbios(struct radeon_device *rdev,
3100 u16 *leakage_id)
3101{
3102 union set_voltage args;
3103 int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
3104 u8 frev, crev;
3105
3106 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
3107 return -EINVAL;
3108
3109 switch (crev) {
3110 case 3:
3111 case 4:
3112 args.v3.ucVoltageType = 0;
3113 args.v3.ucVoltageMode = ATOM_GET_LEAKAGE_ID;
3114 args.v3.usVoltageLevel = 0;
3115
3116 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3117
3118 *leakage_id = le16_to_cpu(args.v3.usVoltageLevel);
3119 break;
3120 default:
3121 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3122 return -EINVAL;
3123 }
3124
3125 return 0;
3126}
3127
3128int radeon_atom_get_leakage_vddc_based_on_leakage_params(struct radeon_device *rdev,
3129 u16 *vddc, u16 *vddci,
3130 u16 virtual_voltage_id,
3131 u16 vbios_voltage_id)
3132{
3133 int index = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo);
3134 u8 frev, crev;
3135 u16 data_offset, size;
3136 int i, j;
3137 ATOM_ASIC_PROFILING_INFO_V2_1 *profile;
3138 u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf;
3139
3140 *vddc = 0;
3141 *vddci = 0;
3142
3143 if (!atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3144 &frev, &crev, &data_offset))
3145 return -EINVAL;
3146
3147 profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *)
3148 (rdev->mode_info.atom_context->bios + data_offset);
3149
3150 switch (frev) {
3151 case 1:
3152 return -EINVAL;
3153 case 2:
3154 switch (crev) {
3155 case 1:
3156 if (size < sizeof(ATOM_ASIC_PROFILING_INFO_V2_1))
3157 return -EINVAL;
3158 leakage_bin = (u16 *)
3159 (rdev->mode_info.atom_context->bios + data_offset +
3160 le16_to_cpu(profile->usLeakageBinArrayOffset));
3161 vddc_id_buf = (u16 *)
3162 (rdev->mode_info.atom_context->bios + data_offset +
3163 le16_to_cpu(profile->usElbVDDC_IdArrayOffset));
3164 vddc_buf = (u16 *)
3165 (rdev->mode_info.atom_context->bios + data_offset +
3166 le16_to_cpu(profile->usElbVDDC_LevelArrayOffset));
3167 vddci_id_buf = (u16 *)
3168 (rdev->mode_info.atom_context->bios + data_offset +
3169 le16_to_cpu(profile->usElbVDDCI_IdArrayOffset));
3170 vddci_buf = (u16 *)
3171 (rdev->mode_info.atom_context->bios + data_offset +
3172 le16_to_cpu(profile->usElbVDDCI_LevelArrayOffset));
3173
3174 if (profile->ucElbVDDC_Num > 0) {
3175 for (i = 0; i < profile->ucElbVDDC_Num; i++) {
3176 if (vddc_id_buf[i] == virtual_voltage_id) {
3177 for (j = 0; j < profile->ucLeakageBinNum; j++) {
3178 if (vbios_voltage_id <= leakage_bin[j]) {
3179 *vddc = vddc_buf[j * profile->ucElbVDDC_Num + i];
3180 break;
3181 }
3182 }
3183 break;
3184 }
3185 }
3186 }
3187 if (profile->ucElbVDDCI_Num > 0) {
3188 for (i = 0; i < profile->ucElbVDDCI_Num; i++) {
3189 if (vddci_id_buf[i] == virtual_voltage_id) {
3190 for (j = 0; j < profile->ucLeakageBinNum; j++) {
3191 if (vbios_voltage_id <= leakage_bin[j]) {
3192 *vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i];
3193 break;
3194 }
3195 }
3196 break;
3197 }
3198 }
3199 }
3200 break;
3201 default:
3202 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3203 return -EINVAL;
3204 }
3205 break;
3206 default:
3207 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3208 return -EINVAL;
3209 }
3210
3211 return 0;
3212}
3213
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003214int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev,
3215 u16 voltage_level, u8 voltage_type,
3216 u32 *gpio_value, u32 *gpio_mask)
3217{
3218 union set_voltage args;
3219 int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
3220 u8 frev, crev;
3221
3222 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
3223 return -EINVAL;
3224
3225 switch (crev) {
3226 case 1:
3227 return -EINVAL;
3228 case 2:
3229 args.v2.ucVoltageType = voltage_type;
3230 args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK;
3231 args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
3232
3233 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3234
3235 *gpio_mask = le32_to_cpu(*(u32 *)&args.v2);
3236
3237 args.v2.ucVoltageType = voltage_type;
3238 args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL;
3239 args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
3240
3241 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3242
3243 *gpio_value = le32_to_cpu(*(u32 *)&args.v2);
3244 break;
3245 default:
3246 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3247 return -EINVAL;
3248 }
3249
3250 return 0;
3251}
3252
3253union voltage_object_info {
Alex Deucher58653ab2013-02-13 17:04:59 -05003254 struct _ATOM_VOLTAGE_OBJECT_INFO v1;
3255 struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
3256 struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003257};
3258
Alex Deucher779187f2013-03-28 14:47:34 -04003259union voltage_object {
3260 struct _ATOM_VOLTAGE_OBJECT v1;
3261 struct _ATOM_VOLTAGE_OBJECT_V2 v2;
3262 union _ATOM_VOLTAGE_OBJECT_V3 v3;
3263};
3264
3265static ATOM_VOLTAGE_OBJECT *atom_lookup_voltage_object_v1(ATOM_VOLTAGE_OBJECT_INFO *v1,
3266 u8 voltage_type)
3267{
Alex Deucher6e764762013-06-24 10:54:16 -04003268 u32 size = le16_to_cpu(v1->sHeader.usStructureSize);
Alex Deucher779187f2013-03-28 14:47:34 -04003269 u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO, asVoltageObj[0]);
3270 u8 *start = (u8 *)v1;
3271
3272 while (offset < size) {
3273 ATOM_VOLTAGE_OBJECT *vo = (ATOM_VOLTAGE_OBJECT *)(start + offset);
3274 if (vo->ucVoltageType == voltage_type)
3275 return vo;
3276 offset += offsetof(ATOM_VOLTAGE_OBJECT, asFormula.ucVIDAdjustEntries) +
3277 vo->asFormula.ucNumOfVoltageEntries;
3278 }
3279 return NULL;
3280}
3281
3282static ATOM_VOLTAGE_OBJECT_V2 *atom_lookup_voltage_object_v2(ATOM_VOLTAGE_OBJECT_INFO_V2 *v2,
3283 u8 voltage_type)
3284{
Alex Deucher6e764762013-06-24 10:54:16 -04003285 u32 size = le16_to_cpu(v2->sHeader.usStructureSize);
Alex Deucher779187f2013-03-28 14:47:34 -04003286 u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V2, asVoltageObj[0]);
3287 u8 *start = (u8*)v2;
3288
3289 while (offset < size) {
3290 ATOM_VOLTAGE_OBJECT_V2 *vo = (ATOM_VOLTAGE_OBJECT_V2 *)(start + offset);
3291 if (vo->ucVoltageType == voltage_type)
3292 return vo;
3293 offset += offsetof(ATOM_VOLTAGE_OBJECT_V2, asFormula.asVIDAdjustEntries) +
3294 (vo->asFormula.ucNumOfVoltageEntries * sizeof(VOLTAGE_LUT_ENTRY));
3295 }
3296 return NULL;
3297}
3298
3299static ATOM_VOLTAGE_OBJECT_V3 *atom_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3,
3300 u8 voltage_type, u8 voltage_mode)
3301{
Alex Deucher6e764762013-06-24 10:54:16 -04003302 u32 size = le16_to_cpu(v3->sHeader.usStructureSize);
Alex Deucher779187f2013-03-28 14:47:34 -04003303 u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
3304 u8 *start = (u8*)v3;
3305
3306 while (offset < size) {
3307 ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
3308 if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) &&
3309 (vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode))
3310 return vo;
Alex Deucher6e764762013-06-24 10:54:16 -04003311 offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize);
Alex Deucher779187f2013-03-28 14:47:34 -04003312 }
3313 return NULL;
3314}
3315
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003316bool
Alex Deucher58653ab2013-02-13 17:04:59 -05003317radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
3318 u8 voltage_type, u8 voltage_mode)
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003319{
3320 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3321 u8 frev, crev;
3322 u16 data_offset, size;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003323 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003324 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003325
3326 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3327 &frev, &crev, &data_offset)) {
3328 voltage_info = (union voltage_object_info *)
3329 (rdev->mode_info.atom_context->bios + data_offset);
3330
Alex Deucher58653ab2013-02-13 17:04:59 -05003331 switch (frev) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003332 case 1:
Alex Deucher58653ab2013-02-13 17:04:59 -05003333 case 2:
3334 switch (crev) {
3335 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003336 voltage_object = (union voltage_object *)
3337 atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
3338 if (voltage_object &&
3339 (voltage_object->v1.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
3340 return true;
Alex Deucher58653ab2013-02-13 17:04:59 -05003341 break;
3342 case 2:
Alex Deucher779187f2013-03-28 14:47:34 -04003343 voltage_object = (union voltage_object *)
3344 atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
3345 if (voltage_object &&
3346 (voltage_object->v2.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
3347 return true;
Alex Deucher58653ab2013-02-13 17:04:59 -05003348 break;
3349 default:
3350 DRM_ERROR("unknown voltage object table\n");
3351 return false;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003352 }
3353 break;
Alex Deucher58653ab2013-02-13 17:04:59 -05003354 case 3:
3355 switch (crev) {
3356 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003357 if (atom_lookup_voltage_object_v3(&voltage_info->v3,
3358 voltage_type, voltage_mode))
3359 return true;
Alex Deucher58653ab2013-02-13 17:04:59 -05003360 break;
3361 default:
3362 DRM_ERROR("unknown voltage object table\n");
3363 return false;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003364 }
3365 break;
3366 default:
3367 DRM_ERROR("unknown voltage object table\n");
3368 return false;
3369 }
3370
3371 }
3372 return false;
3373}
3374
3375int radeon_atom_get_max_voltage(struct radeon_device *rdev,
3376 u8 voltage_type, u16 *max_voltage)
3377{
3378 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3379 u8 frev, crev;
3380 u16 data_offset, size;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003381 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003382 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003383
3384 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3385 &frev, &crev, &data_offset)) {
3386 voltage_info = (union voltage_object_info *)
3387 (rdev->mode_info.atom_context->bios + data_offset);
3388
3389 switch (crev) {
3390 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003391 voltage_object = (union voltage_object *)
3392 atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
3393 if (voltage_object) {
3394 ATOM_VOLTAGE_FORMULA *formula =
3395 &voltage_object->v1.asFormula;
3396 if (formula->ucFlag & 1)
3397 *max_voltage =
3398 le16_to_cpu(formula->usVoltageBaseLevel) +
3399 formula->ucNumOfVoltageEntries / 2 *
3400 le16_to_cpu(formula->usVoltageStep);
3401 else
3402 *max_voltage =
3403 le16_to_cpu(formula->usVoltageBaseLevel) +
3404 (formula->ucNumOfVoltageEntries - 1) *
3405 le16_to_cpu(formula->usVoltageStep);
3406 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003407 }
3408 break;
3409 case 2:
Alex Deucher779187f2013-03-28 14:47:34 -04003410 voltage_object = (union voltage_object *)
3411 atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
3412 if (voltage_object) {
3413 ATOM_VOLTAGE_FORMULA_V2 *formula =
3414 &voltage_object->v2.asFormula;
3415 if (formula->ucNumOfVoltageEntries) {
3416 *max_voltage =
3417 le16_to_cpu(formula->asVIDAdjustEntries[
3418 formula->ucNumOfVoltageEntries - 1
3419 ].usVoltageValue);
3420 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003421 }
3422 }
3423 break;
3424 default:
3425 DRM_ERROR("unknown voltage object table\n");
3426 return -EINVAL;
3427 }
3428
3429 }
3430 return -EINVAL;
3431}
3432
3433int radeon_atom_get_min_voltage(struct radeon_device *rdev,
3434 u8 voltage_type, u16 *min_voltage)
3435{
3436 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3437 u8 frev, crev;
3438 u16 data_offset, size;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003439 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003440 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003441
3442 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3443 &frev, &crev, &data_offset)) {
3444 voltage_info = (union voltage_object_info *)
3445 (rdev->mode_info.atom_context->bios + data_offset);
3446
3447 switch (crev) {
3448 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003449 voltage_object = (union voltage_object *)
3450 atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
3451 if (voltage_object) {
3452 ATOM_VOLTAGE_FORMULA *formula =
3453 &voltage_object->v1.asFormula;
3454 *min_voltage =
3455 le16_to_cpu(formula->usVoltageBaseLevel);
3456 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003457 }
3458 break;
3459 case 2:
Alex Deucher779187f2013-03-28 14:47:34 -04003460 voltage_object = (union voltage_object *)
3461 atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
3462 if (voltage_object) {
3463 ATOM_VOLTAGE_FORMULA_V2 *formula =
3464 &voltage_object->v2.asFormula;
3465 if (formula->ucNumOfVoltageEntries) {
3466 *min_voltage =
3467 le16_to_cpu(formula->asVIDAdjustEntries[
3468 0
3469 ].usVoltageValue);
3470 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003471 }
3472 }
3473 break;
3474 default:
3475 DRM_ERROR("unknown voltage object table\n");
3476 return -EINVAL;
3477 }
3478
3479 }
3480 return -EINVAL;
3481}
3482
3483int radeon_atom_get_voltage_step(struct radeon_device *rdev,
3484 u8 voltage_type, u16 *voltage_step)
3485{
3486 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3487 u8 frev, crev;
3488 u16 data_offset, size;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003489 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003490 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003491
3492 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3493 &frev, &crev, &data_offset)) {
3494 voltage_info = (union voltage_object_info *)
3495 (rdev->mode_info.atom_context->bios + data_offset);
3496
3497 switch (crev) {
3498 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003499 voltage_object = (union voltage_object *)
3500 atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
3501 if (voltage_object) {
3502 ATOM_VOLTAGE_FORMULA *formula =
3503 &voltage_object->v1.asFormula;
3504 if (formula->ucFlag & 1)
3505 *voltage_step =
3506 (le16_to_cpu(formula->usVoltageStep) + 1) / 2;
3507 else
3508 *voltage_step =
3509 le16_to_cpu(formula->usVoltageStep);
3510 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003511 }
3512 break;
3513 case 2:
3514 return -EINVAL;
3515 default:
3516 DRM_ERROR("unknown voltage object table\n");
3517 return -EINVAL;
3518 }
3519
3520 }
3521 return -EINVAL;
3522}
3523
3524int radeon_atom_round_to_true_voltage(struct radeon_device *rdev,
3525 u8 voltage_type,
3526 u16 nominal_voltage,
3527 u16 *true_voltage)
3528{
3529 u16 min_voltage, max_voltage, voltage_step;
3530
3531 if (radeon_atom_get_max_voltage(rdev, voltage_type, &max_voltage))
3532 return -EINVAL;
3533 if (radeon_atom_get_min_voltage(rdev, voltage_type, &min_voltage))
3534 return -EINVAL;
3535 if (radeon_atom_get_voltage_step(rdev, voltage_type, &voltage_step))
3536 return -EINVAL;
3537
3538 if (nominal_voltage <= min_voltage)
3539 *true_voltage = min_voltage;
3540 else if (nominal_voltage >= max_voltage)
3541 *true_voltage = max_voltage;
3542 else
3543 *true_voltage = min_voltage +
3544 ((nominal_voltage - min_voltage) / voltage_step) *
3545 voltage_step;
3546
3547 return 0;
3548}
3549
3550int radeon_atom_get_voltage_table(struct radeon_device *rdev,
Alex Deucher65171942013-02-13 17:29:54 -05003551 u8 voltage_type, u8 voltage_mode,
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003552 struct atom_voltage_table *voltage_table)
3553{
3554 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3555 u8 frev, crev;
3556 u16 data_offset, size;
Alex Deucher779187f2013-03-28 14:47:34 -04003557 int i, ret;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003558 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003559 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003560
3561 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3562 &frev, &crev, &data_offset)) {
3563 voltage_info = (union voltage_object_info *)
3564 (rdev->mode_info.atom_context->bios + data_offset);
3565
Alex Deucher65171942013-02-13 17:29:54 -05003566 switch (frev) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003567 case 1:
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003568 case 2:
Alex Deucher65171942013-02-13 17:29:54 -05003569 switch (crev) {
3570 case 1:
3571 DRM_ERROR("old table version %d, %d\n", frev, crev);
3572 return -EINVAL;
3573 case 2:
Alex Deucher779187f2013-03-28 14:47:34 -04003574 voltage_object = (union voltage_object *)
3575 atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
3576 if (voltage_object) {
3577 ATOM_VOLTAGE_FORMULA_V2 *formula =
3578 &voltage_object->v2.asFormula;
3579 if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES)
3580 return -EINVAL;
3581 for (i = 0; i < formula->ucNumOfVoltageEntries; i++) {
3582 voltage_table->entries[i].value =
3583 le16_to_cpu(formula->asVIDAdjustEntries[i].usVoltageValue);
3584 ret = radeon_atom_get_voltage_gpio_settings(rdev,
3585 voltage_table->entries[i].value,
3586 voltage_type,
3587 &voltage_table->entries[i].smio_low,
3588 &voltage_table->mask_low);
3589 if (ret)
3590 return ret;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003591 }
Alex Deucher779187f2013-03-28 14:47:34 -04003592 voltage_table->count = formula->ucNumOfVoltageEntries;
3593 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003594 }
Alex Deucher65171942013-02-13 17:29:54 -05003595 break;
3596 default:
3597 DRM_ERROR("unknown voltage object table\n");
3598 return -EINVAL;
3599 }
3600 break;
3601 case 3:
3602 switch (crev) {
3603 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003604 voltage_object = (union voltage_object *)
3605 atom_lookup_voltage_object_v3(&voltage_info->v3,
3606 voltage_type, voltage_mode);
3607 if (voltage_object) {
3608 ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio =
3609 &voltage_object->v3.asGpioVoltageObj;
3610 if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES)
3611 return -EINVAL;
3612 for (i = 0; i < gpio->ucGpioEntryNum; i++) {
3613 voltage_table->entries[i].value =
3614 le16_to_cpu(gpio->asVolGpioLut[i].usVoltageValue);
3615 voltage_table->entries[i].smio_low =
3616 le32_to_cpu(gpio->asVolGpioLut[i].ulVoltageId);
Alex Deucher65171942013-02-13 17:29:54 -05003617 }
Alex Deucher779187f2013-03-28 14:47:34 -04003618 voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal);
3619 voltage_table->count = gpio->ucGpioEntryNum;
3620 voltage_table->phase_delay = gpio->ucPhaseDelay;
3621 return 0;
Alex Deucher65171942013-02-13 17:29:54 -05003622 }
3623 break;
3624 default:
3625 DRM_ERROR("unknown voltage object table\n");
3626 return -EINVAL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003627 }
3628 break;
3629 default:
3630 DRM_ERROR("unknown voltage object table\n");
3631 return -EINVAL;
3632 }
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003633 }
3634 return -EINVAL;
3635}
3636
3637union vram_info {
3638 struct _ATOM_VRAM_INFO_V3 v1_3;
3639 struct _ATOM_VRAM_INFO_V4 v1_4;
3640 struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1;
3641};
3642
3643int radeon_atom_get_memory_info(struct radeon_device *rdev,
3644 u8 module_index, struct atom_memory_info *mem_info)
3645{
3646 int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
3647 u8 frev, crev, i;
3648 u16 data_offset, size;
3649 union vram_info *vram_info;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003650
3651 memset(mem_info, 0, sizeof(struct atom_memory_info));
3652
3653 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3654 &frev, &crev, &data_offset)) {
3655 vram_info = (union vram_info *)
3656 (rdev->mode_info.atom_context->bios + data_offset);
3657 switch (frev) {
3658 case 1:
3659 switch (crev) {
3660 case 3:
3661 /* r6xx */
3662 if (module_index < vram_info->v1_3.ucNumOfVRAMModule) {
3663 ATOM_VRAM_MODULE_V3 *vram_module =
3664 (ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003665
3666 for (i = 0; i < module_index; i++) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003667 if (le16_to_cpu(vram_module->usSize) == 0)
3668 return -EINVAL;
Alex Deucher77c7d502013-07-17 10:52:43 -04003669 vram_module = (ATOM_VRAM_MODULE_V3 *)
3670 ((u8 *)vram_module + le16_to_cpu(vram_module->usSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003671 }
3672 mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf;
3673 mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0;
3674 } else
3675 return -EINVAL;
3676 break;
3677 case 4:
3678 /* r7xx, evergreen */
3679 if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
3680 ATOM_VRAM_MODULE_V4 *vram_module =
3681 (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003682
3683 for (i = 0; i < module_index; i++) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003684 if (le16_to_cpu(vram_module->usModuleSize) == 0)
3685 return -EINVAL;
Alex Deucher77c7d502013-07-17 10:52:43 -04003686 vram_module = (ATOM_VRAM_MODULE_V4 *)
3687 ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003688 }
3689 mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
3690 mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
3691 } else
3692 return -EINVAL;
3693 break;
3694 default:
3695 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3696 return -EINVAL;
3697 }
3698 break;
3699 case 2:
3700 switch (crev) {
3701 case 1:
3702 /* ni */
3703 if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
3704 ATOM_VRAM_MODULE_V7 *vram_module =
3705 (ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003706
3707 for (i = 0; i < module_index; i++) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003708 if (le16_to_cpu(vram_module->usModuleSize) == 0)
3709 return -EINVAL;
Alex Deucher77c7d502013-07-17 10:52:43 -04003710 vram_module = (ATOM_VRAM_MODULE_V7 *)
3711 ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003712 }
3713 mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
3714 mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
3715 } else
3716 return -EINVAL;
3717 break;
3718 default:
3719 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3720 return -EINVAL;
3721 }
3722 break;
3723 default:
3724 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3725 return -EINVAL;
3726 }
3727 return 0;
3728 }
3729 return -EINVAL;
3730}
3731
3732int radeon_atom_get_mclk_range_table(struct radeon_device *rdev,
3733 bool gddr5, u8 module_index,
3734 struct atom_memory_clock_range_table *mclk_range_table)
3735{
3736 int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
3737 u8 frev, crev, i;
3738 u16 data_offset, size;
3739 union vram_info *vram_info;
3740 u32 mem_timing_size = gddr5 ?
3741 sizeof(ATOM_MEMORY_TIMING_FORMAT_V2) : sizeof(ATOM_MEMORY_TIMING_FORMAT);
3742 u8 *p;
3743
3744 memset(mclk_range_table, 0, sizeof(struct atom_memory_clock_range_table));
3745
3746 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3747 &frev, &crev, &data_offset)) {
3748 vram_info = (union vram_info *)
3749 (rdev->mode_info.atom_context->bios + data_offset);
3750 switch (frev) {
3751 case 1:
3752 switch (crev) {
3753 case 3:
3754 DRM_ERROR("old table version %d, %d\n", frev, crev);
3755 return -EINVAL;
3756 case 4:
3757 /* r7xx, evergreen */
3758 if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
3759 ATOM_VRAM_MODULE_V4 *vram_module =
3760 (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003761
3762 for (i = 0; i < module_index; i++) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003763 if (le16_to_cpu(vram_module->usModuleSize) == 0)
3764 return -EINVAL;
Alex Deucher77c7d502013-07-17 10:52:43 -04003765 vram_module = (ATOM_VRAM_MODULE_V4 *)
3766 ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003767 }
3768 mclk_range_table->num_entries = (u8)
Alex Deucher1fa42522013-07-17 10:18:52 -04003769 ((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) /
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003770 mem_timing_size);
Alex Deucher77c7d502013-07-17 10:52:43 -04003771 p = (u8 *)&vram_module->asMemTiming[0];
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003772 for (i = 0; i < mclk_range_table->num_entries; i++) {
Alex Deucher77c7d502013-07-17 10:52:43 -04003773 ATOM_MEMORY_TIMING_FORMAT *format = (ATOM_MEMORY_TIMING_FORMAT *)p;
Alex Deuchere6312272013-07-03 11:18:08 -04003774 mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange);
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003775 p += mem_timing_size;
3776 }
3777 } else
3778 return -EINVAL;
3779 break;
3780 default:
3781 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3782 return -EINVAL;
3783 }
3784 break;
3785 case 2:
3786 DRM_ERROR("new table version %d, %d\n", frev, crev);
3787 return -EINVAL;
3788 default:
3789 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3790 return -EINVAL;
3791 }
3792 return 0;
3793 }
3794 return -EINVAL;
3795}
3796
3797#define MEM_ID_MASK 0xff000000
3798#define MEM_ID_SHIFT 24
3799#define CLOCK_RANGE_MASK 0x00ffffff
3800#define CLOCK_RANGE_SHIFT 0
3801#define LOW_NIBBLE_MASK 0xf
3802#define DATA_EQU_PREV 0
3803#define DATA_FROM_TABLE 4
3804
3805int radeon_atom_init_mc_reg_table(struct radeon_device *rdev,
3806 u8 module_index,
3807 struct atom_mc_reg_table *reg_table)
3808{
3809 int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
3810 u8 frev, crev, num_entries, t_mem_id, num_ranges = 0;
3811 u32 i = 0, j;
3812 u16 data_offset, size;
3813 union vram_info *vram_info;
3814
3815 memset(reg_table, 0, sizeof(struct atom_mc_reg_table));
3816
3817 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3818 &frev, &crev, &data_offset)) {
3819 vram_info = (union vram_info *)
3820 (rdev->mode_info.atom_context->bios + data_offset);
3821 switch (frev) {
3822 case 1:
3823 DRM_ERROR("old table version %d, %d\n", frev, crev);
3824 return -EINVAL;
3825 case 2:
3826 switch (crev) {
3827 case 1:
3828 if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
3829 ATOM_INIT_REG_BLOCK *reg_block =
3830 (ATOM_INIT_REG_BLOCK *)
3831 ((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset));
3832 ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data =
3833 (ATOM_MEMORY_SETTING_DATA_BLOCK *)
3834 ((u8 *)reg_block + (2 * sizeof(u16)) +
3835 le16_to_cpu(reg_block->usRegIndexTblSize));
Alex Deucherf90555c2013-07-17 16:34:12 -04003836 ATOM_INIT_REG_INDEX_FORMAT *format = &reg_block->asRegIndexBuf[0];
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003837 num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) /
3838 sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1;
3839 if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE)
3840 return -EINVAL;
Andre Heider48fa04c2013-07-17 14:02:23 -04003841 while (i < num_entries) {
Alex Deucherf90555c2013-07-17 16:34:12 -04003842 if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER)
Andre Heider48fa04c2013-07-17 14:02:23 -04003843 break;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003844 reg_table->mc_reg_address[i].s1 =
Alex Deucherf90555c2013-07-17 16:34:12 -04003845 (u16)(le16_to_cpu(format->usRegIndex));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003846 reg_table->mc_reg_address[i].pre_reg_data =
Alex Deucherf90555c2013-07-17 16:34:12 -04003847 (u8)(format->ucPreRegDataLength);
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003848 i++;
Alex Deucherf90555c2013-07-17 16:34:12 -04003849 format = (ATOM_INIT_REG_INDEX_FORMAT *)
3850 ((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003851 }
3852 reg_table->last = i;
3853 while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) &&
3854 (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {
3855 t_mem_id = (u8)((*(u32 *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
3856 if (module_index == t_mem_id) {
3857 reg_table->mc_reg_table_entry[num_ranges].mclk_max =
3858 (u32)((*(u32 *)reg_data & CLOCK_RANGE_MASK) >> CLOCK_RANGE_SHIFT);
3859 for (i = 0, j = 1; i < reg_table->last; i++) {
3860 if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
3861 reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
3862 (u32)*((u32 *)reg_data + j);
3863 j++;
3864 } else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
3865 reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
3866 reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1];
3867 }
3868 }
3869 num_ranges++;
3870 }
Alex Deucher4da18e22013-07-01 13:33:53 -04003871 reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
3872 ((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003873 }
3874 if (*(u32 *)reg_data != END_OF_REG_DATA_BLOCK)
3875 return -EINVAL;
3876 reg_table->num_entries = num_ranges;
3877 } else
3878 return -EINVAL;
3879 break;
3880 default:
3881 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3882 return -EINVAL;
3883 }
3884 break;
3885 default:
3886 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3887 return -EINVAL;
3888 }
3889 return 0;
3890 }
3891 return -EINVAL;
3892}
3893
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003894void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
3895{
3896 struct radeon_device *rdev = dev->dev_private;
3897 uint32_t bios_2_scratch, bios_6_scratch;
3898
3899 if (rdev->family >= CHIP_R600) {
Dave Airlie4ce001a2009-08-13 16:32:14 +10003900 bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003901 bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
3902 } else {
Dave Airlie4ce001a2009-08-13 16:32:14 +10003903 bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003904 bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
3905 }
3906
3907 /* let the bios control the backlight */
3908 bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;
3909
3910 /* tell the bios not to handle mode switching */
Alex Deucher87364762011-02-02 19:46:06 -05003911 bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003912
3913 if (rdev->family >= CHIP_R600) {
3914 WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
3915 WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
3916 } else {
3917 WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
3918 WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
3919 }
3920
3921}
3922
Yang Zhaof657c2a2009-09-15 12:21:01 +10003923void radeon_save_bios_scratch_regs(struct radeon_device *rdev)
3924{
3925 uint32_t scratch_reg;
3926 int i;
3927
3928 if (rdev->family >= CHIP_R600)
3929 scratch_reg = R600_BIOS_0_SCRATCH;
3930 else
3931 scratch_reg = RADEON_BIOS_0_SCRATCH;
3932
3933 for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++)
3934 rdev->bios_scratch[i] = RREG32(scratch_reg + (i * 4));
3935}
3936
3937void radeon_restore_bios_scratch_regs(struct radeon_device *rdev)
3938{
3939 uint32_t scratch_reg;
3940 int i;
3941
3942 if (rdev->family >= CHIP_R600)
3943 scratch_reg = R600_BIOS_0_SCRATCH;
3944 else
3945 scratch_reg = RADEON_BIOS_0_SCRATCH;
3946
3947 for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++)
3948 WREG32(scratch_reg + (i * 4), rdev->bios_scratch[i]);
3949}
3950
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003951void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock)
3952{
3953 struct drm_device *dev = encoder->dev;
3954 struct radeon_device *rdev = dev->dev_private;
3955 uint32_t bios_6_scratch;
3956
3957 if (rdev->family >= CHIP_R600)
3958 bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
3959 else
3960 bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
3961
Alex Deucher87364762011-02-02 19:46:06 -05003962 if (lock) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003963 bios_6_scratch |= ATOM_S6_CRITICAL_STATE;
Alex Deucher87364762011-02-02 19:46:06 -05003964 bios_6_scratch &= ~ATOM_S6_ACC_MODE;
3965 } else {
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003966 bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;
Alex Deucher87364762011-02-02 19:46:06 -05003967 bios_6_scratch |= ATOM_S6_ACC_MODE;
3968 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003969
3970 if (rdev->family >= CHIP_R600)
3971 WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
3972 else
3973 WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
3974}
3975
3976/* at some point we may want to break this out into individual functions */
3977void
3978radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
3979 struct drm_encoder *encoder,
3980 bool connected)
3981{
3982 struct drm_device *dev = connector->dev;
3983 struct radeon_device *rdev = dev->dev_private;
3984 struct radeon_connector *radeon_connector =
3985 to_radeon_connector(connector);
3986 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
3987 uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch;
3988
3989 if (rdev->family >= CHIP_R600) {
3990 bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH);
3991 bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
3992 bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
3993 } else {
3994 bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
3995 bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
3996 bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
3997 }
3998
3999 if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) &&
4000 (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) {
4001 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004002 DRM_DEBUG_KMS("TV1 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004003 bios_3_scratch |= ATOM_S3_TV1_ACTIVE;
4004 bios_6_scratch |= ATOM_S6_ACC_REQ_TV1;
4005 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004006 DRM_DEBUG_KMS("TV1 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004007 bios_0_scratch &= ~ATOM_S0_TV1_MASK;
4008 bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE;
4009 bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1;
4010 }
4011 }
4012 if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) &&
4013 (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) {
4014 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004015 DRM_DEBUG_KMS("CV connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004016 bios_3_scratch |= ATOM_S3_CV_ACTIVE;
4017 bios_6_scratch |= ATOM_S6_ACC_REQ_CV;
4018 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004019 DRM_DEBUG_KMS("CV disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004020 bios_0_scratch &= ~ATOM_S0_CV_MASK;
4021 bios_3_scratch &= ~ATOM_S3_CV_ACTIVE;
4022 bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV;
4023 }
4024 }
4025 if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
4026 (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
4027 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004028 DRM_DEBUG_KMS("LCD1 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004029 bios_0_scratch |= ATOM_S0_LCD1;
4030 bios_3_scratch |= ATOM_S3_LCD1_ACTIVE;
4031 bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1;
4032 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004033 DRM_DEBUG_KMS("LCD1 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004034 bios_0_scratch &= ~ATOM_S0_LCD1;
4035 bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE;
4036 bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1;
4037 }
4038 }
4039 if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
4040 (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
4041 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004042 DRM_DEBUG_KMS("CRT1 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004043 bios_0_scratch |= ATOM_S0_CRT1_COLOR;
4044 bios_3_scratch |= ATOM_S3_CRT1_ACTIVE;
4045 bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1;
4046 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004047 DRM_DEBUG_KMS("CRT1 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004048 bios_0_scratch &= ~ATOM_S0_CRT1_MASK;
4049 bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE;
4050 bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1;
4051 }
4052 }
4053 if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
4054 (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
4055 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004056 DRM_DEBUG_KMS("CRT2 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004057 bios_0_scratch |= ATOM_S0_CRT2_COLOR;
4058 bios_3_scratch |= ATOM_S3_CRT2_ACTIVE;
4059 bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2;
4060 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004061 DRM_DEBUG_KMS("CRT2 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004062 bios_0_scratch &= ~ATOM_S0_CRT2_MASK;
4063 bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE;
4064 bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2;
4065 }
4066 }
4067 if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
4068 (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
4069 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004070 DRM_DEBUG_KMS("DFP1 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004071 bios_0_scratch |= ATOM_S0_DFP1;
4072 bios_3_scratch |= ATOM_S3_DFP1_ACTIVE;
4073 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1;
4074 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004075 DRM_DEBUG_KMS("DFP1 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004076 bios_0_scratch &= ~ATOM_S0_DFP1;
4077 bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE;
4078 bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1;
4079 }
4080 }
4081 if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
4082 (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
4083 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004084 DRM_DEBUG_KMS("DFP2 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004085 bios_0_scratch |= ATOM_S0_DFP2;
4086 bios_3_scratch |= ATOM_S3_DFP2_ACTIVE;
4087 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2;
4088 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004089 DRM_DEBUG_KMS("DFP2 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004090 bios_0_scratch &= ~ATOM_S0_DFP2;
4091 bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE;
4092 bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2;
4093 }
4094 }
4095 if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) &&
4096 (radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) {
4097 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004098 DRM_DEBUG_KMS("DFP3 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004099 bios_0_scratch |= ATOM_S0_DFP3;
4100 bios_3_scratch |= ATOM_S3_DFP3_ACTIVE;
4101 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3;
4102 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004103 DRM_DEBUG_KMS("DFP3 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004104 bios_0_scratch &= ~ATOM_S0_DFP3;
4105 bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE;
4106 bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3;
4107 }
4108 }
4109 if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) &&
4110 (radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) {
4111 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004112 DRM_DEBUG_KMS("DFP4 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004113 bios_0_scratch |= ATOM_S0_DFP4;
4114 bios_3_scratch |= ATOM_S3_DFP4_ACTIVE;
4115 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4;
4116 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004117 DRM_DEBUG_KMS("DFP4 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004118 bios_0_scratch &= ~ATOM_S0_DFP4;
4119 bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE;
4120 bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4;
4121 }
4122 }
4123 if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) &&
4124 (radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) {
4125 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004126 DRM_DEBUG_KMS("DFP5 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004127 bios_0_scratch |= ATOM_S0_DFP5;
4128 bios_3_scratch |= ATOM_S3_DFP5_ACTIVE;
4129 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5;
4130 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004131 DRM_DEBUG_KMS("DFP5 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004132 bios_0_scratch &= ~ATOM_S0_DFP5;
4133 bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE;
4134 bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5;
4135 }
4136 }
Alex Deucher6f9f8a62012-02-13 08:59:41 -05004137 if ((radeon_encoder->devices & ATOM_DEVICE_DFP6_SUPPORT) &&
4138 (radeon_connector->devices & ATOM_DEVICE_DFP6_SUPPORT)) {
4139 if (connected) {
4140 DRM_DEBUG_KMS("DFP6 connected\n");
4141 bios_0_scratch |= ATOM_S0_DFP6;
4142 bios_3_scratch |= ATOM_S3_DFP6_ACTIVE;
4143 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP6;
4144 } else {
4145 DRM_DEBUG_KMS("DFP6 disconnected\n");
4146 bios_0_scratch &= ~ATOM_S0_DFP6;
4147 bios_3_scratch &= ~ATOM_S3_DFP6_ACTIVE;
4148 bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP6;
4149 }
4150 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004151
4152 if (rdev->family >= CHIP_R600) {
4153 WREG32(R600_BIOS_0_SCRATCH, bios_0_scratch);
4154 WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
4155 WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
4156 } else {
4157 WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch);
4158 WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
4159 WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
4160 }
4161}
4162
4163void
4164radeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc)
4165{
4166 struct drm_device *dev = encoder->dev;
4167 struct radeon_device *rdev = dev->dev_private;
4168 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4169 uint32_t bios_3_scratch;
4170
Alex Deucher6f9f8a62012-02-13 08:59:41 -05004171 if (ASIC_IS_DCE4(rdev))
4172 return;
4173
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004174 if (rdev->family >= CHIP_R600)
4175 bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
4176 else
4177 bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
4178
4179 if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
4180 bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE;
4181 bios_3_scratch |= (crtc << 18);
4182 }
4183 if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
4184 bios_3_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE;
4185 bios_3_scratch |= (crtc << 24);
4186 }
4187 if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
4188 bios_3_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE;
4189 bios_3_scratch |= (crtc << 16);
4190 }
4191 if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
4192 bios_3_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE;
4193 bios_3_scratch |= (crtc << 20);
4194 }
4195 if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
4196 bios_3_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE;
4197 bios_3_scratch |= (crtc << 17);
4198 }
4199 if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
4200 bios_3_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE;
4201 bios_3_scratch |= (crtc << 19);
4202 }
4203 if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
4204 bios_3_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE;
4205 bios_3_scratch |= (crtc << 23);
4206 }
4207 if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
4208 bios_3_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE;
4209 bios_3_scratch |= (crtc << 25);
4210 }
4211
4212 if (rdev->family >= CHIP_R600)
4213 WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
4214 else
4215 WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
4216}
4217
4218void
4219radeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on)
4220{
4221 struct drm_device *dev = encoder->dev;
4222 struct radeon_device *rdev = dev->dev_private;
4223 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4224 uint32_t bios_2_scratch;
4225
Alex Deucher3ac0eb62012-02-19 21:42:03 -05004226 if (ASIC_IS_DCE4(rdev))
4227 return;
4228
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004229 if (rdev->family >= CHIP_R600)
4230 bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
4231 else
4232 bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
4233
4234 if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
4235 if (on)
4236 bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE;
4237 else
4238 bios_2_scratch |= ATOM_S2_TV1_DPMS_STATE;
4239 }
4240 if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
4241 if (on)
4242 bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE;
4243 else
4244 bios_2_scratch |= ATOM_S2_CV_DPMS_STATE;
4245 }
4246 if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
4247 if (on)
4248 bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE;
4249 else
4250 bios_2_scratch |= ATOM_S2_CRT1_DPMS_STATE;
4251 }
4252 if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
4253 if (on)
4254 bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE;
4255 else
4256 bios_2_scratch |= ATOM_S2_CRT2_DPMS_STATE;
4257 }
4258 if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
4259 if (on)
4260 bios_2_scratch &= ~ATOM_S2_LCD1_DPMS_STATE;
4261 else
4262 bios_2_scratch |= ATOM_S2_LCD1_DPMS_STATE;
4263 }
4264 if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
4265 if (on)
4266 bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE;
4267 else
4268 bios_2_scratch |= ATOM_S2_DFP1_DPMS_STATE;
4269 }
4270 if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
4271 if (on)
4272 bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE;
4273 else
4274 bios_2_scratch |= ATOM_S2_DFP2_DPMS_STATE;
4275 }
4276 if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
4277 if (on)
4278 bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE;
4279 else
4280 bios_2_scratch |= ATOM_S2_DFP3_DPMS_STATE;
4281 }
4282 if (radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) {
4283 if (on)
4284 bios_2_scratch &= ~ATOM_S2_DFP4_DPMS_STATE;
4285 else
4286 bios_2_scratch |= ATOM_S2_DFP4_DPMS_STATE;
4287 }
4288 if (radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) {
4289 if (on)
4290 bios_2_scratch &= ~ATOM_S2_DFP5_DPMS_STATE;
4291 else
4292 bios_2_scratch |= ATOM_S2_DFP5_DPMS_STATE;
4293 }
4294
4295 if (rdev->family >= CHIP_R600)
4296 WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
4297 else
4298 WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
4299}