1 /*
2 * Copyright 2006-2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Alexander von Gluck, kallisti5@unixzen.com
7 * Bill Randle, billr@neocat.org
8 */
9
10 /*
11 * It's dangerous to go alone, take this!
12 * framebuffer -> crtc -> encoder -> transmitter -> connector -> monitor
13 */
14
15
16 #include "display.h"
17
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "accelerant.h"
22 #include "accelerant_protos.h"
23 #include "bios.h"
24 #include "connector.h"
25 #include "displayport.h"
26 #include "encoder.h"
27
28
29 #define TRACE_DISPLAY
30 #ifdef TRACE_DISPLAY
31 extern "C" void _sPrintf(const char* format, ...);
32 # define TRACE(x...) _sPrintf("radeon_hd: " x)
33 #else
34 # define TRACE(x...) ;
35 #endif
36
37 #define ERROR(x...) _sPrintf("radeon_hd: " x)
38
39
40 /*! Populate regs with device dependant register locations */
41 status_t
init_registers(register_info * regs,uint8 crtcID)42 init_registers(register_info* regs, uint8 crtcID)
43 {
44 memset(regs, 0, sizeof(register_info));
45
46 radeon_shared_info &info = *gInfo->shared_info;
47
48 if (info.chipsetID >= RADEON_CEDAR) {
49 // Evergreen
50 uint32 offset = 0;
51
52 switch (crtcID) {
53 case 0:
54 offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
55 regs->vgaControl = AVIVO_D1VGA_CONTROL;
56 break;
57 case 1:
58 offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
59 regs->vgaControl = AVIVO_D2VGA_CONTROL;
60 break;
61 case 2:
62 offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
63 regs->vgaControl = EVERGREEN_D3VGA_CONTROL;
64 break;
65 case 3:
66 offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
67 regs->vgaControl = EVERGREEN_D4VGA_CONTROL;
68 break;
69 case 4:
70 offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
71 regs->vgaControl = EVERGREEN_D5VGA_CONTROL;
72 break;
73 case 5:
74 offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
75 regs->vgaControl = EVERGREEN_D6VGA_CONTROL;
76 break;
77 default:
78 ERROR("%s: Unknown CRTC %" B_PRIu32 "\n",
79 __func__, crtcID);
80 return B_ERROR;
81 }
82
83 regs->crtcOffset = offset;
84
85 regs->grphEnable = EVERGREEN_GRPH_ENABLE + offset;
86 regs->grphControl = EVERGREEN_GRPH_CONTROL + offset;
87 regs->grphSwapControl = EVERGREEN_GRPH_SWAP_CONTROL + offset;
88
89 regs->grphPrimarySurfaceAddr
90 = EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + offset;
91 regs->grphSecondarySurfaceAddr
92 = EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + offset;
93 regs->grphPrimarySurfaceAddrHigh
94 = EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + offset;
95 regs->grphSecondarySurfaceAddrHigh
96 = EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + offset;
97
98 regs->grphPitch = EVERGREEN_GRPH_PITCH + offset;
99 regs->grphSurfaceOffsetX
100 = EVERGREEN_GRPH_SURFACE_OFFSET_X + offset;
101 regs->grphSurfaceOffsetY
102 = EVERGREEN_GRPH_SURFACE_OFFSET_Y + offset;
103 regs->grphXStart = EVERGREEN_GRPH_X_START + offset;
104 regs->grphYStart = EVERGREEN_GRPH_Y_START + offset;
105 regs->grphXEnd = EVERGREEN_GRPH_X_END + offset;
106 regs->grphYEnd = EVERGREEN_GRPH_Y_END + offset;
107 regs->modeDesktopHeight = EVERGREEN_DESKTOP_HEIGHT + offset;
108 regs->modeDataFormat = EVERGREEN_DATA_FORMAT + offset;
109 regs->viewportStart = EVERGREEN_VIEWPORT_START + offset;
110 regs->viewportSize = EVERGREEN_VIEWPORT_SIZE + offset;
111
112 } else if (info.chipsetID >= RADEON_RV770) {
113 // R700 series
114 uint32 offset = 0;
115
116 switch (crtcID) {
117 case 0:
118 offset = R700_CRTC0_REGISTER_OFFSET;
119 regs->vgaControl = AVIVO_D1VGA_CONTROL;
120 regs->grphPrimarySurfaceAddrHigh
121 = R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH;
122 break;
123 case 1:
124 offset = R700_CRTC1_REGISTER_OFFSET;
125 regs->vgaControl = AVIVO_D2VGA_CONTROL;
126 regs->grphPrimarySurfaceAddrHigh
127 = R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH;
128 break;
129 default:
130 ERROR("%s: Unknown CRTC %" B_PRIu32 "\n",
131 __func__, crtcID);
132 return B_ERROR;
133 }
134
135 regs->crtcOffset = offset;
136
137 regs->grphEnable = AVIVO_D1GRPH_ENABLE + offset;
138 regs->grphControl = AVIVO_D1GRPH_CONTROL + offset;
139 regs->grphSwapControl = AVIVO_D1GRPH_SWAP_CNTL + offset;
140
141 regs->grphPrimarySurfaceAddr
142 = R700_D1GRPH_PRIMARY_SURFACE_ADDRESS + offset;
143 regs->grphSecondarySurfaceAddr
144 = R700_D1GRPH_SECONDARY_SURFACE_ADDRESS + offset;
145
146 regs->grphPitch = AVIVO_D1GRPH_PITCH + offset;
147 regs->grphSurfaceOffsetX = AVIVO_D1GRPH_SURFACE_OFFSET_X + offset;
148 regs->grphSurfaceOffsetY = AVIVO_D1GRPH_SURFACE_OFFSET_Y + offset;
149 regs->grphXStart = AVIVO_D1GRPH_X_START + offset;
150 regs->grphYStart = AVIVO_D1GRPH_Y_START + offset;
151 regs->grphXEnd = AVIVO_D1GRPH_X_END + offset;
152 regs->grphYEnd = AVIVO_D1GRPH_Y_END + offset;
153
154 regs->modeDesktopHeight = AVIVO_D1MODE_DESKTOP_HEIGHT + offset;
155 regs->modeDataFormat = AVIVO_D1MODE_DATA_FORMAT + offset;
156 regs->viewportStart = AVIVO_D1MODE_VIEWPORT_START + offset;
157 regs->viewportSize = AVIVO_D1MODE_VIEWPORT_SIZE + offset;
158
159 } else if (info.chipsetID >= RADEON_RS600) {
160 // Avivo+
161 uint32 offset = 0;
162
163 switch (crtcID) {
164 case 0:
165 offset = R600_CRTC0_REGISTER_OFFSET;
166 regs->vgaControl = AVIVO_D1VGA_CONTROL;
167 break;
168 case 1:
169 offset = R600_CRTC1_REGISTER_OFFSET;
170 regs->vgaControl = AVIVO_D2VGA_CONTROL;
171 break;
172 default:
173 ERROR("%s: Unknown CRTC %" B_PRIu32 "\n",
174 __func__, crtcID);
175 return B_ERROR;
176 }
177
178 regs->crtcOffset = offset;
179
180 regs->grphEnable = AVIVO_D1GRPH_ENABLE + offset;
181 regs->grphControl = AVIVO_D1GRPH_CONTROL + offset;
182 regs->grphSwapControl = AVIVO_D1GRPH_SWAP_CNTL + offset;
183
184 regs->grphPrimarySurfaceAddr
185 = AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + offset;
186 regs->grphSecondarySurfaceAddr
187 = AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + offset;
188
189 // Surface Address high only used on r700 and higher
190 regs->grphPrimarySurfaceAddrHigh = 0xDEAD;
191 regs->grphSecondarySurfaceAddrHigh = 0xDEAD;
192
193 regs->grphPitch = AVIVO_D1GRPH_PITCH + offset;
194 regs->grphSurfaceOffsetX = AVIVO_D1GRPH_SURFACE_OFFSET_X + offset;
195 regs->grphSurfaceOffsetY = AVIVO_D1GRPH_SURFACE_OFFSET_Y + offset;
196 regs->grphXStart = AVIVO_D1GRPH_X_START + offset;
197 regs->grphYStart = AVIVO_D1GRPH_Y_START + offset;
198 regs->grphXEnd = AVIVO_D1GRPH_X_END + offset;
199 regs->grphYEnd = AVIVO_D1GRPH_Y_END + offset;
200
201 regs->modeDesktopHeight = AVIVO_D1MODE_DESKTOP_HEIGHT + offset;
202 regs->modeDataFormat = AVIVO_D1MODE_DATA_FORMAT + offset;
203 regs->viewportStart = AVIVO_D1MODE_VIEWPORT_START + offset;
204 regs->viewportSize = AVIVO_D1MODE_VIEWPORT_SIZE + offset;
205 } else {
206 // this really shouldn't happen unless a driver PCIID chipset is wrong
207 TRACE("%s, unknown Radeon chipset: %s\n", __func__,
208 info.chipsetName);
209 return B_ERROR;
210 }
211
212 TRACE("%s, registers for ATI chipset %s crt #%d loaded\n", __func__,
213 info.chipsetName, crtcID);
214
215 return B_OK;
216 }
217
218
219 status_t
detect_crt_ranges(uint32 crtid)220 detect_crt_ranges(uint32 crtid)
221 {
222 edid1_info* edid = &gDisplay[crtid]->edidData;
223
224 // Scan each display EDID description for monitor ranges
225 for (uint32 index = 0; index < EDID1_NUM_DETAILED_MONITOR_DESC; index++) {
226
227 edid1_detailed_monitor* monitor
228 = &edid->detailed_monitor[index];
229
230 if (monitor->monitor_desc_type == EDID1_MONITOR_RANGES) {
231 edid1_monitor_range range = monitor->data.monitor_range;
232 gDisplay[crtid]->vfreqMin = range.min_v; /* in Hz */
233 gDisplay[crtid]->vfreqMax = range.max_v;
234 gDisplay[crtid]->hfreqMin = range.min_h; /* in kHz */
235 gDisplay[crtid]->hfreqMax = range.max_h;
236 return B_OK;
237 }
238 }
239
240 return B_ERROR;
241 }
242
243
244 status_t
detect_displays()245 detect_displays()
246 {
247 // reset known displays
248 for (uint32 id = 0; id < MAX_DISPLAY; id++) {
249 gDisplay[id]->attached = false;
250 gDisplay[id]->powered = false;
251 gDisplay[id]->foundRanges = false;
252 }
253
254 uint32 displayIndex = 0;
255 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
256 if (gConnector[id]->valid == false)
257 continue;
258 if (displayIndex >= MAX_DISPLAY)
259 continue;
260
261 if (gConnector[id]->type == VIDEO_CONNECTOR_9DIN) {
262 TRACE("%s: connector(%" B_PRIu32 "): Skipping 9DIN connector "
263 "(not yet supported)\n", __func__, id);
264 continue;
265 }
266
267 if (gConnector[id]->type == VIDEO_CONNECTOR_DP
268 || gConnector[id]->type == VIDEO_CONNECTOR_EDP) {
269 TRACE("%s: connector(%" B_PRIu32 "): Checking %sDP.\n", __func__, id,
270 gConnector[id]->type == VIDEO_CONNECTOR_EDP ? "e" : "");
271
272 if (gConnector[id]->encoderExternal.valid == true) {
273 // If this has a valid external encoder (dp bridge)
274 // normally TRAVIS (LVDS) or NUTMEG (VGA)
275 TRACE("%s: external encoder, performing bridge DDC setup\n",
276 __func__);
277 encoder_external_setup(id,
278 EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
279 }
280 edid1_info* edid = &gDisplay[displayIndex]->edidData;
281 gDisplay[displayIndex]->attached
282 = ddc2_dp_read_edid1(id, edid);
283
284 // TODO: DDC Router switching for DisplayPort (and others?)
285
286 if (gDisplay[displayIndex]->attached) {
287 TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n",
288 __func__, id);
289 gInfo->shared_info->has_edid = true;
290 edid_dump(edid);
291 }
292 }
293
294
295 if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
296 display_mode preferredMode;
297 bool lvdsInfoFound = connector_read_mode_lvds(id,
298 &preferredMode);
299 TRACE("%s: connector(%" B_PRIu32 "): bit-banging LVDS for EDID.\n",
300 __func__, id);
301
302 gDisplay[displayIndex]->attached = connector_read_edid(id,
303 &gDisplay[displayIndex]->edidData);
304
305 if (!gDisplay[displayIndex]->attached && lvdsInfoFound) {
306 // If we didn't find ddc edid data, fallback to lvdsInfo
307 // We have to call connector_read_mode_lvds first to
308 // collect SS data for the lvds connector
309 TRACE("%s: connector(%" B_PRIu32 "): using AtomBIOS LVDS_Info "
310 "preferred mode\n", __func__, id);
311 gDisplay[displayIndex]->attached = true;
312 memcpy(&gDisplay[displayIndex]->preferredMode,
313 &preferredMode, sizeof(display_mode));
314 }
315 }
316
317 // If no display found yet, try more standard detection methods
318 if (gDisplay[displayIndex]->attached == false) {
319 TRACE("%s: connector(%" B_PRIu32 "): bit-banging ddc for EDID.\n",
320 __func__, id);
321
322 // Bit-bang edid from connector
323 gDisplay[displayIndex]->attached = connector_read_edid(id,
324 &gDisplay[displayIndex]->edidData);
325
326 // Found EDID data?
327 if (gDisplay[displayIndex]->attached) {
328 TRACE("%s: connector(%" B_PRIu32 "): found EDID data.\n",
329 __func__, id);
330
331 if (gConnector[id]->type == VIDEO_CONNECTOR_DVII
332 || gConnector[id]->type == VIDEO_CONNECTOR_HDMIB) {
333 // These connectors can share gpio pins for data
334 // communication between digital and analog encoders
335 // (DVI-I is most common)
336 edid1_info* edid = &gDisplay[displayIndex]->edidData;
337
338 bool analogEncoder
339 = gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC
340 || gConnector[id]->encoder.type == VIDEO_ENCODER_DAC;
341 bool digitalEncoder
342 = gConnector[id]->encoder.type == VIDEO_ENCODER_TMDS;
343
344 bool digitalEdid = edid->display.input_type ? true : false;
345
346 if (digitalEdid && analogEncoder) {
347 // Digital EDID + analog encoder? Lets try a load test
348 gDisplay[displayIndex]->attached
349 = encoder_analog_load_detect(id);
350 } else if (!digitalEdid && digitalEncoder) {
351 // non-digital EDID + digital encoder? Nope.
352 gDisplay[displayIndex]->attached = false;
353 }
354
355 // Else... everything aligns as it should and attached = 1
356 }
357 }
358 }
359
360 if (gDisplay[displayIndex]->attached != true) {
361 // Nothing interesting here, move along
362 continue;
363 }
364
365 // We found a valid / attached display
366
367 gDisplay[displayIndex]->connectorIndex = id;
368 // Populate physical connector index from gConnector
369
370 init_registers(gDisplay[displayIndex]->regs, displayIndex);
371
372 if (gDisplay[displayIndex]->preferredMode.virtual_width > 0) {
373 // Found a single preferred mode
374 gDisplay[displayIndex]->foundRanges = false;
375 } else {
376 // Use edid data and pull ranges
377 if (detect_crt_ranges(displayIndex) == B_OK)
378 gDisplay[displayIndex]->foundRanges = true;
379 }
380
381 displayIndex++;
382 }
383
384 // fail if no attached monitors were found
385 if (displayIndex == 0) {
386 // TODO: In the future we might want to accept this condition.. however
387 // without monitor hot plugging, we're most likely going to fail to bring
388 // up a display here.
389 ERROR("%s: ERROR: 0 attached monitors were found on display connectors.\n",
390 __func__);
391 return B_ERROR;
392 }
393
394 // Initial boot state is the first two crtc's powered
395 if (gDisplay[0]->attached == true)
396 gDisplay[0]->powered = true;
397 if (gDisplay[1]->attached == true)
398 gDisplay[1]->powered = true;
399
400 return B_OK;
401 }
402
403
404 void
debug_displays()405 debug_displays()
406 {
407 TRACE("Currently detected monitors===============\n");
408 for (uint32 id = 0; id < MAX_DISPLAY; id++) {
409 ERROR("Display #%" B_PRIu32 " attached = %s\n",
410 id, gDisplay[id]->attached ? "true" : "false");
411
412 uint32 connectorIndex = gDisplay[id]->connectorIndex;
413
414 if (gDisplay[id]->attached) {
415 uint32 connectorType = gConnector[connectorIndex]->type;
416 uint32 encoderType = gConnector[connectorIndex]->encoder.type;
417 ERROR(" + connector ID: %" B_PRIu32 "\n", connectorIndex);
418 ERROR(" + connector type: %s\n", get_connector_name(connectorType));
419 ERROR(" + encoder type: %s\n", get_encoder_name(encoderType));
420 ERROR(" + limits: Vert Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n",
421 gDisplay[id]->vfreqMin, gDisplay[id]->vfreqMax);
422 ERROR(" + limits: Horz Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n",
423 gDisplay[id]->hfreqMin, gDisplay[id]->hfreqMax);
424 }
425 }
426 TRACE("==========================================\n");
427 }
428
429
430 uint32
display_get_encoder_mode(uint32 connectorIndex)431 display_get_encoder_mode(uint32 connectorIndex)
432 {
433 // Is external DisplayPort Bridge?
434 if (gConnector[connectorIndex]->encoderExternal.valid == true
435 && gConnector[connectorIndex]->encoderExternal.isDPBridge == true) {
436 return ATOM_ENCODER_MODE_DP;
437 }
438
439 // DVO Encoders (should be bridges)
440 switch (gConnector[connectorIndex]->encoder.objectID) {
441 case ENCODER_OBJECT_ID_INTERNAL_DVO1:
442 case ENCODER_OBJECT_ID_INTERNAL_DDI:
443 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
444 return ATOM_ENCODER_MODE_DVO;
445 }
446
447 // Find display for connector so we can identify source of edid data
448 int32 crtcID = -1;
449 for (int32 id = 0; id < MAX_DISPLAY; id++) {
450 if (gDisplay[id]->connectorIndex == connectorIndex) {
451 crtcID = id;
452 break;
453 }
454 }
455 bool edidDigital = false;
456 if (crtcID == -1) {
457 ERROR("%s: BUG: executed on connector without assigned display!\n",
458 __func__);
459 } else {
460 edid1_info* edid = &gDisplay[crtcID]->edidData;
461 edidDigital = edid->display.input_type ? true : false;
462 }
463
464 // Normal encoder situations
465 switch (gConnector[connectorIndex]->type) {
466 case VIDEO_CONNECTOR_DVII:
467 case VIDEO_CONNECTOR_HDMIB: /* HDMI-B is DL-DVI; analog works fine */
468 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI
469 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI
470 if (edidDigital)
471 return ATOM_ENCODER_MODE_DVI;
472 else
473 return ATOM_ENCODER_MODE_CRT;
474 break;
475 case VIDEO_CONNECTOR_DVID:
476 case VIDEO_CONNECTOR_HDMIA:
477 default:
478 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI
479 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI
480 return ATOM_ENCODER_MODE_DVI;
481 case VIDEO_CONNECTOR_LVDS:
482 return ATOM_ENCODER_MODE_LVDS;
483 case VIDEO_CONNECTOR_DP:
484 // dig_connector = radeon_connector->con_priv;
485 // if ((dig_connector->dp_sink_type
486 // == CONNECTOR_OBJECT_ID_DISPLAYPORT)
487 // || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
488 // return ATOM_ENCODER_MODE_DP;
489 // }
490 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI
491 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI
492 return ATOM_ENCODER_MODE_DP;
493 case VIDEO_CONNECTOR_EDP:
494 return ATOM_ENCODER_MODE_DP;
495 case VIDEO_CONNECTOR_DVIA:
496 case VIDEO_CONNECTOR_VGA:
497 return ATOM_ENCODER_MODE_CRT;
498 case VIDEO_CONNECTOR_COMPOSITE:
499 case VIDEO_CONNECTOR_SVIDEO:
500 case VIDEO_CONNECTOR_9DIN:
501 return ATOM_ENCODER_MODE_TV;
502 }
503 }
504
505
506 void
display_crtc_lock(uint8 crtcID,int command)507 display_crtc_lock(uint8 crtcID, int command)
508 {
509 TRACE("%s\n", __func__);
510
511 ENABLE_CRTC_PS_ALLOCATION args;
512 int index
513 = GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
514
515 memset(&args, 0, sizeof(args));
516
517 args.ucCRTC = crtcID;
518 args.ucEnable = command;
519
520 atom_execute_table(gAtomContext, index, (uint32*)&args);
521 }
522
523
524 void
display_crtc_blank(uint8 crtcID,int command)525 display_crtc_blank(uint8 crtcID, int command)
526 {
527 TRACE("%s\n", __func__);
528
529 BLANK_CRTC_PS_ALLOCATION args;
530 int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
531
532 memset(&args, 0, sizeof(args));
533
534 args.ucCRTC = crtcID;
535 args.ucBlanking = command;
536
537 args.usBlackColorRCr = 0;
538 args.usBlackColorGY = 0;
539 args.usBlackColorBCb = 0;
540
541 atom_execute_table(gAtomContext, index, (uint32*)&args);
542 }
543
544
545 void
display_crtc_scale(uint8 crtcID,display_mode * mode)546 display_crtc_scale(uint8 crtcID, display_mode* mode)
547 {
548 TRACE("%s\n", __func__);
549 ENABLE_SCALER_PS_ALLOCATION args;
550 int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
551
552 memset(&args, 0, sizeof(args));
553
554 args.ucScaler = crtcID;
555 args.ucEnable = ATOM_SCALER_DISABLE;
556
557 atom_execute_table(gAtomContext, index, (uint32*)&args);
558 }
559
560
561 void
display_crtc_dpms(uint8 crtcID,int mode)562 display_crtc_dpms(uint8 crtcID, int mode)
563 {
564 radeon_shared_info &info = *gInfo->shared_info;
565
566 switch (mode) {
567 case B_DPMS_ON:
568 TRACE("%s: crtc %" B_PRIu8 " dpms powerup\n", __func__, crtcID);
569 if (gDisplay[crtcID]->attached == false)
570 return;
571 display_crtc_power(crtcID, ATOM_ENABLE);
572 gDisplay[crtcID]->powered = true;
573 if (info.dceMajor >= 3 && info.dceMajor < 6)
574 display_crtc_memreq(crtcID, ATOM_ENABLE);
575 display_crtc_blank(crtcID, ATOM_BLANKING_OFF);
576 break;
577 case B_DPMS_STAND_BY:
578 case B_DPMS_SUSPEND:
579 case B_DPMS_OFF:
580 TRACE("%s: crtc %" B_PRIu8 " dpms powerdown\n", __func__, crtcID);
581 if (gDisplay[crtcID]->attached == false)
582 return;
583 if (gDisplay[crtcID]->powered == true)
584 display_crtc_blank(crtcID, ATOM_BLANKING);
585 if (info.dceMajor >= 3 && info.dceMajor < 6)
586 display_crtc_memreq(crtcID, ATOM_DISABLE);
587 display_crtc_power(crtcID, ATOM_DISABLE);
588 gDisplay[crtcID]->powered = false;
589 }
590 }
591
592
593 void
display_dce45_crtc_load_lut(uint8 crtcID)594 display_dce45_crtc_load_lut(uint8 crtcID)
595 {
596 radeon_shared_info &info = *gInfo->shared_info;
597 register_info* regs = gDisplay[crtcID]->regs;
598
599 TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID);
600
601 uint16* r = info.color_data;
602 uint16* g = r + 256;
603 uint16* b = r + 512;
604
605 if (info.dceMajor >= 5) {
606 Write32(OUT, NI_INPUT_CSC_CONTROL + regs->crtcOffset,
607 NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS)
608 | NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS));
609 Write32(OUT, NI_PRESCALE_GRPH_CONTROL + regs->crtcOffset,
610 NI_GRPH_PRESCALE_BYPASS);
611 Write32(OUT, NI_PRESCALE_OVL_CONTROL + regs->crtcOffset,
612 NI_OVL_PRESCALE_BYPASS);
613 Write32(OUT, NI_INPUT_GAMMA_CONTROL + regs->crtcOffset,
614 NI_GRPH_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT) |
615 NI_OVL_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT));
616 }
617
618 Write32(OUT, EVERGREEN_DC_LUT_CONTROL + regs->crtcOffset, 0);
619
620 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + regs->crtcOffset, 0);
621 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + regs->crtcOffset, 0);
622 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_RED + regs->crtcOffset, 0);
623
624 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff);
625 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff);
626 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff);
627
628 Write32(OUT, EVERGREEN_DC_LUT_RW_MODE, 0);
629 Write32(OUT, EVERGREEN_DC_LUT_WRITE_EN_MASK, 0x00000007);
630
631 Write32(OUT, EVERGREEN_DC_LUT_RW_INDEX, 0);
632 for (int i = 0; i < 256; i++) {
633 Write32(OUT, EVERGREEN_DC_LUT_30_COLOR + regs->crtcOffset,
634 (r[i] << 20) | (g[i] << 10) | (b[i] << 0));
635 }
636
637 if (info.dceMajor >= 5) {
638 Write32(OUT, NI_DEGAMMA_CONTROL + regs->crtcOffset,
639 (NI_GRPH_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)
640 | NI_OVL_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)
641 | NI_ICON_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)
642 | NI_CURSOR_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)));
643 Write32(OUT, NI_GAMUT_REMAP_CONTROL + regs->crtcOffset,
644 (NI_GRPH_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS) |
645 NI_OVL_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS)));
646 Write32(OUT, NI_REGAMMA_CONTROL + regs->crtcOffset,
647 (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) |
648 NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS)));
649 Write32(OUT, NI_OUTPUT_CSC_CONTROL + regs->crtcOffset,
650 (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) |
651 NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
652 /* XXX match this to the depth of the crtc fmt block, move to modeset? */
653 Write32(OUT, 0x6940 + regs->crtcOffset, 0);
654 }
655 }
656
657
658 void
display_avivo_crtc_load_lut(uint8 crtcID)659 display_avivo_crtc_load_lut(uint8 crtcID)
660 {
661 radeon_shared_info &info = *gInfo->shared_info;
662 register_info* regs = gDisplay[crtcID]->regs;
663
664 TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID);
665
666 uint16* r = info.color_data;
667 uint16* g = r + 256;
668 uint16* b = r + 512;
669
670 Write32(OUT, AVIVO_DC_LUTA_CONTROL + regs->crtcOffset, 0);
671
672 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + regs->crtcOffset, 0);
673 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + regs->crtcOffset, 0);
674 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_RED + regs->crtcOffset, 0);
675
676 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff);
677 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff);
678 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff);
679
680 Write32(OUT, AVIVO_DC_LUT_RW_SELECT, crtcID);
681 Write32(OUT, AVIVO_DC_LUT_RW_MODE, 0);
682 Write32(OUT, AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f);
683
684 Write32(OUT, AVIVO_DC_LUT_RW_INDEX, 0);
685 for (int i = 0; i < 256; i++) {
686 Write32(OUT, AVIVO_DC_LUT_30_COLOR,
687 (r[i] << 20) | (g[i] << 10) | (b[i] << 0));
688 }
689
690 Write32(OUT, AVIVO_D1GRPH_LUT_SEL + regs->crtcOffset, crtcID);
691 }
692
693
694 void
display_crtc_fb_set(uint8 crtcID,display_mode * mode)695 display_crtc_fb_set(uint8 crtcID, display_mode* mode)
696 {
697 radeon_shared_info &info = *gInfo->shared_info;
698 register_info* regs = gDisplay[crtcID]->regs;
699
700 uint16* r = info.color_data;
701 uint16* g = r + 256;
702 uint16* b = r + 512;
703
704 uint32 fbSwap;
705 if (info.dceMajor >= 4)
706 fbSwap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
707 else
708 fbSwap = R600_D1GRPH_SWAP_ENDIAN_NONE;
709
710 uint32 fbFormat;
711
712 uint32 bytesPerPixel;
713 uint32 bitsPerPixel;
714
715 switch (mode->space) {
716 case B_CMAP8:
717 bytesPerPixel = 1;
718 bitsPerPixel = 8;
719 if (info.dceMajor >= 4) {
720 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP)
721 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
722 } else {
723 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_8BPP
724 | AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;
725 }
726 // TODO: copy system color map into shared info
727 break;
728 case B_RGB15_LITTLE:
729 bytesPerPixel = 2;
730 bitsPerPixel = 15;
731 if (info.dceMajor >= 4) {
732 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP)
733 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555));
734 } else {
735 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP
736 | AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
737 }
738 break;
739 case B_RGB16_LITTLE:
740 bytesPerPixel = 2;
741 bitsPerPixel = 16;
742
743 if (info.dceMajor >= 4) {
744 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP)
745 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
746 #ifdef __POWERPC__
747 fbSwap
748 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
749 #endif
750 } else {
751 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP
752 | AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
753 #ifdef __POWERPC__
754 fbSwap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
755 #endif
756 }
757
758 {
759 // default gamma table
760 uint16 gamma = 0;
761 for (int i = 0; i < 256; i++) {
762 r[i] = gamma;
763 g[i] = gamma;
764 b[i] = gamma;
765 gamma += 4;
766 }
767 }
768 break;
769 case B_RGB24_LITTLE:
770 case B_RGB32_LITTLE:
771 default:
772 bytesPerPixel = 4;
773 bitsPerPixel = 32;
774 if (info.dceMajor >= 4) {
775 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP)
776 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
777 #ifdef __POWERPC__
778 fbSwap
779 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
780 #endif
781 } else {
782 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_32BPP
783 | AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
784 #ifdef __POWERPC__
785 fbSwap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
786 #endif
787 }
788
789 {
790 // default gamma table
791 uint16 gamma = 0;
792 for (int i = 0; i < 256; i++) {
793 r[i] = gamma;
794 g[i] = gamma;
795 b[i] = gamma;
796 gamma += 4;
797 }
798 }
799 break;
800 }
801
802 Write32(OUT, regs->vgaControl, 0);
803
804 uint64 fbAddress = gInfo->fb.vramStart;
805
806 TRACE("%s: Framebuffer at: 0x%" B_PRIX64 "\n", __func__, fbAddress);
807
808 if (info.chipsetID >= RADEON_RV770) {
809 TRACE("%s: Set SurfaceAddress High: 0x%" B_PRIX32 "\n",
810 __func__, (fbAddress >> 32) & 0xf);
811
812 Write32(OUT, regs->grphPrimarySurfaceAddrHigh,
813 (fbAddress >> 32) & 0xf);
814 Write32(OUT, regs->grphSecondarySurfaceAddrHigh,
815 (fbAddress >> 32) & 0xf);
816 }
817
818 TRACE("%s: Set SurfaceAddress: 0x%" B_PRIX64 "\n",
819 __func__, (fbAddress & 0xFFFFFFFF));
820
821 Write32(OUT, regs->grphPrimarySurfaceAddr, (fbAddress & 0xFFFFFFFF));
822 Write32(OUT, regs->grphSecondarySurfaceAddr, (fbAddress & 0xFFFFFFFF));
823
824 if (info.chipsetID >= RADEON_R600) {
825 Write32(CRT, regs->grphControl, fbFormat);
826 Write32(CRT, regs->grphSwapControl, fbSwap);
827 }
828
829 // TODO: Technically if chip >= RS600
830 int largeAlign = (info.dceMajor >= 2) ? 1 : 0;
831
832 // Align our framebuffer width
833 uint32 widthAligned = mode->virtual_width;
834 uint32 pitchMask = 0;
835
836 switch (bytesPerPixel) {
837 case 1:
838 pitchMask = largeAlign ? 255 : 127;
839 break;
840 case 2:
841 pitchMask = largeAlign ? 127 : 31;
842 break;
843 case 3:
844 case 4:
845 pitchMask = largeAlign ? 63 : 15;
846 break;
847 }
848 widthAligned += pitchMask;
849 widthAligned &= ~pitchMask;
850
851 TRACE("%s: fb: %" B_PRIu32 "x%" B_PRIu32 " (%" B_PRIu32 " bpp)\n", __func__,
852 mode->timing.h_display, mode->timing.v_display, bitsPerPixel);
853 TRACE("%s: fb pitch: %" B_PRIu32 " \n", __func__, widthAligned);
854
855 Write32(CRT, regs->grphSurfaceOffsetX, 0);
856 Write32(CRT, regs->grphSurfaceOffsetY, 0);
857 Write32(CRT, regs->grphXStart, 0);
858 Write32(CRT, regs->grphYStart, 0);
859 Write32(CRT, regs->grphXEnd, mode->virtual_width);
860 Write32(CRT, regs->grphYEnd, mode->virtual_height);
861 Write32(CRT, regs->grphPitch, widthAligned);
862
863 Write32(CRT, regs->grphEnable, 1);
864 // Enable Frame buffer
865
866 Write32(CRT, regs->modeDesktopHeight, mode->virtual_height);
867
868 uint32 viewportWidth = mode->timing.h_display;
869 uint32 viewportHeight = (mode->timing.v_display + 1) & ~1;
870
871 Write32(CRT, regs->viewportStart, 0);
872 Write32(CRT, regs->viewportSize,
873 (viewportWidth << 16) | viewportHeight);
874
875 // Pageflip setup
876 if (info.dceMajor >= 4) {
877 uint32 tmp
878 = Read32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset);
879 tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN;
880 Write32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset, tmp);
881
882 Write32(OUT, EVERGREEN_MASTER_UPDATE_MODE + regs->crtcOffset, 0);
883 // Pageflip to happen anywhere in vblank
884 display_dce45_crtc_load_lut(crtcID);
885 } else {
886 uint32 tmp = Read32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset);
887 tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN;
888 Write32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset, tmp);
889
890 Write32(OUT, AVIVO_D1MODE_MASTER_UPDATE_MODE + regs->crtcOffset, 0);
891 // Pageflip to happen anywhere in vblank
892 display_avivo_crtc_load_lut(crtcID);
893 }
894
895 // update shared info
896 gInfo->shared_info->bytes_per_row = widthAligned * bytesPerPixel;
897 gInfo->shared_info->current_mode = *mode;
898 gInfo->shared_info->bits_per_pixel = bitsPerPixel;
899 }
900
901
902 void
display_crtc_set(uint8 crtcID,display_mode * mode)903 display_crtc_set(uint8 crtcID, display_mode* mode)
904 {
905 display_timing& displayTiming = mode->timing;
906
907 TRACE("%s called to do %dx%d\n",
908 __func__, displayTiming.h_display, displayTiming.v_display);
909
910 SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args;
911 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
912 uint16 misc = 0;
913
914 memset(&args, 0, sizeof(args));
915
916 args.usH_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.h_total);
917 args.usH_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display);
918 args.usH_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start);
919 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end
920 - displayTiming.h_sync_start);
921
922 args.usV_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.v_total);
923 args.usV_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display);
924 args.usV_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start);
925 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end
926 - displayTiming.v_sync_start);
927
928 args.ucOverscanRight = 0;
929 args.ucOverscanLeft = 0;
930 args.ucOverscanBottom = 0;
931 args.ucOverscanTop = 0;
932
933 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0)
934 misc |= ATOM_HSYNC_POLARITY;
935 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0)
936 misc |= ATOM_VSYNC_POLARITY;
937
938 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc);
939 args.ucCRTC = crtcID;
940
941 atom_execute_table(gAtomContext, index, (uint32*)&args);
942 }
943
944
945 void
display_crtc_set_dtd(uint8 crtcID,display_mode * mode)946 display_crtc_set_dtd(uint8 crtcID, display_mode* mode)
947 {
948 display_timing& displayTiming = mode->timing;
949
950 TRACE("%s called to do %dx%d\n", __func__,
951 displayTiming.h_display, displayTiming.v_display);
952
953 SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
954 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
955 uint16 misc = 0;
956
957 memset(&args, 0, sizeof(args));
958
959 // Note: the code below assumes H & V borders are both zero
960 uint16 blankStart
961 = MIN(displayTiming.h_sync_start, displayTiming.h_display);
962 uint16 blankEnd
963 = MAX(displayTiming.h_sync_end, displayTiming.h_total);
964 args.usH_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display);
965 args.usH_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart);
966
967 blankStart = MIN(displayTiming.v_sync_start, displayTiming.v_display);
968 blankEnd = MAX(displayTiming.v_sync_end, displayTiming.v_total);
969 args.usV_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display);
970 args.usV_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart);
971
972 args.usH_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start
973 - displayTiming.h_display);
974 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end
975 - displayTiming.h_sync_start);
976
977 args.usV_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start
978 - displayTiming.v_display);
979 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end
980 - displayTiming.v_sync_start);
981
982 args.ucH_Border = 0;
983 args.ucV_Border = 0;
984
985 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0)
986 misc |= ATOM_HSYNC_POLARITY;
987 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0)
988 misc |= ATOM_VSYNC_POLARITY;
989
990 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc);
991 args.ucCRTC = crtcID;
992
993 atom_execute_table(gAtomContext, index, (uint32*)&args);
994 }
995
996
997 void
display_crtc_ss(pll_info * pll,int command)998 display_crtc_ss(pll_info* pll, int command)
999 {
1000 TRACE("%s\n", __func__);
1001 radeon_shared_info &info = *gInfo->shared_info;
1002
1003 if (command == ATOM_ENABLE) {
1004 if (pll->ssPercentage == 0) {
1005 TRACE("%s: ssPercentage 0, ignoring SS request\n", __func__);
1006 return;
1007 }
1008 if ((pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0) {
1009 TRACE("%s: external SS, ignoring SS request\n", __func__);
1010 return;
1011 }
1012 } else {
1013 if (pll_usage_count(pll->id) > 1) {
1014 // TODO: Check if PLL has SS enabled on any other displays, if so
1015 // we need to also skip this function.
1016 TRACE("%s: TODO: shared PLL detected!\n", __func__);
1017 }
1018 }
1019
1020 int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
1021
1022 union enableSS {
1023 ENABLE_LVDS_SS_PARAMETERS lvds_ss;
1024 ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2;
1025 ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
1026 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
1027 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
1028 };
1029
1030 union enableSS args;
1031 memset(&args, 0, sizeof(args));
1032
1033 if (info.dceMajor >= 5) {
1034 args.v3.usSpreadSpectrumAmountFrac = B_HOST_TO_LENDIAN_INT16(0);
1035 args.v3.ucSpreadSpectrumType
1036 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
1037 switch (pll->id) {
1038 case ATOM_PPLL1:
1039 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
1040 break;
1041 case ATOM_PPLL2:
1042 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
1043 break;
1044 case ATOM_DCPLL:
1045 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
1046 break;
1047 case ATOM_PPLL_INVALID:
1048 return;
1049 default:
1050 ERROR("%s: BUG: Invalid PLL ID!\n", __func__);
1051 return;
1052 }
1053 args.v3.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(pll->ssAmount);
1054 args.v3.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(pll->ssStep);
1055 args.v3.ucEnable = command;
1056 } else if (info.dceMajor >= 4) {
1057 args.v2.usSpreadSpectrumPercentage
1058 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage);
1059 args.v2.ucSpreadSpectrumType
1060 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
1061 switch (pll->id) {
1062 case ATOM_PPLL1:
1063 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
1064 break;
1065 case ATOM_PPLL2:
1066 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
1067 break;
1068 case ATOM_DCPLL:
1069 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
1070 break;
1071 case ATOM_PPLL_INVALID:
1072 return;
1073 default:
1074 ERROR("%s: BUG: Invalid PLL ID!\n", __func__);
1075 return;
1076 }
1077 args.v2.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(pll->ssAmount);
1078 args.v2.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(pll->ssStep);
1079 args.v2.ucEnable = command;
1080 } else if (info.dceMajor >= 3) {
1081 args.v1.usSpreadSpectrumPercentage
1082 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage);
1083 args.v1.ucSpreadSpectrumType
1084 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
1085 args.v1.ucSpreadSpectrumStep = pll->ssStep;
1086 args.v1.ucSpreadSpectrumDelay = pll->ssDelay;
1087 args.v1.ucSpreadSpectrumRange = pll->ssRange;
1088 args.v1.ucPpll = pll->id;
1089 args.v1.ucEnable = command;
1090 } else if (info.dceMajor >= 2) {
1091 if (command == ATOM_DISABLE) {
1092 radeon_gpu_ss_control(pll, false);
1093 return;
1094 }
1095 args.lvds_ss_2.usSpreadSpectrumPercentage
1096 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage);
1097 args.lvds_ss_2.ucSpreadSpectrumType
1098 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
1099 args.lvds_ss_2.ucSpreadSpectrumStep = pll->ssStep;
1100 args.lvds_ss_2.ucSpreadSpectrumDelay = pll->ssDelay;
1101 args.lvds_ss_2.ucSpreadSpectrumRange = pll->ssRange;
1102 args.lvds_ss_2.ucEnable = command;
1103 } else {
1104 ERROR("%s: TODO: Old card SS control\n", __func__);
1105 return;
1106 }
1107
1108 atom_execute_table(gAtomContext, index, (uint32*)&args);
1109 }
1110
1111
1112 void
display_crtc_power(uint8 crtcID,int command)1113 display_crtc_power(uint8 crtcID, int command)
1114 {
1115 TRACE("%s\n", __func__);
1116 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
1117 ENABLE_CRTC_PS_ALLOCATION args;
1118
1119 memset(&args, 0, sizeof(args));
1120
1121 args.ucCRTC = crtcID;
1122 args.ucEnable = command;
1123
1124 atom_execute_table(gAtomContext, index, (uint32*)&args);
1125 }
1126
1127
1128 void
display_crtc_memreq(uint8 crtcID,int command)1129 display_crtc_memreq(uint8 crtcID, int command)
1130 {
1131 TRACE("%s\n", __func__);
1132 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq);
1133 ENABLE_CRTC_PS_ALLOCATION args;
1134
1135 memset(&args, 0, sizeof(args));
1136
1137 args.ucCRTC = crtcID;
1138 args.ucEnable = command;
1139
1140 atom_execute_table(gAtomContext, index, (uint32*)&args);
1141 }
1142