blob: 4ac5f4027620c69c638b316822d5ab481b2f8810 [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));
714 int enum_id;
715
716 router.router_id = router_obj_id;
717 for (enum_id = 0; enum_id < router_src_dst_table->ucNumberOfDst;
718 enum_id++) {
719 if (le16_to_cpu(path->usConnObjectId) ==
720 le16_to_cpu(router_src_dst_table->usDstObjectID[enum_id]))
721 break;
722 }
723
John Lindgren97ea5302011-03-24 23:28:31 +0000724 while (record->ucRecordSize > 0 &&
725 record->ucRecordType > 0 &&
Alex Deucher26b5bc92010-08-05 21:21:18 -0400726 record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
727 switch (record->ucRecordType) {
728 case ATOM_I2C_RECORD_TYPE:
729 i2c_record =
730 (ATOM_I2C_RECORD *)
731 record;
732 i2c_config =
733 (ATOM_I2C_ID_CONFIG_ACCESS *)
734 &i2c_record->sucI2cId;
735 router.i2c_info =
736 radeon_lookup_i2c_gpio(rdev,
737 i2c_config->
738 ucAccess);
739 router.i2c_addr = i2c_record->ucI2CAddr >> 1;
740 break;
741 case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
742 ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
743 record;
Alex Deucherfb939df2010-11-08 16:08:29 +0000744 router.ddc_valid = true;
745 router.ddc_mux_type = ddc_path->ucMuxType;
746 router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;
747 router.ddc_mux_state = ddc_path->ucMuxState[enum_id];
748 break;
749 case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
750 cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)
751 record;
752 router.cd_valid = true;
753 router.cd_mux_type = cd_path->ucMuxType;
754 router.cd_mux_control_pin = cd_path->ucMuxControlPin;
755 router.cd_mux_state = cd_path->ucMuxState[enum_id];
Alex Deucher26b5bc92010-08-05 21:21:18 -0400756 break;
757 }
758 record = (ATOM_COMMON_RECORD_HEADER *)
759 ((char *)record + record->ucRecordSize);
760 }
761 }
762 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200763 }
764 }
765
Alex Deuchereed45b32009-12-04 14:45:27 -0500766 /* look up gpio for ddc, hpd */
Alex Deucher2bfcc0f2010-05-18 19:26:46 -0400767 ddc_bus.valid = false;
768 hpd.hpd = RADEON_HPD_NONE;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200769 if ((le16_to_cpu(path->usDeviceTag) &
Alex Deuchereed45b32009-12-04 14:45:27 -0500770 (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200771 for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
772 if (le16_to_cpu(path->usConnObjectId) ==
773 le16_to_cpu(con_obj->asObjects[j].
774 usObjectID)) {
775 ATOM_COMMON_RECORD_HEADER
776 *record =
777 (ATOM_COMMON_RECORD_HEADER
778 *)
779 (ctx->bios + data_offset +
780 le16_to_cpu(con_obj->
781 asObjects[j].
782 usRecordOffset));
783 ATOM_I2C_RECORD *i2c_record;
Alex Deuchereed45b32009-12-04 14:45:27 -0500784 ATOM_HPD_INT_RECORD *hpd_record;
Alex Deucherd3f420d2009-12-08 14:30:49 -0500785 ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
Alex Deucher6a93cb22009-11-23 17:39:28 -0500786
John Lindgren97ea5302011-03-24 23:28:31 +0000787 while (record->ucRecordSize > 0 &&
788 record->ucRecordType > 0 &&
789 record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
Alex Deuchereed45b32009-12-04 14:45:27 -0500790 switch (record->ucRecordType) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200791 case ATOM_I2C_RECORD_TYPE:
792 i2c_record =
Alex Deuchereed45b32009-12-04 14:45:27 -0500793 (ATOM_I2C_RECORD *)
794 record;
Alex Deucherd3f420d2009-12-08 14:30:49 -0500795 i2c_config =
796 (ATOM_I2C_ID_CONFIG_ACCESS *)
797 &i2c_record->sucI2cId;
Alex Deuchereed45b32009-12-04 14:45:27 -0500798 ddc_bus = radeon_lookup_i2c_gpio(rdev,
Alex Deucherd3f420d2009-12-08 14:30:49 -0500799 i2c_config->
800 ucAccess);
Alex Deuchereed45b32009-12-04 14:45:27 -0500801 break;
802 case ATOM_HPD_INT_RECORD_TYPE:
803 hpd_record =
804 (ATOM_HPD_INT_RECORD *)
805 record;
806 gpio = radeon_lookup_gpio(rdev,
807 hpd_record->ucHPDIntGPIOID);
808 hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
809 hpd.plugged_state = hpd_record->ucPlugged_PinState;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200810 break;
811 }
812 record =
813 (ATOM_COMMON_RECORD_HEADER
814 *) ((char *)record
815 +
816 record->
817 ucRecordSize);
818 }
819 break;
820 }
821 }
Alex Deuchereed45b32009-12-04 14:45:27 -0500822 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200823
Alex Deucherbcc1c2a2010-01-12 17:54:34 -0500824 /* needed for aux chan transactions */
Alex Deucher8e36ed02010-05-18 19:26:47 -0400825 ddc_bus.hpd = hpd.hpd;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -0500826
Alex Deucher705af9c2009-09-10 16:31:13 -0400827 conn_id = le16_to_cpu(path->usConnObjectId);
828
829 if (!radeon_atom_apply_quirks
830 (dev, le16_to_cpu(path->usDeviceTag), &connector_type,
Alex Deuchereed45b32009-12-04 14:45:27 -0500831 &ddc_bus, &conn_id, &hpd))
Alex Deucher705af9c2009-09-10 16:31:13 -0400832 continue;
833
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200834 radeon_add_atom_connector(dev,
Alex Deucher705af9c2009-09-10 16:31:13 -0400835 conn_id,
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200836 le16_to_cpu(path->
837 usDeviceTag),
838 connector_type, &ddc_bus,
Alex Deucher5137ee92010-08-12 18:58:47 -0400839 igp_lane_info,
Alex Deuchereed45b32009-12-04 14:45:27 -0500840 connector_object_id,
Alex Deucher26b5bc92010-08-05 21:21:18 -0400841 &hpd,
842 &router);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200843
844 }
845 }
846
847 radeon_link_encoder_connector(dev);
848
849 return true;
850}
851
Alex Deucherb75fad02009-11-05 13:16:01 -0500852static uint16_t atombios_get_connector_object_id(struct drm_device *dev,
853 int connector_type,
854 uint16_t devices)
855{
856 struct radeon_device *rdev = dev->dev_private;
857
858 if (rdev->flags & RADEON_IS_IGP) {
859 return supported_devices_connector_object_id_convert
860 [connector_type];
861 } else if (((connector_type == DRM_MODE_CONNECTOR_DVII) ||
862 (connector_type == DRM_MODE_CONNECTOR_DVID)) &&
863 (devices & ATOM_DEVICE_DFP2_SUPPORT)) {
864 struct radeon_mode_info *mode_info = &rdev->mode_info;
865 struct atom_context *ctx = mode_info->atom_context;
866 int index = GetIndexIntoMasterTable(DATA, XTMDS_Info);
867 uint16_t size, data_offset;
868 uint8_t frev, crev;
869 ATOM_XTMDS_INFO *xtmds;
870
Alex Deuchera084e6e2010-03-18 01:04:01 -0400871 if (atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) {
872 xtmds = (ATOM_XTMDS_INFO *)(ctx->bios + data_offset);
Alex Deucherb75fad02009-11-05 13:16:01 -0500873
Alex Deuchera084e6e2010-03-18 01:04:01 -0400874 if (xtmds->ucSupportedLink & ATOM_XTMDS_SUPPORTED_DUALLINK) {
875 if (connector_type == DRM_MODE_CONNECTOR_DVII)
876 return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I;
877 else
878 return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D;
879 } else {
880 if (connector_type == DRM_MODE_CONNECTOR_DVII)
881 return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I;
882 else
883 return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D;
884 }
885 } else
886 return supported_devices_connector_object_id_convert
887 [connector_type];
Alex Deucherb75fad02009-11-05 13:16:01 -0500888 } else {
889 return supported_devices_connector_object_id_convert
890 [connector_type];
891 }
892}
893
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200894struct bios_connector {
895 bool valid;
Alex Deucher705af9c2009-09-10 16:31:13 -0400896 uint16_t line_mux;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200897 uint16_t devices;
898 int connector_type;
899 struct radeon_i2c_bus_rec ddc_bus;
Alex Deuchereed45b32009-12-04 14:45:27 -0500900 struct radeon_hpd hpd;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200901};
902
903bool radeon_get_atom_connector_info_from_supported_devices_table(struct
904 drm_device
905 *dev)
906{
907 struct radeon_device *rdev = dev->dev_private;
908 struct radeon_mode_info *mode_info = &rdev->mode_info;
909 struct atom_context *ctx = mode_info->atom_context;
910 int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo);
911 uint16_t size, data_offset;
912 uint8_t frev, crev;
913 uint16_t device_support;
914 uint8_t dac;
915 union atom_supported_devices *supported_devices;
Alex Deuchereed45b32009-12-04 14:45:27 -0500916 int i, j, max_device;
Prarit Bhargavaf49d2732010-05-24 10:24:07 +1000917 struct bios_connector *bios_connectors;
918 size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
Alex Deucher26b5bc92010-08-05 21:21:18 -0400919 struct radeon_router router;
920
Alex Deucherfb939df2010-11-08 16:08:29 +0000921 router.ddc_valid = false;
922 router.cd_valid = false;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200923
Prarit Bhargavaf49d2732010-05-24 10:24:07 +1000924 bios_connectors = kzalloc(bc_size, GFP_KERNEL);
925 if (!bios_connectors)
Alex Deuchera084e6e2010-03-18 01:04:01 -0400926 return false;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200927
Prarit Bhargavaf49d2732010-05-24 10:24:07 +1000928 if (!atom_parse_data_header(ctx, index, &size, &frev, &crev,
929 &data_offset)) {
930 kfree(bios_connectors);
931 return false;
932 }
933
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200934 supported_devices =
935 (union atom_supported_devices *)(ctx->bios + data_offset);
936
937 device_support = le16_to_cpu(supported_devices->info.usDeviceSupport);
938
Alex Deuchereed45b32009-12-04 14:45:27 -0500939 if (frev > 1)
940 max_device = ATOM_MAX_SUPPORTED_DEVICE;
941 else
942 max_device = ATOM_MAX_SUPPORTED_DEVICE_INFO;
943
944 for (i = 0; i < max_device; i++) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200945 ATOM_CONNECTOR_INFO_I2C ci =
946 supported_devices->info.asConnInfo[i];
947
948 bios_connectors[i].valid = false;
949
950 if (!(device_support & (1 << i))) {
951 continue;
952 }
953
954 if (i == ATOM_DEVICE_CV_INDEX) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +1000955 DRM_DEBUG_KMS("Skipping Component Video\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200956 continue;
957 }
958
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200959 bios_connectors[i].connector_type =
960 supported_devices_connector_convert[ci.sucConnectorInfo.
961 sbfAccess.
962 bfConnectorType];
963
964 if (bios_connectors[i].connector_type ==
965 DRM_MODE_CONNECTOR_Unknown)
966 continue;
967
968 dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC;
969
Alex Deucherd3f420d2009-12-08 14:30:49 -0500970 bios_connectors[i].line_mux =
971 ci.sucI2cId.ucAccess;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200972
973 /* give tv unique connector ids */
974 if (i == ATOM_DEVICE_TV1_INDEX) {
975 bios_connectors[i].ddc_bus.valid = false;
976 bios_connectors[i].line_mux = 50;
977 } else if (i == ATOM_DEVICE_TV2_INDEX) {
978 bios_connectors[i].ddc_bus.valid = false;
979 bios_connectors[i].line_mux = 51;
980 } else if (i == ATOM_DEVICE_CV_INDEX) {
981 bios_connectors[i].ddc_bus.valid = false;
982 bios_connectors[i].line_mux = 52;
983 } else
984 bios_connectors[i].ddc_bus =
Alex Deuchereed45b32009-12-04 14:45:27 -0500985 radeon_lookup_i2c_gpio(rdev,
986 bios_connectors[i].line_mux);
987
988 if ((crev > 1) && (frev > 1)) {
989 u8 isb = supported_devices->info_2d1.asIntSrcInfo[i].ucIntSrcBitmap;
990 switch (isb) {
991 case 0x4:
992 bios_connectors[i].hpd.hpd = RADEON_HPD_1;
993 break;
994 case 0xa:
995 bios_connectors[i].hpd.hpd = RADEON_HPD_2;
996 break;
997 default:
998 bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
999 break;
1000 }
1001 } else {
1002 if (i == ATOM_DEVICE_DFP1_INDEX)
1003 bios_connectors[i].hpd.hpd = RADEON_HPD_1;
1004 else if (i == ATOM_DEVICE_DFP2_INDEX)
1005 bios_connectors[i].hpd.hpd = RADEON_HPD_2;
1006 else
1007 bios_connectors[i].hpd.hpd = RADEON_HPD_NONE;
1008 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001009
1010 /* Always set the connector type to VGA for CRT1/CRT2. if they are
1011 * shared with a DVI port, we'll pick up the DVI connector when we
1012 * merge the outputs. Some bioses incorrectly list VGA ports as DVI.
1013 */
1014 if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX)
1015 bios_connectors[i].connector_type =
1016 DRM_MODE_CONNECTOR_VGA;
1017
1018 if (!radeon_atom_apply_quirks
1019 (dev, (1 << i), &bios_connectors[i].connector_type,
Alex Deuchereed45b32009-12-04 14:45:27 -05001020 &bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux,
1021 &bios_connectors[i].hpd))
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001022 continue;
1023
1024 bios_connectors[i].valid = true;
1025 bios_connectors[i].devices = (1 << i);
1026
1027 if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom)
1028 radeon_add_atom_encoder(dev,
Alex Deucher5137ee92010-08-12 18:58:47 -04001029 radeon_get_encoder_enum(dev,
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001030 (1 << i),
1031 dac),
Alex Deucher36868bd2011-01-06 21:19:21 -05001032 (1 << i),
1033 0);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001034 else
1035 radeon_add_legacy_encoder(dev,
Alex Deucher5137ee92010-08-12 18:58:47 -04001036 radeon_get_encoder_enum(dev,
Alex Deucherf56cd642009-12-18 11:28:22 -05001037 (1 << i),
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001038 dac),
1039 (1 << i));
1040 }
1041
1042 /* combine shared connectors */
Alex Deuchereed45b32009-12-04 14:45:27 -05001043 for (i = 0; i < max_device; i++) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001044 if (bios_connectors[i].valid) {
Alex Deuchereed45b32009-12-04 14:45:27 -05001045 for (j = 0; j < max_device; j++) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001046 if (bios_connectors[j].valid && (i != j)) {
1047 if (bios_connectors[i].line_mux ==
1048 bios_connectors[j].line_mux) {
Alex Deucherf56cd642009-12-18 11:28:22 -05001049 /* make sure not to combine LVDS */
1050 if (bios_connectors[i].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1051 bios_connectors[i].line_mux = 53;
1052 bios_connectors[i].ddc_bus.valid = false;
1053 continue;
1054 }
1055 if (bios_connectors[j].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1056 bios_connectors[j].line_mux = 53;
1057 bios_connectors[j].ddc_bus.valid = false;
1058 continue;
1059 }
1060 /* combine analog and digital for DVI-I */
1061 if (((bios_connectors[i].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
1062 (bios_connectors[j].devices & (ATOM_DEVICE_CRT_SUPPORT))) ||
1063 ((bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
1064 (bios_connectors[i].devices & (ATOM_DEVICE_CRT_SUPPORT)))) {
1065 bios_connectors[i].devices |=
1066 bios_connectors[j].devices;
1067 bios_connectors[i].connector_type =
1068 DRM_MODE_CONNECTOR_DVII;
1069 if (bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT))
Alex Deuchereed45b32009-12-04 14:45:27 -05001070 bios_connectors[i].hpd =
1071 bios_connectors[j].hpd;
Alex Deucherf56cd642009-12-18 11:28:22 -05001072 bios_connectors[j].valid = false;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001073 }
1074 }
1075 }
1076 }
1077 }
1078 }
1079
1080 /* add the connectors */
Alex Deuchereed45b32009-12-04 14:45:27 -05001081 for (i = 0; i < max_device; i++) {
Alex Deucherb75fad02009-11-05 13:16:01 -05001082 if (bios_connectors[i].valid) {
1083 uint16_t connector_object_id =
1084 atombios_get_connector_object_id(dev,
1085 bios_connectors[i].connector_type,
1086 bios_connectors[i].devices);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001087 radeon_add_atom_connector(dev,
1088 bios_connectors[i].line_mux,
1089 bios_connectors[i].devices,
1090 bios_connectors[i].
1091 connector_type,
1092 &bios_connectors[i].ddc_bus,
Alex Deucher5137ee92010-08-12 18:58:47 -04001093 0,
Alex Deuchereed45b32009-12-04 14:45:27 -05001094 connector_object_id,
Alex Deucher26b5bc92010-08-05 21:21:18 -04001095 &bios_connectors[i].hpd,
1096 &router);
Alex Deucherb75fad02009-11-05 13:16:01 -05001097 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001098 }
1099
1100 radeon_link_encoder_connector(dev);
1101
Prarit Bhargavaf49d2732010-05-24 10:24:07 +10001102 kfree(bios_connectors);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001103 return true;
1104}
1105
1106union firmware_info {
1107 ATOM_FIRMWARE_INFO info;
1108 ATOM_FIRMWARE_INFO_V1_2 info_12;
1109 ATOM_FIRMWARE_INFO_V1_3 info_13;
1110 ATOM_FIRMWARE_INFO_V1_4 info_14;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001111 ATOM_FIRMWARE_INFO_V2_1 info_21;
Alex Deucherf82b3dd2011-01-06 21:19:15 -05001112 ATOM_FIRMWARE_INFO_V2_2 info_22;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001113};
1114
1115bool radeon_atom_get_clock_info(struct drm_device *dev)
1116{
1117 struct radeon_device *rdev = dev->dev_private;
1118 struct radeon_mode_info *mode_info = &rdev->mode_info;
1119 int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
1120 union firmware_info *firmware_info;
1121 uint8_t frev, crev;
1122 struct radeon_pll *p1pll = &rdev->clock.p1pll;
1123 struct radeon_pll *p2pll = &rdev->clock.p2pll;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001124 struct radeon_pll *dcpll = &rdev->clock.dcpll;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001125 struct radeon_pll *spll = &rdev->clock.spll;
1126 struct radeon_pll *mpll = &rdev->clock.mpll;
1127 uint16_t data_offset;
1128
Alex Deuchera084e6e2010-03-18 01:04:01 -04001129 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1130 &frev, &crev, &data_offset)) {
1131 firmware_info =
1132 (union firmware_info *)(mode_info->atom_context->bios +
1133 data_offset);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001134 /* pixel clocks */
1135 p1pll->reference_freq =
1136 le16_to_cpu(firmware_info->info.usReferenceClock);
1137 p1pll->reference_div = 0;
1138
Mathias Fröhlichbc293e52009-10-19 17:49:49 -04001139 if (crev < 2)
1140 p1pll->pll_out_min =
1141 le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
1142 else
1143 p1pll->pll_out_min =
1144 le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001145 p1pll->pll_out_max =
1146 le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
1147
Alex Deucher86cb2bb2010-03-08 12:55:16 -05001148 if (crev >= 4) {
1149 p1pll->lcd_pll_out_min =
1150 le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
1151 if (p1pll->lcd_pll_out_min == 0)
1152 p1pll->lcd_pll_out_min = p1pll->pll_out_min;
1153 p1pll->lcd_pll_out_max =
1154 le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
1155 if (p1pll->lcd_pll_out_max == 0)
1156 p1pll->lcd_pll_out_max = p1pll->pll_out_max;
1157 } else {
1158 p1pll->lcd_pll_out_min = p1pll->pll_out_min;
1159 p1pll->lcd_pll_out_max = p1pll->pll_out_max;
1160 }
1161
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001162 if (p1pll->pll_out_min == 0) {
1163 if (ASIC_IS_AVIVO(rdev))
1164 p1pll->pll_out_min = 64800;
1165 else
1166 p1pll->pll_out_min = 20000;
1167 }
1168
1169 p1pll->pll_in_min =
1170 le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input);
1171 p1pll->pll_in_max =
1172 le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input);
1173
1174 *p2pll = *p1pll;
1175
1176 /* system clock */
Alex Deucherf82b3dd2011-01-06 21:19:15 -05001177 if (ASIC_IS_DCE4(rdev))
1178 spll->reference_freq =
1179 le16_to_cpu(firmware_info->info_21.usCoreReferenceClock);
1180 else
1181 spll->reference_freq =
1182 le16_to_cpu(firmware_info->info.usReferenceClock);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001183 spll->reference_div = 0;
1184
1185 spll->pll_out_min =
1186 le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output);
1187 spll->pll_out_max =
1188 le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output);
1189
1190 /* ??? */
1191 if (spll->pll_out_min == 0) {
1192 if (ASIC_IS_AVIVO(rdev))
1193 spll->pll_out_min = 64800;
1194 else
1195 spll->pll_out_min = 20000;
1196 }
1197
1198 spll->pll_in_min =
1199 le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input);
1200 spll->pll_in_max =
1201 le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input);
1202
1203 /* memory clock */
Alex Deucherf82b3dd2011-01-06 21:19:15 -05001204 if (ASIC_IS_DCE4(rdev))
1205 mpll->reference_freq =
1206 le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock);
1207 else
1208 mpll->reference_freq =
1209 le16_to_cpu(firmware_info->info.usReferenceClock);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001210 mpll->reference_div = 0;
1211
1212 mpll->pll_out_min =
1213 le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output);
1214 mpll->pll_out_max =
1215 le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output);
1216
1217 /* ??? */
1218 if (mpll->pll_out_min == 0) {
1219 if (ASIC_IS_AVIVO(rdev))
1220 mpll->pll_out_min = 64800;
1221 else
1222 mpll->pll_out_min = 20000;
1223 }
1224
1225 mpll->pll_in_min =
1226 le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input);
1227 mpll->pll_in_max =
1228 le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input);
1229
1230 rdev->clock.default_sclk =
1231 le32_to_cpu(firmware_info->info.ulDefaultEngineClock);
1232 rdev->clock.default_mclk =
1233 le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);
1234
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001235 if (ASIC_IS_DCE4(rdev)) {
1236 rdev->clock.default_dispclk =
1237 le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);
Alex Deucherf82b3dd2011-01-06 21:19:15 -05001238 if (rdev->clock.default_dispclk == 0) {
1239 if (ASIC_IS_DCE5(rdev))
1240 rdev->clock.default_dispclk = 54000; /* 540 Mhz */
1241 else
1242 rdev->clock.default_dispclk = 60000; /* 600 Mhz */
1243 }
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001244 rdev->clock.dp_extclk =
1245 le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
Alex Deucher4489cd622013-03-22 15:59:10 -04001246 rdev->clock.current_dispclk = rdev->clock.default_dispclk;
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001247 }
1248 *dcpll = *p1pll;
1249
Alex Deucherb20f9be2011-06-08 13:01:11 -04001250 rdev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock);
1251 if (rdev->clock.max_pixel_clock == 0)
1252 rdev->clock.max_pixel_clock = 40000;
1253
Alex Deucheraf7912e2012-07-26 09:50:57 -04001254 /* not technically a clock, but... */
1255 rdev->mode_info.firmware_flags =
1256 le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);
1257
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001258 return true;
1259 }
Alex Deucherbcc1c2a2010-01-12 17:54:34 -05001260
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001261 return false;
1262}
1263
Alex Deucher06b64762010-01-05 11:27:29 -05001264union igp_info {
1265 struct _ATOM_INTEGRATED_SYSTEM_INFO info;
1266 struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
Alex Deucher3838f462012-07-25 12:32:59 -04001267 struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
1268 struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
Alex Deucherc2037ad2012-07-25 12:45:16 -04001269 struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
Alex Deucher06b64762010-01-05 11:27:29 -05001270};
1271
1272bool radeon_atombios_sideport_present(struct radeon_device *rdev)
1273{
1274 struct radeon_mode_info *mode_info = &rdev->mode_info;
1275 int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1276 union igp_info *igp_info;
1277 u8 frev, crev;
1278 u16 data_offset;
1279
Alex Deucher4c70b2e2010-08-02 19:39:15 -04001280 /* sideport is AMD only */
1281 if (rdev->family == CHIP_RS600)
1282 return false;
1283
Alex Deuchera084e6e2010-03-18 01:04:01 -04001284 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1285 &frev, &crev, &data_offset)) {
1286 igp_info = (union igp_info *)(mode_info->atom_context->bios +
Alex Deucher06b64762010-01-05 11:27:29 -05001287 data_offset);
Alex Deucher06b64762010-01-05 11:27:29 -05001288 switch (crev) {
1289 case 1:
Cédric Cano45894332011-02-11 19:45:37 -05001290 if (le32_to_cpu(igp_info->info.ulBootUpMemoryClock))
Alex Deucher4c70b2e2010-08-02 19:39:15 -04001291 return true;
Alex Deucher06b64762010-01-05 11:27:29 -05001292 break;
1293 case 2:
Cédric Cano45894332011-02-11 19:45:37 -05001294 if (le32_to_cpu(igp_info->info_2.ulBootUpSidePortClock))
Alex Deucher06b64762010-01-05 11:27:29 -05001295 return true;
1296 break;
1297 default:
1298 DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
1299 break;
1300 }
1301 }
1302 return false;
1303}
1304
Dave Airlie445282d2009-09-09 17:40:54 +10001305bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,
1306 struct radeon_encoder_int_tmds *tmds)
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001307{
1308 struct drm_device *dev = encoder->base.dev;
1309 struct radeon_device *rdev = dev->dev_private;
1310 struct radeon_mode_info *mode_info = &rdev->mode_info;
1311 int index = GetIndexIntoMasterTable(DATA, TMDS_Info);
1312 uint16_t data_offset;
1313 struct _ATOM_TMDS_INFO *tmds_info;
1314 uint8_t frev, crev;
1315 uint16_t maxfreq;
1316 int i;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001317
Alex Deuchera084e6e2010-03-18 01:04:01 -04001318 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1319 &frev, &crev, &data_offset)) {
1320 tmds_info =
1321 (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios +
1322 data_offset);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001323
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001324 maxfreq = le16_to_cpu(tmds_info->usMaxFrequency);
1325 for (i = 0; i < 4; i++) {
1326 tmds->tmds_pll[i].freq =
1327 le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency);
1328 tmds->tmds_pll[i].value =
1329 tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f;
1330 tmds->tmds_pll[i].value |=
1331 (tmds_info->asMiscInfo[i].
1332 ucPLL_VCO_Gain & 0x3f) << 6;
1333 tmds->tmds_pll[i].value |=
1334 (tmds_info->asMiscInfo[i].
1335 ucPLL_DutyCycle & 0xf) << 12;
1336 tmds->tmds_pll[i].value |=
1337 (tmds_info->asMiscInfo[i].
1338 ucPLL_VoltageSwing & 0xf) << 16;
1339
Dave Airlied9fdaaf2010-08-02 10:42:55 +10001340 DRM_DEBUG_KMS("TMDS PLL From ATOMBIOS %u %x\n",
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001341 tmds->tmds_pll[i].freq,
1342 tmds->tmds_pll[i].value);
1343
1344 if (maxfreq == tmds->tmds_pll[i].freq) {
1345 tmds->tmds_pll[i].freq = 0xffffffff;
1346 break;
1347 }
1348 }
Dave Airlie445282d2009-09-09 17:40:54 +10001349 return true;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001350 }
Dave Airlie445282d2009-09-09 17:40:54 +10001351 return false;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001352}
1353
Alex Deucherba032a52010-10-04 17:13:01 -04001354bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
1355 struct radeon_atom_ss *ss,
1356 int id)
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001357{
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001358 struct radeon_mode_info *mode_info = &rdev->mode_info;
1359 int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
Alex Deucherba032a52010-10-04 17:13:01 -04001360 uint16_t data_offset, size;
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001361 struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
1362 uint8_t frev, crev;
Alex Deucherba032a52010-10-04 17:13:01 -04001363 int i, num_indices;
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001364
Alex Deucherba032a52010-10-04 17:13:01 -04001365 memset(ss, 0, sizeof(struct radeon_atom_ss));
1366 if (atom_parse_data_header(mode_info->atom_context, index, &size,
Alex Deuchera084e6e2010-03-18 01:04:01 -04001367 &frev, &crev, &data_offset)) {
1368 ss_info =
1369 (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset);
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001370
Alex Deucherba032a52010-10-04 17:13:01 -04001371 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1372 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001373
Alex Deucherba032a52010-10-04 17:13:01 -04001374 for (i = 0; i < num_indices; i++) {
Alex Deucher279b2152009-12-08 14:07:03 -05001375 if (ss_info->asSS_Info[i].ucSS_Id == id) {
1376 ss->percentage =
1377 le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage);
1378 ss->type = ss_info->asSS_Info[i].ucSpreadSpectrumType;
1379 ss->step = ss_info->asSS_Info[i].ucSS_Step;
1380 ss->delay = ss_info->asSS_Info[i].ucSS_Delay;
1381 ss->range = ss_info->asSS_Info[i].ucSS_Range;
1382 ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div;
Alex Deucherba032a52010-10-04 17:13:01 -04001383 return true;
Alex Deucher279b2152009-12-08 14:07:03 -05001384 }
1385 }
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001386 }
Alex Deucherba032a52010-10-04 17:13:01 -04001387 return false;
1388}
1389
Alex Deucher4339c442010-11-22 17:56:25 -05001390static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
1391 struct radeon_atom_ss *ss,
1392 int id)
1393{
1394 struct radeon_mode_info *mode_info = &rdev->mode_info;
1395 int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
1396 u16 data_offset, size;
Alex Deucher3838f462012-07-25 12:32:59 -04001397 union igp_info *igp_info;
Alex Deucher4339c442010-11-22 17:56:25 -05001398 u8 frev, crev;
1399 u16 percentage = 0, rate = 0;
1400
1401 /* get any igp specific overrides */
1402 if (atom_parse_data_header(mode_info->atom_context, index, &size,
1403 &frev, &crev, &data_offset)) {
Alex Deucher3838f462012-07-25 12:32:59 -04001404 igp_info = (union igp_info *)
Alex Deucher4339c442010-11-22 17:56:25 -05001405 (mode_info->atom_context->bios + data_offset);
Alex Deucher3838f462012-07-25 12:32:59 -04001406 switch (crev) {
1407 case 6:
1408 switch (id) {
1409 case ASIC_INTERNAL_SS_ON_TMDS:
1410 percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage);
1411 rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz);
1412 break;
1413 case ASIC_INTERNAL_SS_ON_HDMI:
1414 percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage);
1415 rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz);
1416 break;
1417 case ASIC_INTERNAL_SS_ON_LVDS:
1418 percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage);
1419 rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz);
1420 break;
1421 }
Alex Deucher4339c442010-11-22 17:56:25 -05001422 break;
Alex Deucher3838f462012-07-25 12:32:59 -04001423 case 7:
1424 switch (id) {
1425 case ASIC_INTERNAL_SS_ON_TMDS:
1426 percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage);
1427 rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz);
1428 break;
1429 case ASIC_INTERNAL_SS_ON_HDMI:
1430 percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage);
1431 rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz);
1432 break;
1433 case ASIC_INTERNAL_SS_ON_LVDS:
1434 percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage);
1435 rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz);
1436 break;
1437 }
Alex Deucher4339c442010-11-22 17:56:25 -05001438 break;
Alex Deucherc2037ad2012-07-25 12:45:16 -04001439 case 8:
1440 switch (id) {
1441 case ASIC_INTERNAL_SS_ON_TMDS:
1442 percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage);
1443 rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz);
1444 break;
1445 case ASIC_INTERNAL_SS_ON_HDMI:
1446 percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage);
1447 rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz);
1448 break;
1449 case ASIC_INTERNAL_SS_ON_LVDS:
1450 percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage);
1451 rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz);
1452 break;
1453 }
1454 break;
Alex Deucher3838f462012-07-25 12:32:59 -04001455 default:
1456 DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
Alex Deucher4339c442010-11-22 17:56:25 -05001457 break;
1458 }
1459 if (percentage)
1460 ss->percentage = percentage;
1461 if (rate)
1462 ss->rate = rate;
1463 }
1464}
1465
Alex Deucherba032a52010-10-04 17:13:01 -04001466union asic_ss_info {
1467 struct _ATOM_ASIC_INTERNAL_SS_INFO info;
1468 struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
1469 struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
1470};
1471
1472bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
1473 struct radeon_atom_ss *ss,
1474 int id, u32 clock)
1475{
1476 struct radeon_mode_info *mode_info = &rdev->mode_info;
1477 int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
1478 uint16_t data_offset, size;
1479 union asic_ss_info *ss_info;
1480 uint8_t frev, crev;
1481 int i, num_indices;
1482
Alex Deucher9cb84ab2013-08-19 19:06:19 -04001483 if (id == ASIC_INTERNAL_MEMORY_SS) {
1484 if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT))
1485 return false;
1486 }
1487 if (id == ASIC_INTERNAL_ENGINE_SS) {
1488 if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT))
1489 return false;
1490 }
1491
Alex Deucherba032a52010-10-04 17:13:01 -04001492 memset(ss, 0, sizeof(struct radeon_atom_ss));
1493 if (atom_parse_data_header(mode_info->atom_context, index, &size,
1494 &frev, &crev, &data_offset)) {
1495
1496 ss_info =
1497 (union asic_ss_info *)(mode_info->atom_context->bios + data_offset);
1498
1499 switch (frev) {
1500 case 1:
1501 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1502 sizeof(ATOM_ASIC_SS_ASSIGNMENT);
1503
1504 for (i = 0; i < num_indices; i++) {
1505 if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) &&
Cédric Cano45894332011-02-11 19:45:37 -05001506 (clock <= le32_to_cpu(ss_info->info.asSpreadSpectrum[i].ulTargetClockRange))) {
Alex Deucherba032a52010-10-04 17:13:01 -04001507 ss->percentage =
1508 le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
1509 ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
1510 ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz);
1511 return true;
1512 }
1513 }
1514 break;
1515 case 2:
1516 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1517 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1518 for (i = 0; i < num_indices; i++) {
1519 if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) &&
Cédric Cano45894332011-02-11 19:45:37 -05001520 (clock <= le32_to_cpu(ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange))) {
Alex Deucherba032a52010-10-04 17:13:01 -04001521 ss->percentage =
1522 le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
1523 ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
1524 ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
Alex Deucherae5b0ab2013-06-24 10:50:34 -04001525 if ((crev == 2) &&
1526 ((id == ASIC_INTERNAL_ENGINE_SS) ||
1527 (id == ASIC_INTERNAL_MEMORY_SS)))
1528 ss->rate /= 100;
Alex Deucherba032a52010-10-04 17:13:01 -04001529 return true;
1530 }
1531 }
1532 break;
1533 case 3:
1534 num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
1535 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
1536 for (i = 0; i < num_indices; i++) {
1537 if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) &&
Cédric Cano45894332011-02-11 19:45:37 -05001538 (clock <= le32_to_cpu(ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange))) {
Alex Deucherba032a52010-10-04 17:13:01 -04001539 ss->percentage =
1540 le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
1541 ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
1542 ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
Alex Deucherae5b0ab2013-06-24 10:50:34 -04001543 if ((id == ASIC_INTERNAL_ENGINE_SS) ||
1544 (id == ASIC_INTERNAL_MEMORY_SS))
1545 ss->rate /= 100;
Alex Deucher4339c442010-11-22 17:56:25 -05001546 if (rdev->flags & RADEON_IS_IGP)
1547 radeon_atombios_get_igp_ss_overrides(rdev, ss, id);
Alex Deucherba032a52010-10-04 17:13:01 -04001548 return true;
1549 }
1550 }
1551 break;
1552 default:
1553 DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);
1554 break;
1555 }
1556
1557 }
1558 return false;
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001559}
1560
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001561union lvds_info {
1562 struct _ATOM_LVDS_INFO info;
1563 struct _ATOM_LVDS_INFO_V12 info_12;
1564};
1565
1566struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
1567 radeon_encoder
1568 *encoder)
1569{
1570 struct drm_device *dev = encoder->base.dev;
1571 struct radeon_device *rdev = dev->dev_private;
1572 struct radeon_mode_info *mode_info = &rdev->mode_info;
1573 int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
Alex Deucher7dde8a192009-11-30 01:40:24 -05001574 uint16_t data_offset, misc;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001575 union lvds_info *lvds_info;
1576 uint8_t frev, crev;
1577 struct radeon_encoder_atom_dig *lvds = NULL;
Alex Deucher5137ee92010-08-12 18:58:47 -04001578 int encoder_enum = (encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001579
Alex Deuchera084e6e2010-03-18 01:04:01 -04001580 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1581 &frev, &crev, &data_offset)) {
1582 lvds_info =
1583 (union lvds_info *)(mode_info->atom_context->bios + data_offset);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001584 lvds =
1585 kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL);
1586
1587 if (!lvds)
1588 return NULL;
1589
Alex Deucherde2103e2009-10-09 15:14:30 -04001590 lvds->native_mode.clock =
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001591 le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10;
Alex Deucherde2103e2009-10-09 15:14:30 -04001592 lvds->native_mode.hdisplay =
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001593 le16_to_cpu(lvds_info->info.sLCDTiming.usHActive);
Alex Deucherde2103e2009-10-09 15:14:30 -04001594 lvds->native_mode.vdisplay =
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001595 le16_to_cpu(lvds_info->info.sLCDTiming.usVActive);
Alex Deucherde2103e2009-10-09 15:14:30 -04001596 lvds->native_mode.htotal = lvds->native_mode.hdisplay +
1597 le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
1598 lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
1599 le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
1600 lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
1601 le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);
1602 lvds->native_mode.vtotal = lvds->native_mode.vdisplay +
1603 le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
1604 lvds->native_mode.vsync_start = lvds->native_mode.vdisplay +
Alex Deucher1ff26a32010-05-18 00:23:15 -04001605 le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset);
Alex Deucherde2103e2009-10-09 15:14:30 -04001606 lvds->native_mode.vsync_end = lvds->native_mode.vsync_start +
1607 le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001608 lvds->panel_pwr_delay =
1609 le16_to_cpu(lvds_info->info.usOffDelayInMs);
Alex Deucherba032a52010-10-04 17:13:01 -04001610 lvds->lcd_misc = lvds_info->info.ucLVDS_Misc;
Alex Deucher7dde8a192009-11-30 01:40:24 -05001611
1612 misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess);
1613 if (misc & ATOM_VSYNC_POLARITY)
1614 lvds->native_mode.flags |= DRM_MODE_FLAG_NVSYNC;
1615 if (misc & ATOM_HSYNC_POLARITY)
1616 lvds->native_mode.flags |= DRM_MODE_FLAG_NHSYNC;
1617 if (misc & ATOM_COMPOSITESYNC)
1618 lvds->native_mode.flags |= DRM_MODE_FLAG_CSYNC;
1619 if (misc & ATOM_INTERLACE)
1620 lvds->native_mode.flags |= DRM_MODE_FLAG_INTERLACE;
1621 if (misc & ATOM_DOUBLE_CLOCK_MODE)
1622 lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN;
1623
Cédric Cano45894332011-02-11 19:45:37 -05001624 lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize);
1625 lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize);
Alex Deucher7a868e12010-12-08 22:13:05 -05001626
Alex Deucherde2103e2009-10-09 15:14:30 -04001627 /* set crtc values */
1628 drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001629
Alex Deucherba032a52010-10-04 17:13:01 -04001630 lvds->lcd_ss_id = lvds_info->info.ucSS_Id;
Alex Deucherebbe1cb2009-10-16 11:15:25 -04001631
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001632 encoder->native_mode = lvds->native_mode;
Alex Deucher5137ee92010-08-12 18:58:47 -04001633
1634 if (encoder_enum == 2)
1635 lvds->linkb = true;
1636 else
1637 lvds->linkb = false;
1638
Alex Deucherc324acd2010-12-08 22:13:06 -05001639 /* parse the lcd record table */
Cédric Cano45894332011-02-11 19:45:37 -05001640 if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) {
Alex Deucherc324acd2010-12-08 22:13:06 -05001641 ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
1642 ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
1643 bool bad_record = false;
Alex Deucher05fa7ea2011-05-11 14:02:07 -04001644 u8 *record;
1645
1646 if ((frev == 1) && (crev < 2))
1647 /* absolute */
1648 record = (u8 *)(mode_info->atom_context->bios +
1649 le16_to_cpu(lvds_info->info.usModePatchTableOffset));
1650 else
1651 /* relative */
1652 record = (u8 *)(mode_info->atom_context->bios +
1653 data_offset +
1654 le16_to_cpu(lvds_info->info.usModePatchTableOffset));
Alex Deucherc324acd2010-12-08 22:13:06 -05001655 while (*record != ATOM_RECORD_END_TYPE) {
1656 switch (*record) {
1657 case LCD_MODE_PATCH_RECORD_MODE_TYPE:
1658 record += sizeof(ATOM_PATCH_RECORD_MODE);
1659 break;
1660 case LCD_RTS_RECORD_TYPE:
1661 record += sizeof(ATOM_LCD_RTS_RECORD);
1662 break;
1663 case LCD_CAP_RECORD_TYPE:
1664 record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
1665 break;
1666 case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
1667 fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
1668 if (fake_edid_record->ucFakeEDIDLength) {
1669 struct edid *edid;
1670 int edid_size =
1671 max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength);
1672 edid = kmalloc(edid_size, GFP_KERNEL);
1673 if (edid) {
1674 memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
1675 fake_edid_record->ucFakeEDIDLength);
1676
Dave Airlieeaa4f5e2011-05-01 20:16:30 +10001677 if (drm_edid_is_valid(edid)) {
Alex Deucherc324acd2010-12-08 22:13:06 -05001678 rdev->mode_info.bios_hardcoded_edid = edid;
Dave Airlieeaa4f5e2011-05-01 20:16:30 +10001679 rdev->mode_info.bios_hardcoded_edid_size = edid_size;
1680 } else
Alex Deucherc324acd2010-12-08 22:13:06 -05001681 kfree(edid);
1682 }
1683 }
1684 record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD);
1685 break;
1686 case LCD_PANEL_RESOLUTION_RECORD_TYPE:
1687 panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
1688 lvds->native_mode.width_mm = panel_res_record->usHSize;
1689 lvds->native_mode.height_mm = panel_res_record->usVSize;
1690 record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
1691 break;
1692 default:
1693 DRM_ERROR("Bad LCD record %d\n", *record);
1694 bad_record = true;
1695 break;
1696 }
1697 if (bad_record)
1698 break;
1699 }
1700 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001701 }
1702 return lvds;
1703}
1704
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001705struct radeon_encoder_primary_dac *
1706radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder)
1707{
1708 struct drm_device *dev = encoder->base.dev;
1709 struct radeon_device *rdev = dev->dev_private;
1710 struct radeon_mode_info *mode_info = &rdev->mode_info;
1711 int index = GetIndexIntoMasterTable(DATA, CompassionateData);
1712 uint16_t data_offset;
1713 struct _COMPASSIONATE_DATA *dac_info;
1714 uint8_t frev, crev;
1715 uint8_t bg, dac;
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001716 struct radeon_encoder_primary_dac *p_dac = NULL;
1717
Alex Deuchera084e6e2010-03-18 01:04:01 -04001718 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1719 &frev, &crev, &data_offset)) {
1720 dac_info = (struct _COMPASSIONATE_DATA *)
1721 (mode_info->atom_context->bios + data_offset);
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001722
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001723 p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), GFP_KERNEL);
1724
1725 if (!p_dac)
1726 return NULL;
1727
1728 bg = dac_info->ucDAC1_BG_Adjustment;
1729 dac = dac_info->ucDAC1_DAC_Adjustment;
1730 p_dac->ps2_pdac_adj = (bg << 8) | (dac);
1731
1732 }
1733 return p_dac;
1734}
1735
Dave Airlie4ce001a2009-08-13 16:32:14 +10001736bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001737 struct drm_display_mode *mode)
Dave Airlie4ce001a2009-08-13 16:32:14 +10001738{
1739 struct radeon_mode_info *mode_info = &rdev->mode_info;
1740 ATOM_ANALOG_TV_INFO *tv_info;
1741 ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
1742 ATOM_DTD_FORMAT *dtd_timings;
1743 int data_index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
1744 u8 frev, crev;
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001745 u16 data_offset, misc;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001746
Alex Deuchera084e6e2010-03-18 01:04:01 -04001747 if (!atom_parse_data_header(mode_info->atom_context, data_index, NULL,
1748 &frev, &crev, &data_offset))
1749 return false;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001750
1751 switch (crev) {
1752 case 1:
1753 tv_info = (ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset);
Dan Carpenter0031c412010-04-27 14:11:04 -07001754 if (index >= MAX_SUPPORTED_TV_TIMING)
Dave Airlie4ce001a2009-08-13 16:32:14 +10001755 return false;
1756
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001757 mode->crtc_htotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
1758 mode->crtc_hdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
1759 mode->crtc_hsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
1760 mode->crtc_hsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) +
1761 le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
Dave Airlie4ce001a2009-08-13 16:32:14 +10001762
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001763 mode->crtc_vtotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
1764 mode->crtc_vdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
1765 mode->crtc_vsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
1766 mode->crtc_vsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) +
1767 le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
Dave Airlie4ce001a2009-08-13 16:32:14 +10001768
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001769 mode->flags = 0;
1770 misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess);
1771 if (misc & ATOM_VSYNC_POLARITY)
1772 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1773 if (misc & ATOM_HSYNC_POLARITY)
1774 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1775 if (misc & ATOM_COMPOSITESYNC)
1776 mode->flags |= DRM_MODE_FLAG_CSYNC;
1777 if (misc & ATOM_INTERLACE)
1778 mode->flags |= DRM_MODE_FLAG_INTERLACE;
1779 if (misc & ATOM_DOUBLE_CLOCK_MODE)
1780 mode->flags |= DRM_MODE_FLAG_DBLSCAN;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001781
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001782 mode->clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001783
1784 if (index == 1) {
1785 /* PAL timings appear to have wrong values for totals */
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001786 mode->crtc_htotal -= 1;
1787 mode->crtc_vtotal -= 1;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001788 }
1789 break;
1790 case 2:
1791 tv_info_v1_2 = (ATOM_ANALOG_TV_INFO_V1_2 *)(mode_info->atom_context->bios + data_offset);
Dan Carpenter0031c412010-04-27 14:11:04 -07001792 if (index >= MAX_SUPPORTED_TV_TIMING_V1_2)
Dave Airlie4ce001a2009-08-13 16:32:14 +10001793 return false;
1794
1795 dtd_timings = &tv_info_v1_2->aModeTimings[index];
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001796 mode->crtc_htotal = le16_to_cpu(dtd_timings->usHActive) +
1797 le16_to_cpu(dtd_timings->usHBlanking_Time);
1798 mode->crtc_hdisplay = le16_to_cpu(dtd_timings->usHActive);
1799 mode->crtc_hsync_start = le16_to_cpu(dtd_timings->usHActive) +
1800 le16_to_cpu(dtd_timings->usHSyncOffset);
1801 mode->crtc_hsync_end = mode->crtc_hsync_start +
1802 le16_to_cpu(dtd_timings->usHSyncWidth);
Dave Airlie4ce001a2009-08-13 16:32:14 +10001803
Alex Deucher5a9bcac2009-10-08 15:09:31 -04001804 mode->crtc_vtotal = le16_to_cpu(dtd_timings->usVActive) +
1805 le16_to_cpu(dtd_timings->usVBlanking_Time);
1806 mode->crtc_vdisplay = le16_to_cpu(dtd_timings->usVActive);
1807 mode->crtc_vsync_start = le16_to_cpu(dtd_timings->usVActive) +
1808 le16_to_cpu(dtd_timings->usVSyncOffset);
1809 mode->crtc_vsync_end = mode->crtc_vsync_start +
1810 le16_to_cpu(dtd_timings->usVSyncWidth);
1811
1812 mode->flags = 0;
1813 misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
1814 if (misc & ATOM_VSYNC_POLARITY)
1815 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1816 if (misc & ATOM_HSYNC_POLARITY)
1817 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1818 if (misc & ATOM_COMPOSITESYNC)
1819 mode->flags |= DRM_MODE_FLAG_CSYNC;
1820 if (misc & ATOM_INTERLACE)
1821 mode->flags |= DRM_MODE_FLAG_INTERLACE;
1822 if (misc & ATOM_DOUBLE_CLOCK_MODE)
1823 mode->flags |= DRM_MODE_FLAG_DBLSCAN;
1824
1825 mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
Dave Airlie4ce001a2009-08-13 16:32:14 +10001826 break;
1827 }
1828 return true;
1829}
1830
Alex Deucherd79766f2009-12-17 19:00:29 -05001831enum radeon_tv_std
1832radeon_atombios_get_tv_info(struct radeon_device *rdev)
1833{
1834 struct radeon_mode_info *mode_info = &rdev->mode_info;
1835 int index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
1836 uint16_t data_offset;
1837 uint8_t frev, crev;
1838 struct _ATOM_ANALOG_TV_INFO *tv_info;
1839 enum radeon_tv_std tv_std = TV_STD_NTSC;
1840
Alex Deuchera084e6e2010-03-18 01:04:01 -04001841 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1842 &frev, &crev, &data_offset)) {
Alex Deucherd79766f2009-12-17 19:00:29 -05001843
Alex Deuchera084e6e2010-03-18 01:04:01 -04001844 tv_info = (struct _ATOM_ANALOG_TV_INFO *)
1845 (mode_info->atom_context->bios + data_offset);
Alex Deucherd79766f2009-12-17 19:00:29 -05001846
Alex Deuchera084e6e2010-03-18 01:04:01 -04001847 switch (tv_info->ucTV_BootUpDefaultStandard) {
1848 case ATOM_TV_NTSC:
1849 tv_std = TV_STD_NTSC;
Alex Deucher40f76d82010-10-07 22:38:42 -04001850 DRM_DEBUG_KMS("Default TV standard: NTSC\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001851 break;
1852 case ATOM_TV_NTSCJ:
1853 tv_std = TV_STD_NTSC_J;
Alex Deucher40f76d82010-10-07 22:38:42 -04001854 DRM_DEBUG_KMS("Default TV standard: NTSC-J\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001855 break;
1856 case ATOM_TV_PAL:
1857 tv_std = TV_STD_PAL;
Alex Deucher40f76d82010-10-07 22:38:42 -04001858 DRM_DEBUG_KMS("Default TV standard: PAL\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001859 break;
1860 case ATOM_TV_PALM:
1861 tv_std = TV_STD_PAL_M;
Alex Deucher40f76d82010-10-07 22:38:42 -04001862 DRM_DEBUG_KMS("Default TV standard: PAL-M\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001863 break;
1864 case ATOM_TV_PALN:
1865 tv_std = TV_STD_PAL_N;
Alex Deucher40f76d82010-10-07 22:38:42 -04001866 DRM_DEBUG_KMS("Default TV standard: PAL-N\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001867 break;
1868 case ATOM_TV_PALCN:
1869 tv_std = TV_STD_PAL_CN;
Alex Deucher40f76d82010-10-07 22:38:42 -04001870 DRM_DEBUG_KMS("Default TV standard: PAL-CN\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001871 break;
1872 case ATOM_TV_PAL60:
1873 tv_std = TV_STD_PAL_60;
Alex Deucher40f76d82010-10-07 22:38:42 -04001874 DRM_DEBUG_KMS("Default TV standard: PAL-60\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001875 break;
1876 case ATOM_TV_SECAM:
1877 tv_std = TV_STD_SECAM;
Alex Deucher40f76d82010-10-07 22:38:42 -04001878 DRM_DEBUG_KMS("Default TV standard: SECAM\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001879 break;
1880 default:
1881 tv_std = TV_STD_NTSC;
Alex Deucher40f76d82010-10-07 22:38:42 -04001882 DRM_DEBUG_KMS("Unknown TV standard; defaulting to NTSC\n");
Alex Deuchera084e6e2010-03-18 01:04:01 -04001883 break;
1884 }
Alex Deucherd79766f2009-12-17 19:00:29 -05001885 }
1886 return tv_std;
1887}
1888
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001889struct radeon_encoder_tv_dac *
1890radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
1891{
1892 struct drm_device *dev = encoder->base.dev;
1893 struct radeon_device *rdev = dev->dev_private;
1894 struct radeon_mode_info *mode_info = &rdev->mode_info;
1895 int index = GetIndexIntoMasterTable(DATA, CompassionateData);
1896 uint16_t data_offset;
1897 struct _COMPASSIONATE_DATA *dac_info;
1898 uint8_t frev, crev;
1899 uint8_t bg, dac;
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001900 struct radeon_encoder_tv_dac *tv_dac = NULL;
1901
Alex Deuchera084e6e2010-03-18 01:04:01 -04001902 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
1903 &frev, &crev, &data_offset)) {
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001904
Alex Deuchera084e6e2010-03-18 01:04:01 -04001905 dac_info = (struct _COMPASSIONATE_DATA *)
1906 (mode_info->atom_context->bios + data_offset);
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001907
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001908 tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL);
1909
1910 if (!tv_dac)
1911 return NULL;
1912
1913 bg = dac_info->ucDAC2_CRT2_BG_Adjustment;
1914 dac = dac_info->ucDAC2_CRT2_DAC_Adjustment;
1915 tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
1916
1917 bg = dac_info->ucDAC2_PAL_BG_Adjustment;
1918 dac = dac_info->ucDAC2_PAL_DAC_Adjustment;
1919 tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20);
1920
1921 bg = dac_info->ucDAC2_NTSC_BG_Adjustment;
1922 dac = dac_info->ucDAC2_NTSC_DAC_Adjustment;
1923 tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
1924
Alex Deucherd79766f2009-12-17 19:00:29 -05001925 tv_dac->tv_std = radeon_atombios_get_tv_info(rdev);
Alex Deucher6fe7ac32009-06-12 17:26:08 +00001926 }
1927 return tv_dac;
1928}
1929
Alex Deucher29fb52c2010-03-11 10:01:17 -05001930static const char *thermal_controller_names[] = {
1931 "NONE",
Alex Deucher678e7dfa2010-04-22 14:17:56 -04001932 "lm63",
1933 "adm1032",
1934 "adm1030",
1935 "max6649",
1936 "lm64",
1937 "f75375",
1938 "asc7xxx",
Alex Deucher29fb52c2010-03-11 10:01:17 -05001939};
1940
1941static const char *pp_lib_thermal_controller_names[] = {
1942 "NONE",
Alex Deucher678e7dfa2010-04-22 14:17:56 -04001943 "lm63",
1944 "adm1032",
1945 "adm1030",
1946 "max6649",
1947 "lm64",
1948 "f75375",
Alex Deucher29fb52c2010-03-11 10:01:17 -05001949 "RV6xx",
1950 "RV770",
Alex Deucher678e7dfa2010-04-22 14:17:56 -04001951 "adt7473",
Alex Deucher560154e2010-11-22 17:56:34 -05001952 "NONE",
Alex Deucher49f65982010-03-24 16:39:45 -04001953 "External GPIO",
1954 "Evergreen",
Alex Deucherb0e66412010-11-22 17:56:35 -05001955 "emc2103",
1956 "Sumo",
Alex Deucher4fddba12011-01-06 21:19:22 -05001957 "Northern Islands",
Alex Deucher14607d02012-03-20 17:18:09 -04001958 "Southern Islands",
1959 "lm96163",
Alex Deucher51150202012-12-18 22:07:14 -05001960 "Sea Islands",
Alex Deucher29fb52c2010-03-11 10:01:17 -05001961};
1962
Alex Deucher56278a82009-12-28 13:58:44 -05001963union power_info {
1964 struct _ATOM_POWERPLAY_INFO info;
1965 struct _ATOM_POWERPLAY_INFO_V2 info_2;
1966 struct _ATOM_POWERPLAY_INFO_V3 info_3;
Alex Deucher560154e2010-11-22 17:56:34 -05001967 struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
Alex Deucherb0e66412010-11-22 17:56:35 -05001968 struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
1969 struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
Alex Deucher56278a82009-12-28 13:58:44 -05001970};
1971
Alex Deucher560154e2010-11-22 17:56:34 -05001972union pplib_clock_info {
1973 struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
1974 struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
1975 struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
Alex Deucherb0e66412010-11-22 17:56:35 -05001976 struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
Alex Deucher14607d02012-03-20 17:18:09 -04001977 struct _ATOM_PPLIB_SI_CLOCK_INFO si;
Alex Deucherbc19f592013-06-07 11:41:05 -04001978 struct _ATOM_PPLIB_CI_CLOCK_INFO ci;
Alex Deucher560154e2010-11-22 17:56:34 -05001979};
1980
1981union pplib_power_state {
1982 struct _ATOM_PPLIB_STATE v1;
1983 struct _ATOM_PPLIB_STATE_V2 v2;
1984};
1985
1986static void radeon_atombios_parse_misc_flags_1_3(struct radeon_device *rdev,
1987 int state_index,
1988 u32 misc, u32 misc2)
1989{
1990 rdev->pm.power_state[state_index].misc = misc;
1991 rdev->pm.power_state[state_index].misc2 = misc2;
1992 /* order matters! */
1993 if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
1994 rdev->pm.power_state[state_index].type =
1995 POWER_STATE_TYPE_POWERSAVE;
1996 if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
1997 rdev->pm.power_state[state_index].type =
1998 POWER_STATE_TYPE_BATTERY;
1999 if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
2000 rdev->pm.power_state[state_index].type =
2001 POWER_STATE_TYPE_BATTERY;
2002 if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
2003 rdev->pm.power_state[state_index].type =
2004 POWER_STATE_TYPE_BALANCED;
2005 if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) {
2006 rdev->pm.power_state[state_index].type =
2007 POWER_STATE_TYPE_PERFORMANCE;
2008 rdev->pm.power_state[state_index].flags &=
2009 ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2010 }
2011 if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
2012 rdev->pm.power_state[state_index].type =
2013 POWER_STATE_TYPE_BALANCED;
2014 if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
2015 rdev->pm.power_state[state_index].type =
2016 POWER_STATE_TYPE_DEFAULT;
2017 rdev->pm.default_power_state_index = state_index;
2018 rdev->pm.power_state[state_index].default_clock_mode =
2019 &rdev->pm.power_state[state_index].clock_info[0];
2020 } else if (state_index == 0) {
2021 rdev->pm.power_state[state_index].clock_info[0].flags |=
2022 RADEON_PM_MODE_NO_DISPLAY;
2023 }
2024}
2025
2026static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
2027{
2028 struct radeon_mode_info *mode_info = &rdev->mode_info;
2029 u32 misc, misc2 = 0;
2030 int num_modes = 0, i;
2031 int state_index = 0;
2032 struct radeon_i2c_bus_rec i2c_bus;
2033 union power_info *power_info;
2034 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2035 u16 data_offset;
2036 u8 frev, crev;
2037
2038 if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
2039 &frev, &crev, &data_offset))
2040 return state_index;
2041 power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
2042
2043 /* add the i2c bus for thermal/fan chip */
Alex Deucher4755fab2012-08-30 13:30:49 -04002044 if ((power_info->info.ucOverdriveThermalController > 0) &&
2045 (power_info->info.ucOverdriveThermalController < ARRAY_SIZE(thermal_controller_names))) {
Alex Deucher560154e2010-11-22 17:56:34 -05002046 DRM_INFO("Possible %s thermal controller at 0x%02x\n",
2047 thermal_controller_names[power_info->info.ucOverdriveThermalController],
2048 power_info->info.ucOverdriveControllerAddress >> 1);
2049 i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
2050 rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
2051 if (rdev->pm.i2c_bus) {
2052 struct i2c_board_info info = { };
2053 const char *name = thermal_controller_names[power_info->info.
2054 ucOverdriveThermalController];
2055 info.addr = power_info->info.ucOverdriveControllerAddress >> 1;
2056 strlcpy(info.type, name, sizeof(info.type));
2057 i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
2058 }
2059 }
2060 num_modes = power_info->info.ucNumOfPowerModeEntries;
2061 if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
2062 num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
Alex Deucherf8e6bfc2013-04-25 09:29:17 -04002063 if (num_modes == 0)
2064 return state_index;
Alex Deucher0975b162011-02-02 18:42:03 -05002065 rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL);
2066 if (!rdev->pm.power_state)
2067 return state_index;
Alex Deucher560154e2010-11-22 17:56:34 -05002068 /* last mode is usually default, array is low to high */
2069 for (i = 0; i < num_modes; i++) {
Alex Deucher6991b8f2011-11-14 17:52:51 -05002070 rdev->pm.power_state[state_index].clock_info =
2071 kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL);
2072 if (!rdev->pm.power_state[state_index].clock_info)
2073 return state_index;
2074 rdev->pm.power_state[state_index].num_clock_modes = 1;
Alex Deucher560154e2010-11-22 17:56:34 -05002075 rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
2076 switch (frev) {
2077 case 1:
Alex Deucher560154e2010-11-22 17:56:34 -05002078 rdev->pm.power_state[state_index].clock_info[0].mclk =
2079 le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock);
2080 rdev->pm.power_state[state_index].clock_info[0].sclk =
2081 le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock);
2082 /* skip invalid modes */
2083 if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
2084 (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
2085 continue;
2086 rdev->pm.power_state[state_index].pcie_lanes =
2087 power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
2088 misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
2089 if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
2090 (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
2091 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2092 VOLTAGE_GPIO;
2093 rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
2094 radeon_lookup_gpio(rdev,
2095 power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
2096 if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
2097 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2098 true;
2099 else
2100 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2101 false;
2102 } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
2103 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2104 VOLTAGE_VDDC;
2105 rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
2106 power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
2107 }
2108 rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2109 radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0);
2110 state_index++;
2111 break;
2112 case 2:
Alex Deucher560154e2010-11-22 17:56:34 -05002113 rdev->pm.power_state[state_index].clock_info[0].mclk =
2114 le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
2115 rdev->pm.power_state[state_index].clock_info[0].sclk =
2116 le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock);
2117 /* skip invalid modes */
2118 if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
2119 (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
2120 continue;
2121 rdev->pm.power_state[state_index].pcie_lanes =
2122 power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
2123 misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
2124 misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
2125 if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
2126 (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
2127 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2128 VOLTAGE_GPIO;
2129 rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
2130 radeon_lookup_gpio(rdev,
2131 power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
2132 if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
2133 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2134 true;
2135 else
2136 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2137 false;
2138 } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
2139 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2140 VOLTAGE_VDDC;
2141 rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
2142 power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
2143 }
2144 rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2145 radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
2146 state_index++;
2147 break;
2148 case 3:
Alex Deucher560154e2010-11-22 17:56:34 -05002149 rdev->pm.power_state[state_index].clock_info[0].mclk =
2150 le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
2151 rdev->pm.power_state[state_index].clock_info[0].sclk =
2152 le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock);
2153 /* skip invalid modes */
2154 if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
2155 (rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
2156 continue;
2157 rdev->pm.power_state[state_index].pcie_lanes =
2158 power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
2159 misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
2160 misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2);
2161 if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
2162 (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
2163 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2164 VOLTAGE_GPIO;
2165 rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
2166 radeon_lookup_gpio(rdev,
2167 power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
2168 if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
2169 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2170 true;
2171 else
2172 rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
2173 false;
2174 } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
2175 rdev->pm.power_state[state_index].clock_info[0].voltage.type =
2176 VOLTAGE_VDDC;
2177 rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
2178 power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex;
2179 if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) {
2180 rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled =
2181 true;
2182 rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id =
2183 power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
2184 }
2185 }
2186 rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2187 radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2);
2188 state_index++;
2189 break;
2190 }
2191 }
2192 /* last mode is usually default */
2193 if (rdev->pm.default_power_state_index == -1) {
2194 rdev->pm.power_state[state_index - 1].type =
2195 POWER_STATE_TYPE_DEFAULT;
2196 rdev->pm.default_power_state_index = state_index - 1;
2197 rdev->pm.power_state[state_index - 1].default_clock_mode =
2198 &rdev->pm.power_state[state_index - 1].clock_info[0];
2199 rdev->pm.power_state[state_index].flags &=
2200 ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2201 rdev->pm.power_state[state_index].misc = 0;
2202 rdev->pm.power_state[state_index].misc2 = 0;
2203 }
2204 return state_index;
2205}
2206
2207static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *rdev,
2208 ATOM_PPLIB_THERMALCONTROLLER *controller)
2209{
2210 struct radeon_i2c_bus_rec i2c_bus;
2211
2212 /* add the i2c bus for thermal/fan chip */
2213 if (controller->ucType > 0) {
2214 if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
2215 DRM_INFO("Internal thermal controller %s fan control\n",
2216 (controller->ucFanParameters &
2217 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2218 rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
2219 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
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_RV770;
2224 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
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_EVERGREEN;
Alex Deucherb0e66412010-11-22 17:56:35 -05002229 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
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_SUMO;
Alex Deucher4fddba12011-01-06 21:19:22 -05002234 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
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_NI;
Alex Deucher14607d02012-03-20 17:18:09 -04002239 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
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_SI;
Alex Deucher51150202012-12-18 22:07:14 -05002244 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
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_CI;
Alex Deucher16fbe002013-04-22 21:41:26 -04002249 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) {
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_KV;
Alex Deucher560154e2010-11-22 17:56:34 -05002254 } else if ((controller->ucType ==
2255 ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
2256 (controller->ucType ==
Alex Deucherb0e66412010-11-22 17:56:35 -05002257 ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) ||
2258 (controller->ucType ==
2259 ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) {
Alex Deucher560154e2010-11-22 17:56:34 -05002260 DRM_INFO("Special thermal controller config\n");
Alex Deucher4755fab2012-08-30 13:30:49 -04002261 } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
Alex Deucher560154e2010-11-22 17:56:34 -05002262 DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
2263 pp_lib_thermal_controller_names[controller->ucType],
2264 controller->ucI2cAddress >> 1,
2265 (controller->ucFanParameters &
2266 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
2267 i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
2268 rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
2269 if (rdev->pm.i2c_bus) {
2270 struct i2c_board_info info = { };
2271 const char *name = pp_lib_thermal_controller_names[controller->ucType];
2272 info.addr = controller->ucI2cAddress >> 1;
2273 strlcpy(info.type, name, sizeof(info.type));
2274 i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
2275 }
Alex Deucher4755fab2012-08-30 13:30:49 -04002276 } else {
2277 DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n",
2278 controller->ucType,
2279 controller->ucI2cAddress >> 1,
2280 (controller->ucFanParameters &
2281 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
Alex Deucher560154e2010-11-22 17:56:34 -05002282 }
2283 }
2284}
2285
Alex Deucher4a6369e2013-04-12 14:04:10 -04002286void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
Alex Deucher2abba662013-03-25 12:47:23 -04002287 u16 *vddc, u16 *vddci, u16 *mvdd)
Alex Deucher560154e2010-11-22 17:56:34 -05002288{
2289 struct radeon_mode_info *mode_info = &rdev->mode_info;
2290 int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
2291 u8 frev, crev;
2292 u16 data_offset;
2293 union firmware_info *firmware_info;
Alex Deucher2feea492011-04-12 14:49:24 -04002294
2295 *vddc = 0;
2296 *vddci = 0;
Alex Deucher2abba662013-03-25 12:47:23 -04002297 *mvdd = 0;
Alex Deucher560154e2010-11-22 17:56:34 -05002298
2299 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
2300 &frev, &crev, &data_offset)) {
2301 firmware_info =
2302 (union firmware_info *)(mode_info->atom_context->bios +
2303 data_offset);
Alex Deucher2feea492011-04-12 14:49:24 -04002304 *vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
Alex Deucher2abba662013-03-25 12:47:23 -04002305 if ((frev == 2) && (crev >= 2)) {
Alex Deucher2feea492011-04-12 14:49:24 -04002306 *vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);
Alex Deucher2abba662013-03-25 12:47:23 -04002307 *mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage);
2308 }
Alex Deucher560154e2010-11-22 17:56:34 -05002309 }
Alex Deucher560154e2010-11-22 17:56:34 -05002310}
2311
2312static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev,
2313 int state_index, int mode_index,
2314 struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info)
2315{
2316 int j;
2317 u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
2318 u32 misc2 = le16_to_cpu(non_clock_info->usClassification);
Alex Deucher2abba662013-03-25 12:47:23 -04002319 u16 vddc, vddci, mvdd;
Alex Deucher2feea492011-04-12 14:49:24 -04002320
Alex Deucher2abba662013-03-25 12:47:23 -04002321 radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd);
Alex Deucher560154e2010-11-22 17:56:34 -05002322
2323 rdev->pm.power_state[state_index].misc = misc;
2324 rdev->pm.power_state[state_index].misc2 = misc2;
2325 rdev->pm.power_state[state_index].pcie_lanes =
2326 ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
2327 ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
2328 switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
2329 case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
2330 rdev->pm.power_state[state_index].type =
2331 POWER_STATE_TYPE_BATTERY;
2332 break;
2333 case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
2334 rdev->pm.power_state[state_index].type =
2335 POWER_STATE_TYPE_BALANCED;
2336 break;
2337 case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
2338 rdev->pm.power_state[state_index].type =
2339 POWER_STATE_TYPE_PERFORMANCE;
2340 break;
2341 case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
2342 if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
2343 rdev->pm.power_state[state_index].type =
2344 POWER_STATE_TYPE_PERFORMANCE;
2345 break;
2346 }
2347 rdev->pm.power_state[state_index].flags = 0;
2348 if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
2349 rdev->pm.power_state[state_index].flags |=
2350 RADEON_PM_STATE_SINGLE_DISPLAY_ONLY;
2351 if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
2352 rdev->pm.power_state[state_index].type =
2353 POWER_STATE_TYPE_DEFAULT;
2354 rdev->pm.default_power_state_index = state_index;
2355 rdev->pm.power_state[state_index].default_clock_mode =
2356 &rdev->pm.power_state[state_index].clock_info[mode_index - 1];
Alex Deucher982cb322013-04-29 10:51:26 -04002357 if ((rdev->family >= CHIP_BARTS) && !(rdev->flags & RADEON_IS_IGP)) {
Alex Deucher9ace9f72011-01-06 21:19:26 -05002358 /* NI chips post without MC ucode, so default clocks are strobe mode only */
2359 rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk;
2360 rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk;
2361 rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage;
Alex Deucher2feea492011-04-12 14:49:24 -04002362 rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci;
Alex Deucher9ace9f72011-01-06 21:19:26 -05002363 } else {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04002364 u16 max_vddci = 0;
2365
2366 if (ASIC_IS_DCE4(rdev))
2367 radeon_atom_get_max_voltage(rdev,
2368 SET_VOLTAGE_TYPE_ASIC_VDDCI,
2369 &max_vddci);
2370 /* patch the table values with the default sclk/mclk from firmware info */
Alex Deucher9ace9f72011-01-06 21:19:26 -05002371 for (j = 0; j < mode_index; j++) {
2372 rdev->pm.power_state[state_index].clock_info[j].mclk =
2373 rdev->clock.default_mclk;
2374 rdev->pm.power_state[state_index].clock_info[j].sclk =
2375 rdev->clock.default_sclk;
2376 if (vddc)
2377 rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
2378 vddc;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04002379 if (max_vddci)
2380 rdev->pm.power_state[state_index].clock_info[j].voltage.vddci =
2381 max_vddci;
Alex Deucher9ace9f72011-01-06 21:19:26 -05002382 }
Alex Deucher560154e2010-11-22 17:56:34 -05002383 }
2384 }
2385}
2386
2387static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
2388 int state_index, int mode_index,
2389 union pplib_clock_info *clock_info)
2390{
2391 u32 sclk, mclk;
Alex Deuchere83753b2012-03-20 17:18:08 -04002392 u16 vddc;
Alex Deucher560154e2010-11-22 17:56:34 -05002393
2394 if (rdev->flags & RADEON_IS_IGP) {
Alex Deucherb0e66412010-11-22 17:56:35 -05002395 if (rdev->family >= CHIP_PALM) {
2396 sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
2397 sclk |= clock_info->sumo.ucEngineClockHigh << 16;
2398 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2399 } else {
2400 sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
2401 sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
2402 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2403 }
Alex Deucherbc19f592013-06-07 11:41:05 -04002404 } else if (rdev->family >= CHIP_BONAIRE) {
2405 sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
2406 sclk |= clock_info->ci.ucEngineClockHigh << 16;
2407 mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
2408 mclk |= clock_info->ci.ucMemoryClockHigh << 16;
2409 rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2410 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2411 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2412 VOLTAGE_NONE;
Alex Deucher982cb322013-04-29 10:51:26 -04002413 } else if (rdev->family >= CHIP_TAHITI) {
Alex Deucher14607d02012-03-20 17:18:09 -04002414 sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
2415 sclk |= clock_info->si.ucEngineClockHigh << 16;
2416 mclk = le16_to_cpu(clock_info->si.usMemoryClockLow);
2417 mclk |= clock_info->si.ucMemoryClockHigh << 16;
2418 rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2419 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2420 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2421 VOLTAGE_SW;
2422 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
2423 le16_to_cpu(clock_info->si.usVDDC);
2424 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
2425 le16_to_cpu(clock_info->si.usVDDCI);
Alex Deucher982cb322013-04-29 10:51:26 -04002426 } else if (rdev->family >= CHIP_CEDAR) {
Alex Deucher560154e2010-11-22 17:56:34 -05002427 sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
2428 sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
2429 mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
2430 mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
2431 rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2432 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2433 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2434 VOLTAGE_SW;
2435 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
Cédric Cano45894332011-02-11 19:45:37 -05002436 le16_to_cpu(clock_info->evergreen.usVDDC);
Alex Deucher2feea492011-04-12 14:49:24 -04002437 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci =
2438 le16_to_cpu(clock_info->evergreen.usVDDCI);
Alex Deucher560154e2010-11-22 17:56:34 -05002439 } else {
2440 sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
2441 sclk |= clock_info->r600.ucEngineClockHigh << 16;
2442 mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
2443 mclk |= clock_info->r600.ucMemoryClockHigh << 16;
2444 rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
2445 rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
2446 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
2447 VOLTAGE_SW;
2448 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
Cédric Cano45894332011-02-11 19:45:37 -05002449 le16_to_cpu(clock_info->r600.usVDDC);
Alex Deucher560154e2010-11-22 17:56:34 -05002450 }
2451
Alex Deucheree4017f2011-06-23 12:19:32 -04002452 /* patch up vddc if necessary */
Alex Deuchere83753b2012-03-20 17:18:08 -04002453 switch (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage) {
2454 case ATOM_VIRTUAL_VOLTAGE_ID0:
2455 case ATOM_VIRTUAL_VOLTAGE_ID1:
2456 case ATOM_VIRTUAL_VOLTAGE_ID2:
2457 case ATOM_VIRTUAL_VOLTAGE_ID3:
Alex Deucherc6cf7772013-07-05 13:14:30 -04002458 case ATOM_VIRTUAL_VOLTAGE_ID4:
2459 case ATOM_VIRTUAL_VOLTAGE_ID5:
2460 case ATOM_VIRTUAL_VOLTAGE_ID6:
2461 case ATOM_VIRTUAL_VOLTAGE_ID7:
Alex Deuchere83753b2012-03-20 17:18:08 -04002462 if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC,
2463 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage,
2464 &vddc) == 0)
Alex Deucheree4017f2011-06-23 12:19:32 -04002465 rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = vddc;
Alex Deuchere83753b2012-03-20 17:18:08 -04002466 break;
2467 default:
2468 break;
Alex Deucheree4017f2011-06-23 12:19:32 -04002469 }
2470
Alex Deucher560154e2010-11-22 17:56:34 -05002471 if (rdev->flags & RADEON_IS_IGP) {
2472 /* skip invalid modes */
2473 if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
2474 return false;
2475 } else {
2476 /* skip invalid modes */
2477 if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
2478 (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
2479 return false;
2480 }
2481 return true;
2482}
2483
2484static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev)
2485{
2486 struct radeon_mode_info *mode_info = &rdev->mode_info;
2487 struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
2488 union pplib_power_state *power_state;
2489 int i, j;
2490 int state_index = 0, mode_index = 0;
2491 union pplib_clock_info *clock_info;
2492 bool valid;
2493 union power_info *power_info;
2494 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2495 u16 data_offset;
2496 u8 frev, crev;
2497
2498 if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
2499 &frev, &crev, &data_offset))
2500 return state_index;
2501 power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
2502
2503 radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
Alex Deucherf8e6bfc2013-04-25 09:29:17 -04002504 if (power_info->pplib.ucNumStates == 0)
2505 return state_index;
Alex Deucher0975b162011-02-02 18:42:03 -05002506 rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) *
2507 power_info->pplib.ucNumStates, GFP_KERNEL);
2508 if (!rdev->pm.power_state)
2509 return state_index;
Alex Deucher560154e2010-11-22 17:56:34 -05002510 /* first mode is usually default, followed by low to high */
2511 for (i = 0; i < power_info->pplib.ucNumStates; i++) {
2512 mode_index = 0;
2513 power_state = (union pplib_power_state *)
2514 (mode_info->atom_context->bios + data_offset +
2515 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
2516 i * power_info->pplib.ucStateEntrySize);
2517 non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
2518 (mode_info->atom_context->bios + data_offset +
2519 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
2520 (power_state->v1.ucNonClockStateIndex *
2521 power_info->pplib.ucNonClockSize));
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002522 rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) *
2523 ((power_info->pplib.ucStateEntrySize - 1) ?
2524 (power_info->pplib.ucStateEntrySize - 1) : 1),
2525 GFP_KERNEL);
2526 if (!rdev->pm.power_state[i].clock_info)
2527 return state_index;
2528 if (power_info->pplib.ucStateEntrySize - 1) {
2529 for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
2530 clock_info = (union pplib_clock_info *)
2531 (mode_info->atom_context->bios + data_offset +
2532 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
2533 (power_state->v1.ucClockStateIndices[j] *
2534 power_info->pplib.ucClockInfoSize));
2535 valid = radeon_atombios_parse_pplib_clock_info(rdev,
2536 state_index, mode_index,
2537 clock_info);
2538 if (valid)
2539 mode_index++;
2540 }
2541 } else {
2542 rdev->pm.power_state[state_index].clock_info[0].mclk =
2543 rdev->clock.default_mclk;
2544 rdev->pm.power_state[state_index].clock_info[0].sclk =
2545 rdev->clock.default_sclk;
2546 mode_index++;
Alex Deucher560154e2010-11-22 17:56:34 -05002547 }
2548 rdev->pm.power_state[state_index].num_clock_modes = mode_index;
2549 if (mode_index) {
2550 radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
2551 non_clock_info);
2552 state_index++;
2553 }
2554 }
2555 /* if multiple clock modes, mark the lowest as no display */
2556 for (i = 0; i < state_index; i++) {
2557 if (rdev->pm.power_state[i].num_clock_modes > 1)
2558 rdev->pm.power_state[i].clock_info[0].flags |=
2559 RADEON_PM_MODE_NO_DISPLAY;
2560 }
2561 /* first mode is usually default */
2562 if (rdev->pm.default_power_state_index == -1) {
2563 rdev->pm.power_state[0].type =
2564 POWER_STATE_TYPE_DEFAULT;
2565 rdev->pm.default_power_state_index = 0;
2566 rdev->pm.power_state[0].default_clock_mode =
2567 &rdev->pm.power_state[0].clock_info[0];
2568 }
2569 return state_index;
2570}
2571
Alex Deucherb0e66412010-11-22 17:56:35 -05002572static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev)
2573{
2574 struct radeon_mode_info *mode_info = &rdev->mode_info;
2575 struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
2576 union pplib_power_state *power_state;
2577 int i, j, non_clock_array_index, clock_array_index;
2578 int state_index = 0, mode_index = 0;
2579 union pplib_clock_info *clock_info;
Alex Deucherf7346882012-03-20 17:17:58 -04002580 struct _StateArray *state_array;
2581 struct _ClockInfoArray *clock_info_array;
2582 struct _NonClockInfoArray *non_clock_info_array;
Alex Deucherb0e66412010-11-22 17:56:35 -05002583 bool valid;
2584 union power_info *power_info;
2585 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2586 u16 data_offset;
2587 u8 frev, crev;
Alex Deucher441e76c2013-05-01 14:34:54 -04002588 u8 *power_state_offset;
Alex Deucherb0e66412010-11-22 17:56:35 -05002589
2590 if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
2591 &frev, &crev, &data_offset))
2592 return state_index;
2593 power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
2594
2595 radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
Alex Deucherf7346882012-03-20 17:17:58 -04002596 state_array = (struct _StateArray *)
Alex Deucherb0e66412010-11-22 17:56:35 -05002597 (mode_info->atom_context->bios + data_offset +
Cédric Cano45894332011-02-11 19:45:37 -05002598 le16_to_cpu(power_info->pplib.usStateArrayOffset));
Alex Deucherf7346882012-03-20 17:17:58 -04002599 clock_info_array = (struct _ClockInfoArray *)
Alex Deucherb0e66412010-11-22 17:56:35 -05002600 (mode_info->atom_context->bios + data_offset +
Cédric Cano45894332011-02-11 19:45:37 -05002601 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
Alex Deucherf7346882012-03-20 17:17:58 -04002602 non_clock_info_array = (struct _NonClockInfoArray *)
Alex Deucherb0e66412010-11-22 17:56:35 -05002603 (mode_info->atom_context->bios + data_offset +
Cédric Cano45894332011-02-11 19:45:37 -05002604 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
Alex Deucherf8e6bfc2013-04-25 09:29:17 -04002605 if (state_array->ucNumEntries == 0)
2606 return state_index;
Alex Deucher0975b162011-02-02 18:42:03 -05002607 rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) *
2608 state_array->ucNumEntries, GFP_KERNEL);
2609 if (!rdev->pm.power_state)
2610 return state_index;
Alex Deucher441e76c2013-05-01 14:34:54 -04002611 power_state_offset = (u8 *)state_array->states;
Alex Deucherb0e66412010-11-22 17:56:35 -05002612 for (i = 0; i < state_array->ucNumEntries; i++) {
2613 mode_index = 0;
Alex Deucher441e76c2013-05-01 14:34:54 -04002614 power_state = (union pplib_power_state *)power_state_offset;
2615 non_clock_array_index = power_state->v2.nonClockInfoIndex;
Alex Deucherb0e66412010-11-22 17:56:35 -05002616 non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
2617 &non_clock_info_array->nonClockInfo[non_clock_array_index];
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002618 rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) *
2619 (power_state->v2.ucNumDPMLevels ?
2620 power_state->v2.ucNumDPMLevels : 1),
2621 GFP_KERNEL);
2622 if (!rdev->pm.power_state[i].clock_info)
2623 return state_index;
2624 if (power_state->v2.ucNumDPMLevels) {
2625 for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
2626 clock_array_index = power_state->v2.clockInfoIndex[j];
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002627 clock_info = (union pplib_clock_info *)
Alex Deucherf7346882012-03-20 17:17:58 -04002628 &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002629 valid = radeon_atombios_parse_pplib_clock_info(rdev,
2630 state_index, mode_index,
2631 clock_info);
2632 if (valid)
2633 mode_index++;
2634 }
2635 } else {
2636 rdev->pm.power_state[state_index].clock_info[0].mclk =
2637 rdev->clock.default_mclk;
2638 rdev->pm.power_state[state_index].clock_info[0].sclk =
2639 rdev->clock.default_sclk;
2640 mode_index++;
Alex Deucherb0e66412010-11-22 17:56:35 -05002641 }
2642 rdev->pm.power_state[state_index].num_clock_modes = mode_index;
2643 if (mode_index) {
2644 radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index,
2645 non_clock_info);
2646 state_index++;
2647 }
Alex Deucher441e76c2013-05-01 14:34:54 -04002648 power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
Alex Deucherb0e66412010-11-22 17:56:35 -05002649 }
2650 /* if multiple clock modes, mark the lowest as no display */
2651 for (i = 0; i < state_index; i++) {
2652 if (rdev->pm.power_state[i].num_clock_modes > 1)
2653 rdev->pm.power_state[i].clock_info[0].flags |=
2654 RADEON_PM_MODE_NO_DISPLAY;
2655 }
2656 /* first mode is usually default */
2657 if (rdev->pm.default_power_state_index == -1) {
2658 rdev->pm.power_state[0].type =
2659 POWER_STATE_TYPE_DEFAULT;
2660 rdev->pm.default_power_state_index = 0;
2661 rdev->pm.power_state[0].default_clock_mode =
2662 &rdev->pm.power_state[0].clock_info[0];
2663 }
2664 return state_index;
2665}
2666
Alex Deucher56278a82009-12-28 13:58:44 -05002667void radeon_atombios_get_power_modes(struct radeon_device *rdev)
2668{
2669 struct radeon_mode_info *mode_info = &rdev->mode_info;
2670 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
2671 u16 data_offset;
2672 u8 frev, crev;
Alex Deucher560154e2010-11-22 17:56:34 -05002673 int state_index = 0;
Alex Deucher56278a82009-12-28 13:58:44 -05002674
Alex Deuchera48b9b42010-04-22 14:03:55 -04002675 rdev->pm.default_power_state_index = -1;
Alex Deucher56278a82009-12-28 13:58:44 -05002676
Alex Deuchera084e6e2010-03-18 01:04:01 -04002677 if (atom_parse_data_header(mode_info->atom_context, index, NULL,
2678 &frev, &crev, &data_offset)) {
Alex Deucher560154e2010-11-22 17:56:34 -05002679 switch (frev) {
2680 case 1:
2681 case 2:
2682 case 3:
2683 state_index = radeon_atombios_parse_power_table_1_3(rdev);
2684 break;
2685 case 4:
2686 case 5:
2687 state_index = radeon_atombios_parse_power_table_4_5(rdev);
2688 break;
Alex Deucherb0e66412010-11-22 17:56:35 -05002689 case 6:
2690 state_index = radeon_atombios_parse_power_table_6(rdev);
2691 break;
Alex Deucher560154e2010-11-22 17:56:34 -05002692 default:
2693 break;
Alex Deucher56278a82009-12-28 13:58:44 -05002694 }
Alex Deucherf8e6bfc2013-04-25 09:29:17 -04002695 }
2696
2697 if (state_index == 0) {
Alex Deucher0975b162011-02-02 18:42:03 -05002698 rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL);
2699 if (rdev->pm.power_state) {
Alex Deucher8f3f1c92011-11-04 10:09:43 -04002700 rdev->pm.power_state[0].clock_info =
2701 kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL);
2702 if (rdev->pm.power_state[0].clock_info) {
2703 /* add the default mode */
2704 rdev->pm.power_state[state_index].type =
2705 POWER_STATE_TYPE_DEFAULT;
2706 rdev->pm.power_state[state_index].num_clock_modes = 1;
2707 rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
2708 rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
2709 rdev->pm.power_state[state_index].default_clock_mode =
2710 &rdev->pm.power_state[state_index].clock_info[0];
2711 rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
2712 rdev->pm.power_state[state_index].pcie_lanes = 16;
2713 rdev->pm.default_power_state_index = state_index;
2714 rdev->pm.power_state[state_index].flags = 0;
2715 state_index++;
2716 }
Alex Deucher0975b162011-02-02 18:42:03 -05002717 }
Alex Deucher56278a82009-12-28 13:58:44 -05002718 }
Alex Deucher02b17cc2010-04-22 13:25:06 -04002719
Alex Deucher56278a82009-12-28 13:58:44 -05002720 rdev->pm.num_power_states = state_index;
Rafał Miłecki9038dfd2010-02-20 23:15:04 +00002721
Alex Deuchera48b9b42010-04-22 14:03:55 -04002722 rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
2723 rdev->pm.current_clock_mode_index = 0;
Alexander Müller4376eee2011-12-30 12:55:48 -05002724 if (rdev->pm.default_power_state_index >= 0)
2725 rdev->pm.current_vddc =
2726 rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
2727 else
2728 rdev->pm.current_vddc = 0;
Alex Deucher56278a82009-12-28 13:58:44 -05002729}
2730
Christian König7062ab62013-04-08 12:41:31 +02002731union get_clock_dividers {
2732 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1;
2733 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2;
2734 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3;
2735 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4;
2736 struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5;
Alex Deucher9219ed62013-02-19 14:35:34 -05002737 struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in;
2738 struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out;
Christian König7062ab62013-04-08 12:41:31 +02002739};
2740
2741int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
2742 u8 clock_type,
2743 u32 clock,
2744 bool strobe_mode,
2745 struct atom_clock_dividers *dividers)
2746{
2747 union get_clock_dividers args;
2748 int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL);
2749 u8 frev, crev;
2750
2751 memset(&args, 0, sizeof(args));
2752 memset(dividers, 0, sizeof(struct atom_clock_dividers));
2753
2754 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
2755 return -EINVAL;
2756
2757 switch (crev) {
2758 case 1:
2759 /* r4xx, r5xx */
2760 args.v1.ucAction = clock_type;
2761 args.v1.ulClock = cpu_to_le32(clock); /* 10 khz */
2762
2763 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2764
2765 dividers->post_div = args.v1.ucPostDiv;
2766 dividers->fb_div = args.v1.ucFbDiv;
2767 dividers->enable_post_div = true;
2768 break;
2769 case 2:
2770 case 3:
Alex Deucher360b1f52013-06-07 11:50:12 -04002771 case 5:
2772 /* r6xx, r7xx, evergreen, ni, si */
Christian König7062ab62013-04-08 12:41:31 +02002773 if (rdev->family <= CHIP_RV770) {
2774 args.v2.ucAction = clock_type;
2775 args.v2.ulClock = cpu_to_le32(clock); /* 10 khz */
2776
2777 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2778
2779 dividers->post_div = args.v2.ucPostDiv;
2780 dividers->fb_div = le16_to_cpu(args.v2.usFbDiv);
2781 dividers->ref_div = args.v2.ucAction;
2782 if (rdev->family == CHIP_RV770) {
2783 dividers->enable_post_div = (le32_to_cpu(args.v2.ulClock) & (1 << 24)) ?
2784 true : false;
2785 dividers->vco_mode = (le32_to_cpu(args.v2.ulClock) & (1 << 25)) ? 1 : 0;
2786 } else
2787 dividers->enable_post_div = (dividers->fb_div & 1) ? true : false;
2788 } else {
2789 if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {
Alex Deucherf4a25962013-04-22 09:59:01 -04002790 args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
Christian König7062ab62013-04-08 12:41:31 +02002791
2792 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2793
2794 dividers->post_div = args.v3.ucPostDiv;
2795 dividers->enable_post_div = (args.v3.ucCntlFlag &
2796 ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
2797 dividers->enable_dithen = (args.v3.ucCntlFlag &
2798 ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
Alex Deucher20fab642013-07-28 12:33:56 -04002799 dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
Christian König7062ab62013-04-08 12:41:31 +02002800 dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
2801 dividers->ref_div = args.v3.ucRefDiv;
2802 dividers->vco_mode = (args.v3.ucCntlFlag &
2803 ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
2804 } else {
Alex Deucher360b1f52013-06-07 11:50:12 -04002805 /* for SI we use ComputeMemoryClockParam for memory plls */
2806 if (rdev->family >= CHIP_TAHITI)
2807 return -EINVAL;
Alex Deucherf4a25962013-04-22 09:59:01 -04002808 args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
Christian König7062ab62013-04-08 12:41:31 +02002809 if (strobe_mode)
2810 args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
2811
2812 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2813
2814 dividers->post_div = args.v5.ucPostDiv;
2815 dividers->enable_post_div = (args.v5.ucCntlFlag &
2816 ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
2817 dividers->enable_dithen = (args.v5.ucCntlFlag &
2818 ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
2819 dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv);
2820 dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac);
2821 dividers->ref_div = args.v5.ucRefDiv;
2822 dividers->vco_mode = (args.v5.ucCntlFlag &
2823 ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
2824 }
2825 }
2826 break;
2827 case 4:
2828 /* fusion */
2829 args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */
2830
2831 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2832
Alex Deucher9219ed62013-02-19 14:35:34 -05002833 dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;
Christian König7062ab62013-04-08 12:41:31 +02002834 dividers->real_clock = le32_to_cpu(args.v4.ulClock);
2835 break;
Alex Deucher9219ed62013-02-19 14:35:34 -05002836 case 6:
2837 /* CI */
2838 /* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */
2839 args.v6_in.ulClock.ulComputeClockFlag = clock_type;
2840 args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */
2841
2842 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2843
2844 dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);
2845 dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);
2846 dividers->ref_div = args.v6_out.ucPllRefDiv;
2847 dividers->post_div = args.v6_out.ucPllPostDiv;
2848 dividers->flags = args.v6_out.ucPllCntlFlag;
2849 dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock);
2850 dividers->post_divider = args.v6_out.ulClock.ucPostDiv;
2851 break;
Christian König7062ab62013-04-08 12:41:31 +02002852 default:
2853 return -EINVAL;
2854 }
2855 return 0;
2856}
2857
Alex Deuchereaa778a2013-02-13 16:38:25 -05002858int radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev,
2859 u32 clock,
2860 bool strobe_mode,
2861 struct atom_mpll_param *mpll_param)
2862{
2863 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 args;
2864 int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam);
2865 u8 frev, crev;
2866
2867 memset(&args, 0, sizeof(args));
2868 memset(mpll_param, 0, sizeof(struct atom_mpll_param));
2869
2870 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
2871 return -EINVAL;
2872
2873 switch (frev) {
2874 case 2:
2875 switch (crev) {
2876 case 1:
2877 /* SI */
2878 args.ulClock = cpu_to_le32(clock); /* 10 khz */
2879 args.ucInputFlag = 0;
2880 if (strobe_mode)
2881 args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN;
2882
2883 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2884
2885 mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac);
2886 mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv);
2887 mpll_param->post_div = args.ucPostDiv;
2888 mpll_param->dll_speed = args.ucDllSpeed;
2889 mpll_param->bwcntl = args.ucBWCntl;
2890 mpll_param->vco_mode =
2891 (args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK) ? 1 : 0;
2892 mpll_param->yclk_sel =
2893 (args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0;
2894 mpll_param->qdr =
2895 (args.ucPllCntlFlag & MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0;
2896 mpll_param->half_rate =
2897 (args.ucPllCntlFlag & MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0;
2898 break;
2899 default:
2900 return -EINVAL;
2901 }
2902 break;
2903 default:
2904 return -EINVAL;
2905 }
2906 return 0;
2907}
2908
Jerome Glisse771fe6b2009-06-05 14:42:42 +02002909void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
2910{
2911 DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
2912 int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
2913
2914 args.ucEnable = enable;
2915
2916 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2917}
2918
Rafał Miłecki74338742009-11-03 00:53:02 +01002919uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev)
2920{
2921 GET_ENGINE_CLOCK_PS_ALLOCATION args;
2922 int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock);
2923
2924 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
Cédric Cano45894332011-02-11 19:45:37 -05002925 return le32_to_cpu(args.ulReturnEngineClock);
Rafał Miłecki74338742009-11-03 00:53:02 +01002926}
2927
2928uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev)
2929{
2930 GET_MEMORY_CLOCK_PS_ALLOCATION args;
2931 int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock);
2932
2933 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
Cédric Cano45894332011-02-11 19:45:37 -05002934 return le32_to_cpu(args.ulReturnMemoryClock);
Rafał Miłecki74338742009-11-03 00:53:02 +01002935}
2936
Jerome Glisse771fe6b2009-06-05 14:42:42 +02002937void radeon_atom_set_engine_clock(struct radeon_device *rdev,
2938 uint32_t eng_clock)
2939{
2940 SET_ENGINE_CLOCK_PS_ALLOCATION args;
2941 int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
2942
Cédric Cano45894332011-02-11 19:45:37 -05002943 args.ulTargetEngineClock = cpu_to_le32(eng_clock); /* 10 khz */
Jerome Glisse771fe6b2009-06-05 14:42:42 +02002944
2945 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2946}
2947
2948void radeon_atom_set_memory_clock(struct radeon_device *rdev,
2949 uint32_t mem_clock)
2950{
2951 SET_MEMORY_CLOCK_PS_ALLOCATION args;
2952 int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
2953
2954 if (rdev->flags & RADEON_IS_IGP)
2955 return;
2956
Cédric Cano45894332011-02-11 19:45:37 -05002957 args.ulTargetMemoryClock = cpu_to_le32(mem_clock); /* 10 khz */
Jerome Glisse771fe6b2009-06-05 14:42:42 +02002958
2959 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2960}
2961
Alex Deucherae5b0ab2013-06-24 10:50:34 -04002962void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev,
2963 u32 eng_clock, u32 mem_clock)
2964{
2965 SET_ENGINE_CLOCK_PS_ALLOCATION args;
2966 int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
2967 u32 tmp;
2968
2969 memset(&args, 0, sizeof(args));
2970
2971 tmp = eng_clock & SET_CLOCK_FREQ_MASK;
2972 tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24);
2973
2974 args.ulTargetEngineClock = cpu_to_le32(tmp);
2975 if (mem_clock)
2976 args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK);
2977
2978 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2979}
2980
2981void radeon_atom_update_memory_dll(struct radeon_device *rdev,
2982 u32 mem_clock)
2983{
2984 u32 args;
2985 int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
2986
2987 args = cpu_to_le32(mem_clock); /* 10 khz */
2988
2989 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
2990}
2991
2992void radeon_atom_set_ac_timing(struct radeon_device *rdev,
2993 u32 mem_clock)
2994{
2995 SET_MEMORY_CLOCK_PS_ALLOCATION args;
2996 int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
2997 u32 tmp = mem_clock | (COMPUTE_MEMORY_PLL_PARAM << 24);
2998
2999 args.ulTargetMemoryClock = cpu_to_le32(tmp); /* 10 khz */
3000
3001 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3002}
3003
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003004union set_voltage {
3005 struct _SET_VOLTAGE_PS_ALLOCATION alloc;
3006 struct _SET_VOLTAGE_PARAMETERS v1;
3007 struct _SET_VOLTAGE_PARAMETERS_V2 v2;
Alex Deuchere83753b2012-03-20 17:18:08 -04003008 struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003009};
3010
Alex Deucher8a83ec52011-04-12 14:49:23 -04003011void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type)
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003012{
3013 union set_voltage args;
3014 int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
Alex Deucher8a83ec52011-04-12 14:49:23 -04003015 u8 frev, crev, volt_index = voltage_level;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003016
3017 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
3018 return;
3019
Alex Deuchera377e182011-06-20 13:00:31 -04003020 /* 0xff01 is a flag rather then an actual voltage */
3021 if (voltage_level == 0xff01)
3022 return;
3023
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003024 switch (crev) {
3025 case 1:
Alex Deucher8a83ec52011-04-12 14:49:23 -04003026 args.v1.ucVoltageType = voltage_type;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003027 args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE;
3028 args.v1.ucVoltageIndex = volt_index;
3029 break;
3030 case 2:
Alex Deucher8a83ec52011-04-12 14:49:23 -04003031 args.v2.ucVoltageType = voltage_type;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003032 args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE;
Alex Deucher8a83ec52011-04-12 14:49:23 -04003033 args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003034 break;
Alex Deuchere83753b2012-03-20 17:18:08 -04003035 case 3:
3036 args.v3.ucVoltageType = voltage_type;
3037 args.v3.ucVoltageMode = ATOM_SET_VOLTAGE;
3038 args.v3.usVoltageLevel = cpu_to_le16(voltage_level);
3039 break;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003040 default:
3041 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3042 return;
3043 }
3044
3045 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3046}
3047
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003048int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
3049 u16 voltage_id, u16 *voltage)
Alex Deucheree4017f2011-06-23 12:19:32 -04003050{
3051 union set_voltage args;
3052 int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
3053 u8 frev, crev;
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003054
Alex Deucheree4017f2011-06-23 12:19:32 -04003055 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
3056 return -EINVAL;
3057
3058 switch (crev) {
3059 case 1:
3060 return -EINVAL;
3061 case 2:
3062 args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;
3063 args.v2.ucVoltageMode = 0;
3064 args.v2.usVoltageLevel = 0;
3065
3066 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3067
3068 *voltage = le16_to_cpu(args.v2.usVoltageLevel);
3069 break;
Alex Deuchere83753b2012-03-20 17:18:08 -04003070 case 3:
3071 args.v3.ucVoltageType = voltage_type;
3072 args.v3.ucVoltageMode = ATOM_GET_VOLTAGE_LEVEL;
3073 args.v3.usVoltageLevel = cpu_to_le16(voltage_id);
3074
3075 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3076
3077 *voltage = le16_to_cpu(args.v3.usVoltageLevel);
3078 break;
Alex Deucheree4017f2011-06-23 12:19:32 -04003079 default:
3080 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3081 return -EINVAL;
3082 }
3083
3084 return 0;
3085}
Alex Deucher7ac9aa52010-05-27 19:25:54 -04003086
Alex Deucherbeb79f42013-02-19 17:14:43 -05003087int radeon_atom_get_leakage_vddc_based_on_leakage_idx(struct radeon_device *rdev,
3088 u16 *voltage,
3089 u16 leakage_idx)
3090{
3091 return radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage);
3092}
3093
Alex Deucher62c35fd72013-02-19 18:15:06 -05003094int radeon_atom_get_leakage_id_from_vbios(struct radeon_device *rdev,
3095 u16 *leakage_id)
3096{
3097 union set_voltage args;
3098 int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
3099 u8 frev, crev;
3100
3101 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
3102 return -EINVAL;
3103
3104 switch (crev) {
3105 case 3:
3106 case 4:
3107 args.v3.ucVoltageType = 0;
3108 args.v3.ucVoltageMode = ATOM_GET_LEAKAGE_ID;
3109 args.v3.usVoltageLevel = 0;
3110
3111 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3112
3113 *leakage_id = le16_to_cpu(args.v3.usVoltageLevel);
3114 break;
3115 default:
3116 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3117 return -EINVAL;
3118 }
3119
3120 return 0;
3121}
3122
3123int radeon_atom_get_leakage_vddc_based_on_leakage_params(struct radeon_device *rdev,
3124 u16 *vddc, u16 *vddci,
3125 u16 virtual_voltage_id,
3126 u16 vbios_voltage_id)
3127{
3128 int index = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo);
3129 u8 frev, crev;
3130 u16 data_offset, size;
3131 int i, j;
3132 ATOM_ASIC_PROFILING_INFO_V2_1 *profile;
3133 u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf;
3134
3135 *vddc = 0;
3136 *vddci = 0;
3137
3138 if (!atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3139 &frev, &crev, &data_offset))
3140 return -EINVAL;
3141
3142 profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *)
3143 (rdev->mode_info.atom_context->bios + data_offset);
3144
3145 switch (frev) {
3146 case 1:
3147 return -EINVAL;
3148 case 2:
3149 switch (crev) {
3150 case 1:
3151 if (size < sizeof(ATOM_ASIC_PROFILING_INFO_V2_1))
3152 return -EINVAL;
3153 leakage_bin = (u16 *)
3154 (rdev->mode_info.atom_context->bios + data_offset +
3155 le16_to_cpu(profile->usLeakageBinArrayOffset));
3156 vddc_id_buf = (u16 *)
3157 (rdev->mode_info.atom_context->bios + data_offset +
3158 le16_to_cpu(profile->usElbVDDC_IdArrayOffset));
3159 vddc_buf = (u16 *)
3160 (rdev->mode_info.atom_context->bios + data_offset +
3161 le16_to_cpu(profile->usElbVDDC_LevelArrayOffset));
3162 vddci_id_buf = (u16 *)
3163 (rdev->mode_info.atom_context->bios + data_offset +
3164 le16_to_cpu(profile->usElbVDDCI_IdArrayOffset));
3165 vddci_buf = (u16 *)
3166 (rdev->mode_info.atom_context->bios + data_offset +
3167 le16_to_cpu(profile->usElbVDDCI_LevelArrayOffset));
3168
3169 if (profile->ucElbVDDC_Num > 0) {
3170 for (i = 0; i < profile->ucElbVDDC_Num; i++) {
3171 if (vddc_id_buf[i] == virtual_voltage_id) {
3172 for (j = 0; j < profile->ucLeakageBinNum; j++) {
3173 if (vbios_voltage_id <= leakage_bin[j]) {
3174 *vddc = vddc_buf[j * profile->ucElbVDDC_Num + i];
3175 break;
3176 }
3177 }
3178 break;
3179 }
3180 }
3181 }
3182 if (profile->ucElbVDDCI_Num > 0) {
3183 for (i = 0; i < profile->ucElbVDDCI_Num; i++) {
3184 if (vddci_id_buf[i] == virtual_voltage_id) {
3185 for (j = 0; j < profile->ucLeakageBinNum; j++) {
3186 if (vbios_voltage_id <= leakage_bin[j]) {
3187 *vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i];
3188 break;
3189 }
3190 }
3191 break;
3192 }
3193 }
3194 }
3195 break;
3196 default:
3197 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3198 return -EINVAL;
3199 }
3200 break;
3201 default:
3202 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3203 return -EINVAL;
3204 }
3205
3206 return 0;
3207}
3208
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003209int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev,
3210 u16 voltage_level, u8 voltage_type,
3211 u32 *gpio_value, u32 *gpio_mask)
3212{
3213 union set_voltage args;
3214 int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
3215 u8 frev, crev;
3216
3217 if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
3218 return -EINVAL;
3219
3220 switch (crev) {
3221 case 1:
3222 return -EINVAL;
3223 case 2:
3224 args.v2.ucVoltageType = voltage_type;
3225 args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK;
3226 args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
3227
3228 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3229
3230 *gpio_mask = le32_to_cpu(*(u32 *)&args.v2);
3231
3232 args.v2.ucVoltageType = voltage_type;
3233 args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL;
3234 args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
3235
3236 atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3237
3238 *gpio_value = le32_to_cpu(*(u32 *)&args.v2);
3239 break;
3240 default:
3241 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3242 return -EINVAL;
3243 }
3244
3245 return 0;
3246}
3247
3248union voltage_object_info {
Alex Deucher58653ab2013-02-13 17:04:59 -05003249 struct _ATOM_VOLTAGE_OBJECT_INFO v1;
3250 struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
3251 struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003252};
3253
Alex Deucher779187f2013-03-28 14:47:34 -04003254union voltage_object {
3255 struct _ATOM_VOLTAGE_OBJECT v1;
3256 struct _ATOM_VOLTAGE_OBJECT_V2 v2;
3257 union _ATOM_VOLTAGE_OBJECT_V3 v3;
3258};
3259
3260static ATOM_VOLTAGE_OBJECT *atom_lookup_voltage_object_v1(ATOM_VOLTAGE_OBJECT_INFO *v1,
3261 u8 voltage_type)
3262{
Alex Deucher6e764762013-06-24 10:54:16 -04003263 u32 size = le16_to_cpu(v1->sHeader.usStructureSize);
Alex Deucher779187f2013-03-28 14:47:34 -04003264 u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO, asVoltageObj[0]);
3265 u8 *start = (u8 *)v1;
3266
3267 while (offset < size) {
3268 ATOM_VOLTAGE_OBJECT *vo = (ATOM_VOLTAGE_OBJECT *)(start + offset);
3269 if (vo->ucVoltageType == voltage_type)
3270 return vo;
3271 offset += offsetof(ATOM_VOLTAGE_OBJECT, asFormula.ucVIDAdjustEntries) +
3272 vo->asFormula.ucNumOfVoltageEntries;
3273 }
3274 return NULL;
3275}
3276
3277static ATOM_VOLTAGE_OBJECT_V2 *atom_lookup_voltage_object_v2(ATOM_VOLTAGE_OBJECT_INFO_V2 *v2,
3278 u8 voltage_type)
3279{
Alex Deucher6e764762013-06-24 10:54:16 -04003280 u32 size = le16_to_cpu(v2->sHeader.usStructureSize);
Alex Deucher779187f2013-03-28 14:47:34 -04003281 u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V2, asVoltageObj[0]);
3282 u8 *start = (u8*)v2;
3283
3284 while (offset < size) {
3285 ATOM_VOLTAGE_OBJECT_V2 *vo = (ATOM_VOLTAGE_OBJECT_V2 *)(start + offset);
3286 if (vo->ucVoltageType == voltage_type)
3287 return vo;
3288 offset += offsetof(ATOM_VOLTAGE_OBJECT_V2, asFormula.asVIDAdjustEntries) +
3289 (vo->asFormula.ucNumOfVoltageEntries * sizeof(VOLTAGE_LUT_ENTRY));
3290 }
3291 return NULL;
3292}
3293
3294static ATOM_VOLTAGE_OBJECT_V3 *atom_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3,
3295 u8 voltage_type, u8 voltage_mode)
3296{
Alex Deucher6e764762013-06-24 10:54:16 -04003297 u32 size = le16_to_cpu(v3->sHeader.usStructureSize);
Alex Deucher779187f2013-03-28 14:47:34 -04003298 u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
3299 u8 *start = (u8*)v3;
3300
3301 while (offset < size) {
3302 ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
3303 if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) &&
3304 (vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode))
3305 return vo;
Alex Deucher6e764762013-06-24 10:54:16 -04003306 offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize);
Alex Deucher779187f2013-03-28 14:47:34 -04003307 }
3308 return NULL;
3309}
3310
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003311bool
Alex Deucher58653ab2013-02-13 17:04:59 -05003312radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
3313 u8 voltage_type, u8 voltage_mode)
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003314{
3315 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3316 u8 frev, crev;
3317 u16 data_offset, size;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003318 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003319 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003320
3321 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3322 &frev, &crev, &data_offset)) {
3323 voltage_info = (union voltage_object_info *)
3324 (rdev->mode_info.atom_context->bios + data_offset);
3325
Alex Deucher58653ab2013-02-13 17:04:59 -05003326 switch (frev) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003327 case 1:
Alex Deucher58653ab2013-02-13 17:04:59 -05003328 case 2:
3329 switch (crev) {
3330 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003331 voltage_object = (union voltage_object *)
3332 atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
3333 if (voltage_object &&
3334 (voltage_object->v1.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
3335 return true;
Alex Deucher58653ab2013-02-13 17:04:59 -05003336 break;
3337 case 2:
Alex Deucher779187f2013-03-28 14:47:34 -04003338 voltage_object = (union voltage_object *)
3339 atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
3340 if (voltage_object &&
3341 (voltage_object->v2.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
3342 return true;
Alex Deucher58653ab2013-02-13 17:04:59 -05003343 break;
3344 default:
3345 DRM_ERROR("unknown voltage object table\n");
3346 return false;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003347 }
3348 break;
Alex Deucher58653ab2013-02-13 17:04:59 -05003349 case 3:
3350 switch (crev) {
3351 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003352 if (atom_lookup_voltage_object_v3(&voltage_info->v3,
3353 voltage_type, voltage_mode))
3354 return true;
Alex Deucher58653ab2013-02-13 17:04:59 -05003355 break;
3356 default:
3357 DRM_ERROR("unknown voltage object table\n");
3358 return false;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003359 }
3360 break;
3361 default:
3362 DRM_ERROR("unknown voltage object table\n");
3363 return false;
3364 }
3365
3366 }
3367 return false;
3368}
3369
3370int radeon_atom_get_max_voltage(struct radeon_device *rdev,
3371 u8 voltage_type, u16 *max_voltage)
3372{
3373 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3374 u8 frev, crev;
3375 u16 data_offset, size;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003376 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003377 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003378
3379 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3380 &frev, &crev, &data_offset)) {
3381 voltage_info = (union voltage_object_info *)
3382 (rdev->mode_info.atom_context->bios + data_offset);
3383
3384 switch (crev) {
3385 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003386 voltage_object = (union voltage_object *)
3387 atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
3388 if (voltage_object) {
3389 ATOM_VOLTAGE_FORMULA *formula =
3390 &voltage_object->v1.asFormula;
3391 if (formula->ucFlag & 1)
3392 *max_voltage =
3393 le16_to_cpu(formula->usVoltageBaseLevel) +
3394 formula->ucNumOfVoltageEntries / 2 *
3395 le16_to_cpu(formula->usVoltageStep);
3396 else
3397 *max_voltage =
3398 le16_to_cpu(formula->usVoltageBaseLevel) +
3399 (formula->ucNumOfVoltageEntries - 1) *
3400 le16_to_cpu(formula->usVoltageStep);
3401 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003402 }
3403 break;
3404 case 2:
Alex Deucher779187f2013-03-28 14:47:34 -04003405 voltage_object = (union voltage_object *)
3406 atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
3407 if (voltage_object) {
3408 ATOM_VOLTAGE_FORMULA_V2 *formula =
3409 &voltage_object->v2.asFormula;
3410 if (formula->ucNumOfVoltageEntries) {
3411 *max_voltage =
3412 le16_to_cpu(formula->asVIDAdjustEntries[
3413 formula->ucNumOfVoltageEntries - 1
3414 ].usVoltageValue);
3415 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003416 }
3417 }
3418 break;
3419 default:
3420 DRM_ERROR("unknown voltage object table\n");
3421 return -EINVAL;
3422 }
3423
3424 }
3425 return -EINVAL;
3426}
3427
3428int radeon_atom_get_min_voltage(struct radeon_device *rdev,
3429 u8 voltage_type, u16 *min_voltage)
3430{
3431 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3432 u8 frev, crev;
3433 u16 data_offset, size;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003434 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003435 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003436
3437 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3438 &frev, &crev, &data_offset)) {
3439 voltage_info = (union voltage_object_info *)
3440 (rdev->mode_info.atom_context->bios + data_offset);
3441
3442 switch (crev) {
3443 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003444 voltage_object = (union voltage_object *)
3445 atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
3446 if (voltage_object) {
3447 ATOM_VOLTAGE_FORMULA *formula =
3448 &voltage_object->v1.asFormula;
3449 *min_voltage =
3450 le16_to_cpu(formula->usVoltageBaseLevel);
3451 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003452 }
3453 break;
3454 case 2:
Alex Deucher779187f2013-03-28 14:47:34 -04003455 voltage_object = (union voltage_object *)
3456 atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
3457 if (voltage_object) {
3458 ATOM_VOLTAGE_FORMULA_V2 *formula =
3459 &voltage_object->v2.asFormula;
3460 if (formula->ucNumOfVoltageEntries) {
3461 *min_voltage =
3462 le16_to_cpu(formula->asVIDAdjustEntries[
3463 0
3464 ].usVoltageValue);
3465 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003466 }
3467 }
3468 break;
3469 default:
3470 DRM_ERROR("unknown voltage object table\n");
3471 return -EINVAL;
3472 }
3473
3474 }
3475 return -EINVAL;
3476}
3477
3478int radeon_atom_get_voltage_step(struct radeon_device *rdev,
3479 u8 voltage_type, u16 *voltage_step)
3480{
3481 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3482 u8 frev, crev;
3483 u16 data_offset, size;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003484 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003485 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003486
3487 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3488 &frev, &crev, &data_offset)) {
3489 voltage_info = (union voltage_object_info *)
3490 (rdev->mode_info.atom_context->bios + data_offset);
3491
3492 switch (crev) {
3493 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003494 voltage_object = (union voltage_object *)
3495 atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
3496 if (voltage_object) {
3497 ATOM_VOLTAGE_FORMULA *formula =
3498 &voltage_object->v1.asFormula;
3499 if (formula->ucFlag & 1)
3500 *voltage_step =
3501 (le16_to_cpu(formula->usVoltageStep) + 1) / 2;
3502 else
3503 *voltage_step =
3504 le16_to_cpu(formula->usVoltageStep);
3505 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003506 }
3507 break;
3508 case 2:
3509 return -EINVAL;
3510 default:
3511 DRM_ERROR("unknown voltage object table\n");
3512 return -EINVAL;
3513 }
3514
3515 }
3516 return -EINVAL;
3517}
3518
3519int radeon_atom_round_to_true_voltage(struct radeon_device *rdev,
3520 u8 voltage_type,
3521 u16 nominal_voltage,
3522 u16 *true_voltage)
3523{
3524 u16 min_voltage, max_voltage, voltage_step;
3525
3526 if (radeon_atom_get_max_voltage(rdev, voltage_type, &max_voltage))
3527 return -EINVAL;
3528 if (radeon_atom_get_min_voltage(rdev, voltage_type, &min_voltage))
3529 return -EINVAL;
3530 if (radeon_atom_get_voltage_step(rdev, voltage_type, &voltage_step))
3531 return -EINVAL;
3532
3533 if (nominal_voltage <= min_voltage)
3534 *true_voltage = min_voltage;
3535 else if (nominal_voltage >= max_voltage)
3536 *true_voltage = max_voltage;
3537 else
3538 *true_voltage = min_voltage +
3539 ((nominal_voltage - min_voltage) / voltage_step) *
3540 voltage_step;
3541
3542 return 0;
3543}
3544
3545int radeon_atom_get_voltage_table(struct radeon_device *rdev,
Alex Deucher65171942013-02-13 17:29:54 -05003546 u8 voltage_type, u8 voltage_mode,
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003547 struct atom_voltage_table *voltage_table)
3548{
3549 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
3550 u8 frev, crev;
3551 u16 data_offset, size;
Alex Deucher779187f2013-03-28 14:47:34 -04003552 int i, ret;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003553 union voltage_object_info *voltage_info;
Alex Deucher779187f2013-03-28 14:47:34 -04003554 union voltage_object *voltage_object = NULL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003555
3556 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3557 &frev, &crev, &data_offset)) {
3558 voltage_info = (union voltage_object_info *)
3559 (rdev->mode_info.atom_context->bios + data_offset);
3560
Alex Deucher65171942013-02-13 17:29:54 -05003561 switch (frev) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003562 case 1:
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003563 case 2:
Alex Deucher65171942013-02-13 17:29:54 -05003564 switch (crev) {
3565 case 1:
3566 DRM_ERROR("old table version %d, %d\n", frev, crev);
3567 return -EINVAL;
3568 case 2:
Alex Deucher779187f2013-03-28 14:47:34 -04003569 voltage_object = (union voltage_object *)
3570 atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
3571 if (voltage_object) {
3572 ATOM_VOLTAGE_FORMULA_V2 *formula =
3573 &voltage_object->v2.asFormula;
3574 if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES)
3575 return -EINVAL;
3576 for (i = 0; i < formula->ucNumOfVoltageEntries; i++) {
3577 voltage_table->entries[i].value =
3578 le16_to_cpu(formula->asVIDAdjustEntries[i].usVoltageValue);
3579 ret = radeon_atom_get_voltage_gpio_settings(rdev,
3580 voltage_table->entries[i].value,
3581 voltage_type,
3582 &voltage_table->entries[i].smio_low,
3583 &voltage_table->mask_low);
3584 if (ret)
3585 return ret;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003586 }
Alex Deucher779187f2013-03-28 14:47:34 -04003587 voltage_table->count = formula->ucNumOfVoltageEntries;
3588 return 0;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003589 }
Alex Deucher65171942013-02-13 17:29:54 -05003590 break;
3591 default:
3592 DRM_ERROR("unknown voltage object table\n");
3593 return -EINVAL;
3594 }
3595 break;
3596 case 3:
3597 switch (crev) {
3598 case 1:
Alex Deucher779187f2013-03-28 14:47:34 -04003599 voltage_object = (union voltage_object *)
3600 atom_lookup_voltage_object_v3(&voltage_info->v3,
3601 voltage_type, voltage_mode);
3602 if (voltage_object) {
3603 ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio =
3604 &voltage_object->v3.asGpioVoltageObj;
3605 if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES)
3606 return -EINVAL;
3607 for (i = 0; i < gpio->ucGpioEntryNum; i++) {
3608 voltage_table->entries[i].value =
3609 le16_to_cpu(gpio->asVolGpioLut[i].usVoltageValue);
3610 voltage_table->entries[i].smio_low =
3611 le32_to_cpu(gpio->asVolGpioLut[i].ulVoltageId);
Alex Deucher65171942013-02-13 17:29:54 -05003612 }
Alex Deucher779187f2013-03-28 14:47:34 -04003613 voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal);
3614 voltage_table->count = gpio->ucGpioEntryNum;
3615 voltage_table->phase_delay = gpio->ucPhaseDelay;
3616 return 0;
Alex Deucher65171942013-02-13 17:29:54 -05003617 }
3618 break;
3619 default:
3620 DRM_ERROR("unknown voltage object table\n");
3621 return -EINVAL;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003622 }
3623 break;
3624 default:
3625 DRM_ERROR("unknown voltage object table\n");
3626 return -EINVAL;
3627 }
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003628 }
3629 return -EINVAL;
3630}
3631
3632union vram_info {
3633 struct _ATOM_VRAM_INFO_V3 v1_3;
3634 struct _ATOM_VRAM_INFO_V4 v1_4;
3635 struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1;
3636};
3637
3638int radeon_atom_get_memory_info(struct radeon_device *rdev,
3639 u8 module_index, struct atom_memory_info *mem_info)
3640{
3641 int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
3642 u8 frev, crev, i;
3643 u16 data_offset, size;
3644 union vram_info *vram_info;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003645
3646 memset(mem_info, 0, sizeof(struct atom_memory_info));
3647
3648 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3649 &frev, &crev, &data_offset)) {
3650 vram_info = (union vram_info *)
3651 (rdev->mode_info.atom_context->bios + data_offset);
3652 switch (frev) {
3653 case 1:
3654 switch (crev) {
3655 case 3:
3656 /* r6xx */
3657 if (module_index < vram_info->v1_3.ucNumOfVRAMModule) {
3658 ATOM_VRAM_MODULE_V3 *vram_module =
3659 (ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003660
3661 for (i = 0; i < module_index; i++) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003662 if (le16_to_cpu(vram_module->usSize) == 0)
3663 return -EINVAL;
Alex Deucher77c7d502013-07-17 10:52:43 -04003664 vram_module = (ATOM_VRAM_MODULE_V3 *)
3665 ((u8 *)vram_module + le16_to_cpu(vram_module->usSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003666 }
3667 mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf;
3668 mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0;
3669 } else
3670 return -EINVAL;
3671 break;
3672 case 4:
3673 /* r7xx, evergreen */
3674 if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
3675 ATOM_VRAM_MODULE_V4 *vram_module =
3676 (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003677
3678 for (i = 0; i < module_index; i++) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003679 if (le16_to_cpu(vram_module->usModuleSize) == 0)
3680 return -EINVAL;
Alex Deucher77c7d502013-07-17 10:52:43 -04003681 vram_module = (ATOM_VRAM_MODULE_V4 *)
3682 ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003683 }
3684 mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
3685 mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
3686 } else
3687 return -EINVAL;
3688 break;
3689 default:
3690 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3691 return -EINVAL;
3692 }
3693 break;
3694 case 2:
3695 switch (crev) {
3696 case 1:
3697 /* ni */
3698 if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
3699 ATOM_VRAM_MODULE_V7 *vram_module =
3700 (ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003701
3702 for (i = 0; i < module_index; i++) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003703 if (le16_to_cpu(vram_module->usModuleSize) == 0)
3704 return -EINVAL;
Alex Deucher77c7d502013-07-17 10:52:43 -04003705 vram_module = (ATOM_VRAM_MODULE_V7 *)
3706 ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003707 }
3708 mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
3709 mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
3710 } else
3711 return -EINVAL;
3712 break;
3713 default:
3714 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3715 return -EINVAL;
3716 }
3717 break;
3718 default:
3719 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3720 return -EINVAL;
3721 }
3722 return 0;
3723 }
3724 return -EINVAL;
3725}
3726
3727int radeon_atom_get_mclk_range_table(struct radeon_device *rdev,
3728 bool gddr5, u8 module_index,
3729 struct atom_memory_clock_range_table *mclk_range_table)
3730{
3731 int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
3732 u8 frev, crev, i;
3733 u16 data_offset, size;
3734 union vram_info *vram_info;
3735 u32 mem_timing_size = gddr5 ?
3736 sizeof(ATOM_MEMORY_TIMING_FORMAT_V2) : sizeof(ATOM_MEMORY_TIMING_FORMAT);
3737 u8 *p;
3738
3739 memset(mclk_range_table, 0, sizeof(struct atom_memory_clock_range_table));
3740
3741 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3742 &frev, &crev, &data_offset)) {
3743 vram_info = (union vram_info *)
3744 (rdev->mode_info.atom_context->bios + data_offset);
3745 switch (frev) {
3746 case 1:
3747 switch (crev) {
3748 case 3:
3749 DRM_ERROR("old table version %d, %d\n", frev, crev);
3750 return -EINVAL;
3751 case 4:
3752 /* r7xx, evergreen */
3753 if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
3754 ATOM_VRAM_MODULE_V4 *vram_module =
3755 (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003756
3757 for (i = 0; i < module_index; i++) {
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003758 if (le16_to_cpu(vram_module->usModuleSize) == 0)
3759 return -EINVAL;
Alex Deucher77c7d502013-07-17 10:52:43 -04003760 vram_module = (ATOM_VRAM_MODULE_V4 *)
3761 ((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003762 }
3763 mclk_range_table->num_entries = (u8)
Alex Deucher1fa42522013-07-17 10:18:52 -04003764 ((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) /
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003765 mem_timing_size);
Alex Deucher77c7d502013-07-17 10:52:43 -04003766 p = (u8 *)&vram_module->asMemTiming[0];
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003767 for (i = 0; i < mclk_range_table->num_entries; i++) {
Alex Deucher77c7d502013-07-17 10:52:43 -04003768 ATOM_MEMORY_TIMING_FORMAT *format = (ATOM_MEMORY_TIMING_FORMAT *)p;
Alex Deuchere6312272013-07-03 11:18:08 -04003769 mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange);
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003770 p += mem_timing_size;
3771 }
3772 } else
3773 return -EINVAL;
3774 break;
3775 default:
3776 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3777 return -EINVAL;
3778 }
3779 break;
3780 case 2:
3781 DRM_ERROR("new table version %d, %d\n", frev, crev);
3782 return -EINVAL;
3783 default:
3784 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3785 return -EINVAL;
3786 }
3787 return 0;
3788 }
3789 return -EINVAL;
3790}
3791
3792#define MEM_ID_MASK 0xff000000
3793#define MEM_ID_SHIFT 24
3794#define CLOCK_RANGE_MASK 0x00ffffff
3795#define CLOCK_RANGE_SHIFT 0
3796#define LOW_NIBBLE_MASK 0xf
3797#define DATA_EQU_PREV 0
3798#define DATA_FROM_TABLE 4
3799
3800int radeon_atom_init_mc_reg_table(struct radeon_device *rdev,
3801 u8 module_index,
3802 struct atom_mc_reg_table *reg_table)
3803{
3804 int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
3805 u8 frev, crev, num_entries, t_mem_id, num_ranges = 0;
3806 u32 i = 0, j;
3807 u16 data_offset, size;
3808 union vram_info *vram_info;
3809
3810 memset(reg_table, 0, sizeof(struct atom_mc_reg_table));
3811
3812 if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
3813 &frev, &crev, &data_offset)) {
3814 vram_info = (union vram_info *)
3815 (rdev->mode_info.atom_context->bios + data_offset);
3816 switch (frev) {
3817 case 1:
3818 DRM_ERROR("old table version %d, %d\n", frev, crev);
3819 return -EINVAL;
3820 case 2:
3821 switch (crev) {
3822 case 1:
3823 if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
3824 ATOM_INIT_REG_BLOCK *reg_block =
3825 (ATOM_INIT_REG_BLOCK *)
3826 ((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset));
3827 ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data =
3828 (ATOM_MEMORY_SETTING_DATA_BLOCK *)
3829 ((u8 *)reg_block + (2 * sizeof(u16)) +
3830 le16_to_cpu(reg_block->usRegIndexTblSize));
Alex Deucherf90555c2013-07-17 16:34:12 -04003831 ATOM_INIT_REG_INDEX_FORMAT *format = &reg_block->asRegIndexBuf[0];
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003832 num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) /
3833 sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1;
3834 if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE)
3835 return -EINVAL;
Andre Heider48fa04c2013-07-17 14:02:23 -04003836 while (i < num_entries) {
Alex Deucherf90555c2013-07-17 16:34:12 -04003837 if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER)
Andre Heider48fa04c2013-07-17 14:02:23 -04003838 break;
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003839 reg_table->mc_reg_address[i].s1 =
Alex Deucherf90555c2013-07-17 16:34:12 -04003840 (u16)(le16_to_cpu(format->usRegIndex));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003841 reg_table->mc_reg_address[i].pre_reg_data =
Alex Deucherf90555c2013-07-17 16:34:12 -04003842 (u8)(format->ucPreRegDataLength);
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003843 i++;
Alex Deucherf90555c2013-07-17 16:34:12 -04003844 format = (ATOM_INIT_REG_INDEX_FORMAT *)
3845 ((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003846 }
3847 reg_table->last = i;
3848 while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) &&
3849 (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {
3850 t_mem_id = (u8)((*(u32 *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
3851 if (module_index == t_mem_id) {
3852 reg_table->mc_reg_table_entry[num_ranges].mclk_max =
3853 (u32)((*(u32 *)reg_data & CLOCK_RANGE_MASK) >> CLOCK_RANGE_SHIFT);
3854 for (i = 0, j = 1; i < reg_table->last; i++) {
3855 if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
3856 reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
3857 (u32)*((u32 *)reg_data + j);
3858 j++;
3859 } else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
3860 reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
3861 reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1];
3862 }
3863 }
3864 num_ranges++;
3865 }
Alex Deucher4da18e22013-07-01 13:33:53 -04003866 reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
3867 ((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));
Alex Deucherae5b0ab2013-06-24 10:50:34 -04003868 }
3869 if (*(u32 *)reg_data != END_OF_REG_DATA_BLOCK)
3870 return -EINVAL;
3871 reg_table->num_entries = num_ranges;
3872 } else
3873 return -EINVAL;
3874 break;
3875 default:
3876 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3877 return -EINVAL;
3878 }
3879 break;
3880 default:
3881 DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
3882 return -EINVAL;
3883 }
3884 return 0;
3885 }
3886 return -EINVAL;
3887}
3888
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003889void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
3890{
3891 struct radeon_device *rdev = dev->dev_private;
3892 uint32_t bios_2_scratch, bios_6_scratch;
3893
3894 if (rdev->family >= CHIP_R600) {
Dave Airlie4ce001a2009-08-13 16:32:14 +10003895 bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003896 bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
3897 } else {
Dave Airlie4ce001a2009-08-13 16:32:14 +10003898 bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003899 bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
3900 }
3901
3902 /* let the bios control the backlight */
3903 bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;
3904
3905 /* tell the bios not to handle mode switching */
Alex Deucher87364762011-02-02 19:46:06 -05003906 bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003907
3908 if (rdev->family >= CHIP_R600) {
3909 WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
3910 WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
3911 } else {
3912 WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
3913 WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
3914 }
3915
3916}
3917
Yang Zhaof657c2a2009-09-15 12:21:01 +10003918void radeon_save_bios_scratch_regs(struct radeon_device *rdev)
3919{
3920 uint32_t scratch_reg;
3921 int i;
3922
3923 if (rdev->family >= CHIP_R600)
3924 scratch_reg = R600_BIOS_0_SCRATCH;
3925 else
3926 scratch_reg = RADEON_BIOS_0_SCRATCH;
3927
3928 for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++)
3929 rdev->bios_scratch[i] = RREG32(scratch_reg + (i * 4));
3930}
3931
3932void radeon_restore_bios_scratch_regs(struct radeon_device *rdev)
3933{
3934 uint32_t scratch_reg;
3935 int i;
3936
3937 if (rdev->family >= CHIP_R600)
3938 scratch_reg = R600_BIOS_0_SCRATCH;
3939 else
3940 scratch_reg = RADEON_BIOS_0_SCRATCH;
3941
3942 for (i = 0; i < RADEON_BIOS_NUM_SCRATCH; i++)
3943 WREG32(scratch_reg + (i * 4), rdev->bios_scratch[i]);
3944}
3945
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003946void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock)
3947{
3948 struct drm_device *dev = encoder->dev;
3949 struct radeon_device *rdev = dev->dev_private;
3950 uint32_t bios_6_scratch;
3951
3952 if (rdev->family >= CHIP_R600)
3953 bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
3954 else
3955 bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
3956
Alex Deucher87364762011-02-02 19:46:06 -05003957 if (lock) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003958 bios_6_scratch |= ATOM_S6_CRITICAL_STATE;
Alex Deucher87364762011-02-02 19:46:06 -05003959 bios_6_scratch &= ~ATOM_S6_ACC_MODE;
3960 } else {
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003961 bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;
Alex Deucher87364762011-02-02 19:46:06 -05003962 bios_6_scratch |= ATOM_S6_ACC_MODE;
3963 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003964
3965 if (rdev->family >= CHIP_R600)
3966 WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
3967 else
3968 WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
3969}
3970
3971/* at some point we may want to break this out into individual functions */
3972void
3973radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
3974 struct drm_encoder *encoder,
3975 bool connected)
3976{
3977 struct drm_device *dev = connector->dev;
3978 struct radeon_device *rdev = dev->dev_private;
3979 struct radeon_connector *radeon_connector =
3980 to_radeon_connector(connector);
3981 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
3982 uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch;
3983
3984 if (rdev->family >= CHIP_R600) {
3985 bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH);
3986 bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
3987 bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
3988 } else {
3989 bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
3990 bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
3991 bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
3992 }
3993
3994 if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) &&
3995 (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) {
3996 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10003997 DRM_DEBUG_KMS("TV1 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02003998 bios_3_scratch |= ATOM_S3_TV1_ACTIVE;
3999 bios_6_scratch |= ATOM_S6_ACC_REQ_TV1;
4000 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004001 DRM_DEBUG_KMS("TV1 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004002 bios_0_scratch &= ~ATOM_S0_TV1_MASK;
4003 bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE;
4004 bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1;
4005 }
4006 }
4007 if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) &&
4008 (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) {
4009 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004010 DRM_DEBUG_KMS("CV connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004011 bios_3_scratch |= ATOM_S3_CV_ACTIVE;
4012 bios_6_scratch |= ATOM_S6_ACC_REQ_CV;
4013 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004014 DRM_DEBUG_KMS("CV disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004015 bios_0_scratch &= ~ATOM_S0_CV_MASK;
4016 bios_3_scratch &= ~ATOM_S3_CV_ACTIVE;
4017 bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV;
4018 }
4019 }
4020 if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
4021 (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
4022 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004023 DRM_DEBUG_KMS("LCD1 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004024 bios_0_scratch |= ATOM_S0_LCD1;
4025 bios_3_scratch |= ATOM_S3_LCD1_ACTIVE;
4026 bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1;
4027 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004028 DRM_DEBUG_KMS("LCD1 disconnected\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 }
4033 }
4034 if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
4035 (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
4036 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004037 DRM_DEBUG_KMS("CRT1 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004038 bios_0_scratch |= ATOM_S0_CRT1_COLOR;
4039 bios_3_scratch |= ATOM_S3_CRT1_ACTIVE;
4040 bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1;
4041 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004042 DRM_DEBUG_KMS("CRT1 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004043 bios_0_scratch &= ~ATOM_S0_CRT1_MASK;
4044 bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE;
4045 bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1;
4046 }
4047 }
4048 if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
4049 (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
4050 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004051 DRM_DEBUG_KMS("CRT2 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004052 bios_0_scratch |= ATOM_S0_CRT2_COLOR;
4053 bios_3_scratch |= ATOM_S3_CRT2_ACTIVE;
4054 bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2;
4055 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004056 DRM_DEBUG_KMS("CRT2 disconnected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004057 bios_0_scratch &= ~ATOM_S0_CRT2_MASK;
4058 bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE;
4059 bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2;
4060 }
4061 }
4062 if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
4063 (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
4064 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004065 DRM_DEBUG_KMS("DFP1 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004066 bios_0_scratch |= ATOM_S0_DFP1;
4067 bios_3_scratch |= ATOM_S3_DFP1_ACTIVE;
4068 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1;
4069 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004070 DRM_DEBUG_KMS("DFP1 disconnected\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 }
4075 }
4076 if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
4077 (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
4078 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004079 DRM_DEBUG_KMS("DFP2 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004080 bios_0_scratch |= ATOM_S0_DFP2;
4081 bios_3_scratch |= ATOM_S3_DFP2_ACTIVE;
4082 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2;
4083 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004084 DRM_DEBUG_KMS("DFP2 disconnected\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 }
4089 }
4090 if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) &&
4091 (radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) {
4092 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004093 DRM_DEBUG_KMS("DFP3 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004094 bios_0_scratch |= ATOM_S0_DFP3;
4095 bios_3_scratch |= ATOM_S3_DFP3_ACTIVE;
4096 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3;
4097 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004098 DRM_DEBUG_KMS("DFP3 disconnected\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 }
4103 }
4104 if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) &&
4105 (radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) {
4106 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004107 DRM_DEBUG_KMS("DFP4 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004108 bios_0_scratch |= ATOM_S0_DFP4;
4109 bios_3_scratch |= ATOM_S3_DFP4_ACTIVE;
4110 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4;
4111 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004112 DRM_DEBUG_KMS("DFP4 disconnected\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 }
4117 }
4118 if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) &&
4119 (radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) {
4120 if (connected) {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004121 DRM_DEBUG_KMS("DFP5 connected\n");
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004122 bios_0_scratch |= ATOM_S0_DFP5;
4123 bios_3_scratch |= ATOM_S3_DFP5_ACTIVE;
4124 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5;
4125 } else {
Dave Airlied9fdaaf2010-08-02 10:42:55 +10004126 DRM_DEBUG_KMS("DFP5 disconnected\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 }
4131 }
Alex Deucher6f9f8a62012-02-13 08:59:41 -05004132 if ((radeon_encoder->devices & ATOM_DEVICE_DFP6_SUPPORT) &&
4133 (radeon_connector->devices & ATOM_DEVICE_DFP6_SUPPORT)) {
4134 if (connected) {
4135 DRM_DEBUG_KMS("DFP6 connected\n");
4136 bios_0_scratch |= ATOM_S0_DFP6;
4137 bios_3_scratch |= ATOM_S3_DFP6_ACTIVE;
4138 bios_6_scratch |= ATOM_S6_ACC_REQ_DFP6;
4139 } else {
4140 DRM_DEBUG_KMS("DFP6 disconnected\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 }
4145 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004146
4147 if (rdev->family >= CHIP_R600) {
4148 WREG32(R600_BIOS_0_SCRATCH, bios_0_scratch);
4149 WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
4150 WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
4151 } else {
4152 WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch);
4153 WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
4154 WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
4155 }
4156}
4157
4158void
4159radeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc)
4160{
4161 struct drm_device *dev = encoder->dev;
4162 struct radeon_device *rdev = dev->dev_private;
4163 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4164 uint32_t bios_3_scratch;
4165
Alex Deucher6f9f8a62012-02-13 08:59:41 -05004166 if (ASIC_IS_DCE4(rdev))
4167 return;
4168
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004169 if (rdev->family >= CHIP_R600)
4170 bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
4171 else
4172 bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
4173
4174 if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
4175 bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE;
4176 bios_3_scratch |= (crtc << 18);
4177 }
4178 if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
4179 bios_3_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE;
4180 bios_3_scratch |= (crtc << 24);
4181 }
4182 if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
4183 bios_3_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE;
4184 bios_3_scratch |= (crtc << 16);
4185 }
4186 if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
4187 bios_3_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE;
4188 bios_3_scratch |= (crtc << 20);
4189 }
4190 if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
4191 bios_3_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE;
4192 bios_3_scratch |= (crtc << 17);
4193 }
4194 if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
4195 bios_3_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE;
4196 bios_3_scratch |= (crtc << 19);
4197 }
4198 if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
4199 bios_3_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE;
4200 bios_3_scratch |= (crtc << 23);
4201 }
4202 if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
4203 bios_3_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE;
4204 bios_3_scratch |= (crtc << 25);
4205 }
4206
4207 if (rdev->family >= CHIP_R600)
4208 WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
4209 else
4210 WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
4211}
4212
4213void
4214radeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on)
4215{
4216 struct drm_device *dev = encoder->dev;
4217 struct radeon_device *rdev = dev->dev_private;
4218 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4219 uint32_t bios_2_scratch;
4220
Alex Deucher3ac0eb62012-02-19 21:42:03 -05004221 if (ASIC_IS_DCE4(rdev))
4222 return;
4223
Jerome Glisse771fe6b2009-06-05 14:42:42 +02004224 if (rdev->family >= CHIP_R600)
4225 bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
4226 else
4227 bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
4228
4229 if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
4230 if (on)
4231 bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE;
4232 else
4233 bios_2_scratch |= ATOM_S2_TV1_DPMS_STATE;
4234 }
4235 if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
4236 if (on)
4237 bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE;
4238 else
4239 bios_2_scratch |= ATOM_S2_CV_DPMS_STATE;
4240 }
4241 if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
4242 if (on)
4243 bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE;
4244 else
4245 bios_2_scratch |= ATOM_S2_CRT1_DPMS_STATE;
4246 }
4247 if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
4248 if (on)
4249 bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE;
4250 else
4251 bios_2_scratch |= ATOM_S2_CRT2_DPMS_STATE;
4252 }
4253 if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
4254 if (on)
4255 bios_2_scratch &= ~ATOM_S2_LCD1_DPMS_STATE;
4256 else
4257 bios_2_scratch |= ATOM_S2_LCD1_DPMS_STATE;
4258 }
4259 if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
4260 if (on)
4261 bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE;
4262 else
4263 bios_2_scratch |= ATOM_S2_DFP1_DPMS_STATE;
4264 }
4265 if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
4266 if (on)
4267 bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE;
4268 else
4269 bios_2_scratch |= ATOM_S2_DFP2_DPMS_STATE;
4270 }
4271 if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
4272 if (on)
4273 bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE;
4274 else
4275 bios_2_scratch |= ATOM_S2_DFP3_DPMS_STATE;
4276 }
4277 if (radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) {
4278 if (on)
4279 bios_2_scratch &= ~ATOM_S2_DFP4_DPMS_STATE;
4280 else
4281 bios_2_scratch |= ATOM_S2_DFP4_DPMS_STATE;
4282 }
4283 if (radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) {
4284 if (on)
4285 bios_2_scratch &= ~ATOM_S2_DFP5_DPMS_STATE;
4286 else
4287 bios_2_scratch |= ATOM_S2_DFP5_DPMS_STATE;
4288 }
4289
4290 if (rdev->family >= CHIP_R600)
4291 WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
4292 else
4293 WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
4294}