vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / radeon_hd / display.cpp
blob7dcfc29ce50fc95177da56fffa01b77e75cb4225
1 /*
2 * Copyright 2006-2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Alexander von Gluck, kallisti5@unixzen.com
7 * Bill Randle, billr@neocat.org
8 */
11 * It's dangerous to go alone, take this!
12 * framebuffer -> crtc -> encoder -> transmitter -> connector -> monitor
16 #include "display.h"
18 #include <stdlib.h>
19 #include <string.h>
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"
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
37 #define ERROR(x...) _sPrintf("radeon_hd: " x)
40 /*! Populate regs with device dependant register locations */
41 status_t
42 init_registers(register_info* regs, uint8 crtcID)
44 memset(regs, 0, sizeof(register_info));
46 radeon_shared_info &info = *gInfo->shared_info;
48 if (info.chipsetID >= RADEON_CEDAR) {
49 // Evergreen
50 uint32 offset = 0;
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;
83 regs->crtcOffset = offset;
85 regs->grphEnable = EVERGREEN_GRPH_ENABLE + offset;
86 regs->grphControl = EVERGREEN_GRPH_CONTROL + offset;
87 regs->grphSwapControl = EVERGREEN_GRPH_SWAP_CONTROL + offset;
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;
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;
112 } else if (info.chipsetID >= RADEON_RV770) {
113 // R700 series
114 uint32 offset = 0;
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;
135 regs->crtcOffset = offset;
137 regs->grphEnable = AVIVO_D1GRPH_ENABLE + offset;
138 regs->grphControl = AVIVO_D1GRPH_CONTROL + offset;
139 regs->grphSwapControl = AVIVO_D1GRPH_SWAP_CNTL + offset;
141 regs->grphPrimarySurfaceAddr
142 = R700_D1GRPH_PRIMARY_SURFACE_ADDRESS + offset;
143 regs->grphSecondarySurfaceAddr
144 = R700_D1GRPH_SECONDARY_SURFACE_ADDRESS + offset;
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;
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;
159 } else if (info.chipsetID >= RADEON_RS600) {
160 // Avivo+
161 uint32 offset = 0;
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;
178 regs->crtcOffset = offset;
180 regs->grphEnable = AVIVO_D1GRPH_ENABLE + offset;
181 regs->grphControl = AVIVO_D1GRPH_CONTROL + offset;
182 regs->grphSwapControl = AVIVO_D1GRPH_SWAP_CNTL + offset;
184 regs->grphPrimarySurfaceAddr
185 = AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + offset;
186 regs->grphSecondarySurfaceAddr
187 = AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + offset;
189 // Surface Address high only used on r700 and higher
190 regs->grphPrimarySurfaceAddrHigh = 0xDEAD;
191 regs->grphSecondarySurfaceAddrHigh = 0xDEAD;
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;
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;
212 TRACE("%s, registers for ATI chipset %s crt #%d loaded\n", __func__,
213 info.chipsetName, crtcID);
215 return B_OK;
219 status_t
220 detect_crt_ranges(uint32 crtid)
222 edid1_info* edid = &gDisplay[crtid]->edidData;
224 // Scan each display EDID description for monitor ranges
225 for (uint32 index = 0; index < EDID1_NUM_DETAILED_MONITOR_DESC; index++) {
227 edid1_detailed_monitor* monitor
228 = &edid->detailed_monitor[index];
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;
240 return B_ERROR;
244 status_t
245 detect_displays()
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;
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;
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;
267 if (gConnector[id]->type == VIDEO_CONNECTOR_DP) {
268 TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id);
270 if (gConnector[id]->encoderExternal.valid == true) {
271 // If this has a valid external encoder (dp bridge)
272 // normally TRAVIS (LVDS) or NUTMEG (VGA)
273 TRACE("%s: external encoder, performing bridge DDC setup\n",
274 __func__);
275 encoder_external_setup(id,
276 EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
278 edid1_info* edid = &gDisplay[displayIndex]->edidData;
279 gDisplay[displayIndex]->attached
280 = ddc2_dp_read_edid1(id, edid);
282 // TODO: DDC Router switching for DisplayPort (and others?)
284 if (gDisplay[displayIndex]->attached) {
285 TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n",
286 __func__, id);
291 if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) {
292 display_mode preferredMode;
293 bool lvdsInfoFound = connector_read_mode_lvds(id,
294 &preferredMode);
295 TRACE("%s: connector(%" B_PRIu32 "): bit-banging LVDS for EDID.\n",
296 __func__, id);
298 gDisplay[displayIndex]->attached = connector_read_edid(id,
299 &gDisplay[displayIndex]->edidData);
301 if (!gDisplay[displayIndex]->attached && lvdsInfoFound) {
302 // If we didn't find ddc edid data, fallback to lvdsInfo
303 // We have to call connector_read_mode_lvds first to
304 // collect SS data for the lvds connector
305 TRACE("%s: connector(%" B_PRIu32 "): using AtomBIOS LVDS_Info "
306 "preferred mode\n", __func__, id);
307 gDisplay[displayIndex]->attached = true;
308 memcpy(&gDisplay[displayIndex]->preferredMode,
309 &preferredMode, sizeof(display_mode));
313 // If no display found yet, try more standard detection methods
314 if (gDisplay[displayIndex]->attached == false) {
315 TRACE("%s: connector(%" B_PRIu32 "): bit-banging ddc for EDID.\n",
316 __func__, id);
318 // Bit-bang edid from connector
319 gDisplay[displayIndex]->attached = connector_read_edid(id,
320 &gDisplay[displayIndex]->edidData);
322 // Found EDID data?
323 if (gDisplay[displayIndex]->attached) {
324 TRACE("%s: connector(%" B_PRIu32 "): found EDID data.\n",
325 __func__, id);
327 if (gConnector[id]->type == VIDEO_CONNECTOR_DVII
328 || gConnector[id]->type == VIDEO_CONNECTOR_HDMIB) {
329 // These connectors can share gpio pins for data
330 // communication between digital and analog encoders
331 // (DVI-I is most common)
332 edid1_info* edid = &gDisplay[displayIndex]->edidData;
334 bool analogEncoder
335 = gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC
336 || gConnector[id]->encoder.type == VIDEO_ENCODER_DAC;
337 bool digitalEncoder
338 = gConnector[id]->encoder.type == VIDEO_ENCODER_TMDS;
340 bool digitalEdid = edid->display.input_type ? true : false;
342 if (digitalEdid && analogEncoder) {
343 // Digital EDID + analog encoder? Lets try a load test
344 gDisplay[displayIndex]->attached
345 = encoder_analog_load_detect(id);
346 } else if (!digitalEdid && digitalEncoder) {
347 // non-digital EDID + digital encoder? Nope.
348 gDisplay[displayIndex]->attached = false;
351 // Else... everything aligns as it should and attached = 1
356 if (gDisplay[displayIndex]->attached != true) {
357 // Nothing interesting here, move along
358 continue;
361 // We found a valid / attached display
363 gDisplay[displayIndex]->connectorIndex = id;
364 // Populate physical connector index from gConnector
366 init_registers(gDisplay[displayIndex]->regs, displayIndex);
368 if (gDisplay[displayIndex]->preferredMode.virtual_width > 0) {
369 // Found a single preferred mode
370 gDisplay[displayIndex]->foundRanges = false;
371 } else {
372 // Use edid data and pull ranges
373 if (detect_crt_ranges(displayIndex) == B_OK)
374 gDisplay[displayIndex]->foundRanges = true;
377 displayIndex++;
380 // fallback if no attached monitors were found
381 if (displayIndex == 0) {
382 // This is a hack, however as we don't support HPD just yet,
383 // it tries to prevent a "no displays" situation.
384 ERROR("%s: ERROR: 0 attached monitors were found on display connectors."
385 " Injecting first connector as a last resort.\n", __func__);
386 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
387 // skip TV DAC connectors as likely fallback isn't for TV
388 if (gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC)
389 continue;
390 gDisplay[0]->attached = true;
391 gDisplay[0]->connectorIndex = id;
392 init_registers(gDisplay[0]->regs, 0);
393 if (detect_crt_ranges(0) == B_OK)
394 gDisplay[0]->foundRanges = true;
395 break;
399 // Initial boot state is the first two crtc's powered
400 if (gDisplay[0]->attached == true)
401 gDisplay[0]->powered = true;
402 if (gDisplay[1]->attached == true)
403 gDisplay[1]->powered = true;
405 return B_OK;
409 void
410 debug_displays()
412 TRACE("Currently detected monitors===============\n");
413 for (uint32 id = 0; id < MAX_DISPLAY; id++) {
414 ERROR("Display #%" B_PRIu32 " attached = %s\n",
415 id, gDisplay[id]->attached ? "true" : "false");
417 uint32 connectorIndex = gDisplay[id]->connectorIndex;
419 if (gDisplay[id]->attached) {
420 uint32 connectorType = gConnector[connectorIndex]->type;
421 uint32 encoderType = gConnector[connectorIndex]->encoder.type;
422 ERROR(" + connector ID: %" B_PRIu32 "\n", connectorIndex);
423 ERROR(" + connector type: %s\n", get_connector_name(connectorType));
424 ERROR(" + encoder type: %s\n", get_encoder_name(encoderType));
425 ERROR(" + limits: Vert Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n",
426 gDisplay[id]->vfreqMin, gDisplay[id]->vfreqMax);
427 ERROR(" + limits: Horz Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n",
428 gDisplay[id]->hfreqMin, gDisplay[id]->hfreqMax);
431 TRACE("==========================================\n");
435 uint32
436 display_get_encoder_mode(uint32 connectorIndex)
438 // Is external DisplayPort Bridge?
439 if (gConnector[connectorIndex]->encoderExternal.valid == true
440 && gConnector[connectorIndex]->encoderExternal.isDPBridge == true) {
441 return ATOM_ENCODER_MODE_DP;
444 // DVO Encoders (should be bridges)
445 switch (gConnector[connectorIndex]->encoder.objectID) {
446 case ENCODER_OBJECT_ID_INTERNAL_DVO1:
447 case ENCODER_OBJECT_ID_INTERNAL_DDI:
448 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
449 return ATOM_ENCODER_MODE_DVO;
452 // Find display for connector so we can identify source of edid data
453 int32 crtcID = -1;
454 for (int32 id = 0; id < MAX_DISPLAY; id++) {
455 if (gDisplay[id]->connectorIndex == connectorIndex) {
456 crtcID = id;
457 break;
460 bool edidDigital = false;
461 if (crtcID == -1) {
462 ERROR("%s: BUG: executed on connector without assigned display!\n",
463 __func__);
464 } else {
465 edid1_info* edid = &gDisplay[crtcID]->edidData;
466 edidDigital = edid->display.input_type ? true : false;
469 // Normal encoder situations
470 switch (gConnector[connectorIndex]->type) {
471 case VIDEO_CONNECTOR_DVII:
472 case VIDEO_CONNECTOR_HDMIB: /* HDMI-B is DL-DVI; analog works fine */
473 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI
474 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI
475 if (edidDigital)
476 return ATOM_ENCODER_MODE_DVI;
477 else
478 return ATOM_ENCODER_MODE_CRT;
479 break;
480 case VIDEO_CONNECTOR_DVID:
481 case VIDEO_CONNECTOR_HDMIA:
482 default:
483 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI
484 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI
485 return ATOM_ENCODER_MODE_DVI;
486 case VIDEO_CONNECTOR_LVDS:
487 return ATOM_ENCODER_MODE_LVDS;
488 case VIDEO_CONNECTOR_DP:
489 // dig_connector = radeon_connector->con_priv;
490 // if ((dig_connector->dp_sink_type
491 // == CONNECTOR_OBJECT_ID_DISPLAYPORT)
492 // || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
493 // return ATOM_ENCODER_MODE_DP;
494 // }
495 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI
496 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI
497 return ATOM_ENCODER_MODE_DP;
498 case VIDEO_CONNECTOR_EDP:
499 return ATOM_ENCODER_MODE_DP;
500 case VIDEO_CONNECTOR_DVIA:
501 case VIDEO_CONNECTOR_VGA:
502 return ATOM_ENCODER_MODE_CRT;
503 case VIDEO_CONNECTOR_COMPOSITE:
504 case VIDEO_CONNECTOR_SVIDEO:
505 case VIDEO_CONNECTOR_9DIN:
506 return ATOM_ENCODER_MODE_TV;
511 void
512 display_crtc_lock(uint8 crtcID, int command)
514 TRACE("%s\n", __func__);
516 ENABLE_CRTC_PS_ALLOCATION args;
517 int index
518 = GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
520 memset(&args, 0, sizeof(args));
522 args.ucCRTC = crtcID;
523 args.ucEnable = command;
525 atom_execute_table(gAtomContext, index, (uint32*)&args);
529 void
530 display_crtc_blank(uint8 crtcID, int command)
532 TRACE("%s\n", __func__);
534 BLANK_CRTC_PS_ALLOCATION args;
535 int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
537 memset(&args, 0, sizeof(args));
539 args.ucCRTC = crtcID;
540 args.ucBlanking = command;
542 args.usBlackColorRCr = 0;
543 args.usBlackColorGY = 0;
544 args.usBlackColorBCb = 0;
546 atom_execute_table(gAtomContext, index, (uint32*)&args);
550 void
551 display_crtc_scale(uint8 crtcID, display_mode* mode)
553 TRACE("%s\n", __func__);
554 ENABLE_SCALER_PS_ALLOCATION args;
555 int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
557 memset(&args, 0, sizeof(args));
559 args.ucScaler = crtcID;
560 args.ucEnable = ATOM_SCALER_DISABLE;
562 atom_execute_table(gAtomContext, index, (uint32*)&args);
566 void
567 display_crtc_dpms(uint8 crtcID, int mode)
569 radeon_shared_info &info = *gInfo->shared_info;
571 switch (mode) {
572 case B_DPMS_ON:
573 TRACE("%s: crtc %" B_PRIu8 " dpms powerup\n", __func__, crtcID);
574 if (gDisplay[crtcID]->attached == false)
575 return;
576 display_crtc_power(crtcID, ATOM_ENABLE);
577 gDisplay[crtcID]->powered = true;
578 if (info.dceMajor >= 3 && info.dceMajor < 6)
579 display_crtc_memreq(crtcID, ATOM_ENABLE);
580 display_crtc_blank(crtcID, ATOM_BLANKING_OFF);
581 break;
582 case B_DPMS_STAND_BY:
583 case B_DPMS_SUSPEND:
584 case B_DPMS_OFF:
585 TRACE("%s: crtc %" B_PRIu8 " dpms powerdown\n", __func__, crtcID);
586 if (gDisplay[crtcID]->attached == false)
587 return;
588 if (gDisplay[crtcID]->powered == true)
589 display_crtc_blank(crtcID, ATOM_BLANKING);
590 if (info.dceMajor >= 3 && info.dceMajor < 6)
591 display_crtc_memreq(crtcID, ATOM_DISABLE);
592 display_crtc_power(crtcID, ATOM_DISABLE);
593 gDisplay[crtcID]->powered = false;
598 void
599 display_dce45_crtc_load_lut(uint8 crtcID)
601 radeon_shared_info &info = *gInfo->shared_info;
602 register_info* regs = gDisplay[crtcID]->regs;
604 TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID);
606 uint16* r = info.color_data;
607 uint16* g = r + 256;
608 uint16* b = r + 512;
610 if (info.dceMajor >= 5) {
611 Write32(OUT, NI_INPUT_CSC_CONTROL + regs->crtcOffset,
612 NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS)
613 | NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS));
614 Write32(OUT, NI_PRESCALE_GRPH_CONTROL + regs->crtcOffset,
615 NI_GRPH_PRESCALE_BYPASS);
616 Write32(OUT, NI_PRESCALE_OVL_CONTROL + regs->crtcOffset,
617 NI_OVL_PRESCALE_BYPASS);
618 Write32(OUT, NI_INPUT_GAMMA_CONTROL + regs->crtcOffset,
619 NI_GRPH_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT) |
620 NI_OVL_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT));
623 Write32(OUT, EVERGREEN_DC_LUT_CONTROL + regs->crtcOffset, 0);
625 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + regs->crtcOffset, 0);
626 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + regs->crtcOffset, 0);
627 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_RED + regs->crtcOffset, 0);
629 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff);
630 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff);
631 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff);
633 Write32(OUT, EVERGREEN_DC_LUT_RW_MODE, 0);
634 Write32(OUT, EVERGREEN_DC_LUT_WRITE_EN_MASK, 0x00000007);
636 Write32(OUT, EVERGREEN_DC_LUT_RW_INDEX, 0);
637 for (int i = 0; i < 256; i++) {
638 Write32(OUT, EVERGREEN_DC_LUT_30_COLOR + regs->crtcOffset,
639 (r[i] << 20) | (g[i] << 10) | (b[i] << 0));
642 if (info.dceMajor >= 5) {
643 Write32(OUT, NI_DEGAMMA_CONTROL + regs->crtcOffset,
644 (NI_GRPH_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)
645 | NI_OVL_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)
646 | NI_ICON_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)
647 | NI_CURSOR_DEGAMMA_MODE(NI_DEGAMMA_BYPASS)));
648 Write32(OUT, NI_GAMUT_REMAP_CONTROL + regs->crtcOffset,
649 (NI_GRPH_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS) |
650 NI_OVL_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS)));
651 Write32(OUT, NI_REGAMMA_CONTROL + regs->crtcOffset,
652 (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) |
653 NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS)));
654 Write32(OUT, NI_OUTPUT_CSC_CONTROL + regs->crtcOffset,
655 (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) |
656 NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
657 /* XXX match this to the depth of the crtc fmt block, move to modeset? */
658 Write32(OUT, 0x6940 + regs->crtcOffset, 0);
663 void
664 display_avivo_crtc_load_lut(uint8 crtcID)
666 radeon_shared_info &info = *gInfo->shared_info;
667 register_info* regs = gDisplay[crtcID]->regs;
669 TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID);
671 uint16* r = info.color_data;
672 uint16* g = r + 256;
673 uint16* b = r + 512;
675 Write32(OUT, AVIVO_DC_LUTA_CONTROL + regs->crtcOffset, 0);
677 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + regs->crtcOffset, 0);
678 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + regs->crtcOffset, 0);
679 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_RED + regs->crtcOffset, 0);
681 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff);
682 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff);
683 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff);
685 Write32(OUT, AVIVO_DC_LUT_RW_SELECT, crtcID);
686 Write32(OUT, AVIVO_DC_LUT_RW_MODE, 0);
687 Write32(OUT, AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f);
689 Write32(OUT, AVIVO_DC_LUT_RW_INDEX, 0);
690 for (int i = 0; i < 256; i++) {
691 Write32(OUT, AVIVO_DC_LUT_30_COLOR,
692 (r[i] << 20) | (g[i] << 10) | (b[i] << 0));
695 Write32(OUT, AVIVO_D1GRPH_LUT_SEL + regs->crtcOffset, crtcID);
699 void
700 display_crtc_fb_set(uint8 crtcID, display_mode* mode)
702 radeon_shared_info &info = *gInfo->shared_info;
703 register_info* regs = gDisplay[crtcID]->regs;
705 uint16* r = info.color_data;
706 uint16* g = r + 256;
707 uint16* b = r + 512;
709 uint32 fbSwap;
710 if (info.dceMajor >= 4)
711 fbSwap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
712 else
713 fbSwap = R600_D1GRPH_SWAP_ENDIAN_NONE;
715 uint32 fbFormat;
717 uint32 bytesPerPixel;
718 uint32 bitsPerPixel;
720 switch (mode->space) {
721 case B_CMAP8:
722 bytesPerPixel = 1;
723 bitsPerPixel = 8;
724 if (info.dceMajor >= 4) {
725 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP)
726 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
727 } else {
728 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_8BPP
729 | AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;
731 // TODO: copy system color map into shared info
732 break;
733 case B_RGB15_LITTLE:
734 bytesPerPixel = 2;
735 bitsPerPixel = 15;
736 if (info.dceMajor >= 4) {
737 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP)
738 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555));
739 } else {
740 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP
741 | AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
743 break;
744 case B_RGB16_LITTLE:
745 bytesPerPixel = 2;
746 bitsPerPixel = 16;
748 if (info.dceMajor >= 4) {
749 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP)
750 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
751 #ifdef __POWERPC__
752 fbSwap
753 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
754 #endif
755 } else {
756 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP
757 | AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
758 #ifdef __POWERPC__
759 fbSwap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
760 #endif
764 // default gamma table
765 uint16 gamma = 0;
766 for (int i = 0; i < 256; i++) {
767 r[i] = gamma;
768 g[i] = gamma;
769 b[i] = gamma;
770 gamma += 4;
773 break;
774 case B_RGB24_LITTLE:
775 case B_RGB32_LITTLE:
776 default:
777 bytesPerPixel = 4;
778 bitsPerPixel = 32;
779 if (info.dceMajor >= 4) {
780 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP)
781 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
782 #ifdef __POWERPC__
783 fbSwap
784 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
785 #endif
786 } else {
787 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_32BPP
788 | AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
789 #ifdef __POWERPC__
790 fbSwap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
791 #endif
795 // default gamma table
796 uint16 gamma = 0;
797 for (int i = 0; i < 256; i++) {
798 r[i] = gamma;
799 g[i] = gamma;
800 b[i] = gamma;
801 gamma += 4;
804 break;
807 Write32(OUT, regs->vgaControl, 0);
809 uint64 fbAddress = gInfo->fb.vramStart;
811 TRACE("%s: Framebuffer at: 0x%" B_PRIX64 "\n", __func__, fbAddress);
813 if (info.chipsetID >= RADEON_RV770) {
814 TRACE("%s: Set SurfaceAddress High: 0x%" B_PRIX32 "\n",
815 __func__, (fbAddress >> 32) & 0xf);
817 Write32(OUT, regs->grphPrimarySurfaceAddrHigh,
818 (fbAddress >> 32) & 0xf);
819 Write32(OUT, regs->grphSecondarySurfaceAddrHigh,
820 (fbAddress >> 32) & 0xf);
823 TRACE("%s: Set SurfaceAddress: 0x%" B_PRIX64 "\n",
824 __func__, (fbAddress & 0xFFFFFFFF));
826 Write32(OUT, regs->grphPrimarySurfaceAddr, (fbAddress & 0xFFFFFFFF));
827 Write32(OUT, regs->grphSecondarySurfaceAddr, (fbAddress & 0xFFFFFFFF));
829 if (info.chipsetID >= RADEON_R600) {
830 Write32(CRT, regs->grphControl, fbFormat);
831 Write32(CRT, regs->grphSwapControl, fbSwap);
834 // TODO: Technically if chip >= RS600
835 int largeAlign = (info.dceMajor >= 2) ? 1 : 0;
837 // Align our framebuffer width
838 uint32 widthAligned = mode->virtual_width;
839 uint32 pitchMask = 0;
841 switch (bytesPerPixel) {
842 case 1:
843 pitchMask = largeAlign ? 255 : 127;
844 break;
845 case 2:
846 pitchMask = largeAlign ? 127 : 31;
847 break;
848 case 3:
849 case 4:
850 pitchMask = largeAlign ? 63 : 15;
851 break;
853 widthAligned += pitchMask;
854 widthAligned &= ~pitchMask;
856 TRACE("%s: fb: %" B_PRIu32 "x%" B_PRIu32 " (%" B_PRIu32 " bpp)\n", __func__,
857 mode->timing.h_display, mode->timing.v_display, bitsPerPixel);
858 TRACE("%s: fb pitch: %" B_PRIu32 " \n", __func__, widthAligned);
860 Write32(CRT, regs->grphSurfaceOffsetX, 0);
861 Write32(CRT, regs->grphSurfaceOffsetY, 0);
862 Write32(CRT, regs->grphXStart, 0);
863 Write32(CRT, regs->grphYStart, 0);
864 Write32(CRT, regs->grphXEnd, mode->virtual_width);
865 Write32(CRT, regs->grphYEnd, mode->virtual_height);
866 Write32(CRT, regs->grphPitch, widthAligned);
868 Write32(CRT, regs->grphEnable, 1);
869 // Enable Frame buffer
871 Write32(CRT, regs->modeDesktopHeight, mode->virtual_height);
873 uint32 viewportWidth = mode->timing.h_display;
874 uint32 viewportHeight = (mode->timing.v_display + 1) & ~1;
876 Write32(CRT, regs->viewportStart, 0);
877 Write32(CRT, regs->viewportSize,
878 (viewportWidth << 16) | viewportHeight);
880 // Pageflip setup
881 if (info.dceMajor >= 4) {
882 uint32 tmp
883 = Read32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset);
884 tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN;
885 Write32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset, tmp);
887 Write32(OUT, EVERGREEN_MASTER_UPDATE_MODE + regs->crtcOffset, 0);
888 // Pageflip to happen anywhere in vblank
889 display_dce45_crtc_load_lut(crtcID);
890 } else {
891 uint32 tmp = Read32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset);
892 tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN;
893 Write32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset, tmp);
895 Write32(OUT, AVIVO_D1MODE_MASTER_UPDATE_MODE + regs->crtcOffset, 0);
896 // Pageflip to happen anywhere in vblank
897 display_avivo_crtc_load_lut(crtcID);
900 // update shared info
901 gInfo->shared_info->bytes_per_row = widthAligned * bytesPerPixel;
902 gInfo->shared_info->current_mode = *mode;
903 gInfo->shared_info->bits_per_pixel = bitsPerPixel;
907 void
908 display_crtc_set(uint8 crtcID, display_mode* mode)
910 display_timing& displayTiming = mode->timing;
912 TRACE("%s called to do %dx%d\n",
913 __func__, displayTiming.h_display, displayTiming.v_display);
915 SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args;
916 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
917 uint16 misc = 0;
919 memset(&args, 0, sizeof(args));
921 args.usH_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.h_total);
922 args.usH_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display);
923 args.usH_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start);
924 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end
925 - displayTiming.h_sync_start);
927 args.usV_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.v_total);
928 args.usV_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display);
929 args.usV_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start);
930 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end
931 - displayTiming.v_sync_start);
933 args.ucOverscanRight = 0;
934 args.ucOverscanLeft = 0;
935 args.ucOverscanBottom = 0;
936 args.ucOverscanTop = 0;
938 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0)
939 misc |= ATOM_HSYNC_POLARITY;
940 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0)
941 misc |= ATOM_VSYNC_POLARITY;
943 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc);
944 args.ucCRTC = crtcID;
946 atom_execute_table(gAtomContext, index, (uint32*)&args);
950 void
951 display_crtc_set_dtd(uint8 crtcID, display_mode* mode)
953 display_timing& displayTiming = mode->timing;
955 TRACE("%s called to do %dx%d\n", __func__,
956 displayTiming.h_display, displayTiming.v_display);
958 SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
959 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
960 uint16 misc = 0;
962 memset(&args, 0, sizeof(args));
964 // Note: the code below assumes H & V borders are both zero
965 uint16 blankStart
966 = MIN(displayTiming.h_sync_start, displayTiming.h_display);
967 uint16 blankEnd
968 = MAX(displayTiming.h_sync_end, displayTiming.h_total);
969 args.usH_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display);
970 args.usH_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart);
972 blankStart = MIN(displayTiming.v_sync_start, displayTiming.v_display);
973 blankEnd = MAX(displayTiming.v_sync_end, displayTiming.v_total);
974 args.usV_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display);
975 args.usV_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart);
977 args.usH_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start
978 - displayTiming.h_display);
979 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end
980 - displayTiming.h_sync_start);
982 args.usV_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start
983 - displayTiming.v_display);
984 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end
985 - displayTiming.v_sync_start);
987 args.ucH_Border = 0;
988 args.ucV_Border = 0;
990 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0)
991 misc |= ATOM_HSYNC_POLARITY;
992 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0)
993 misc |= ATOM_VSYNC_POLARITY;
995 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc);
996 args.ucCRTC = crtcID;
998 atom_execute_table(gAtomContext, index, (uint32*)&args);
1002 void
1003 display_crtc_ss(pll_info* pll, int command)
1005 TRACE("%s\n", __func__);
1006 radeon_shared_info &info = *gInfo->shared_info;
1008 if (command == ATOM_ENABLE) {
1009 if (pll->ssPercentage == 0) {
1010 TRACE("%s: ssPercentage 0, ignoring SS request\n", __func__);
1011 return;
1013 if ((pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0) {
1014 TRACE("%s: external SS, ignoring SS request\n", __func__);
1015 return;
1017 } else {
1018 if (pll_usage_count(pll->id) > 1) {
1019 // TODO: Check if PLL has SS enabled on any other displays, if so
1020 // we need to also skip this function.
1021 TRACE("%s: TODO: shared PLL detected!\n", __func__);
1025 int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
1027 union enableSS {
1028 ENABLE_LVDS_SS_PARAMETERS lvds_ss;
1029 ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2;
1030 ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
1031 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
1032 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
1035 union enableSS args;
1036 memset(&args, 0, sizeof(args));
1038 if (info.dceMajor >= 5) {
1039 args.v3.usSpreadSpectrumAmountFrac = B_HOST_TO_LENDIAN_INT16(0);
1040 args.v3.ucSpreadSpectrumType
1041 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
1042 switch (pll->id) {
1043 case ATOM_PPLL1:
1044 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
1045 break;
1046 case ATOM_PPLL2:
1047 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
1048 break;
1049 case ATOM_DCPLL:
1050 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
1051 break;
1052 case ATOM_PPLL_INVALID:
1053 return;
1054 default:
1055 ERROR("%s: BUG: Invalid PLL ID!\n", __func__);
1056 return;
1058 args.v3.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(pll->ssAmount);
1059 args.v3.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(pll->ssStep);
1060 args.v3.ucEnable = command;
1061 } else if (info.dceMajor >= 4) {
1062 args.v2.usSpreadSpectrumPercentage
1063 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage);
1064 args.v2.ucSpreadSpectrumType
1065 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
1066 switch (pll->id) {
1067 case ATOM_PPLL1:
1068 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
1069 break;
1070 case ATOM_PPLL2:
1071 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
1072 break;
1073 case ATOM_DCPLL:
1074 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
1075 break;
1076 case ATOM_PPLL_INVALID:
1077 return;
1078 default:
1079 ERROR("%s: BUG: Invalid PLL ID!\n", __func__);
1080 return;
1082 args.v2.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(pll->ssAmount);
1083 args.v2.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(pll->ssStep);
1084 args.v2.ucEnable = command;
1085 } else if (info.dceMajor >= 3) {
1086 args.v1.usSpreadSpectrumPercentage
1087 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage);
1088 args.v1.ucSpreadSpectrumType
1089 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
1090 args.v1.ucSpreadSpectrumStep = pll->ssStep;
1091 args.v1.ucSpreadSpectrumDelay = pll->ssDelay;
1092 args.v1.ucSpreadSpectrumRange = pll->ssRange;
1093 args.v1.ucPpll = pll->id;
1094 args.v1.ucEnable = command;
1095 } else if (info.dceMajor >= 2) {
1096 if (command == ATOM_DISABLE) {
1097 radeon_gpu_ss_control(pll, false);
1098 return;
1100 args.lvds_ss_2.usSpreadSpectrumPercentage
1101 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage);
1102 args.lvds_ss_2.ucSpreadSpectrumType
1103 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
1104 args.lvds_ss_2.ucSpreadSpectrumStep = pll->ssStep;
1105 args.lvds_ss_2.ucSpreadSpectrumDelay = pll->ssDelay;
1106 args.lvds_ss_2.ucSpreadSpectrumRange = pll->ssRange;
1107 args.lvds_ss_2.ucEnable = command;
1108 } else {
1109 ERROR("%s: TODO: Old card SS control\n", __func__);
1110 return;
1113 atom_execute_table(gAtomContext, index, (uint32*)&args);
1117 void
1118 display_crtc_power(uint8 crtcID, int command)
1120 TRACE("%s\n", __func__);
1121 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
1122 ENABLE_CRTC_PS_ALLOCATION args;
1124 memset(&args, 0, sizeof(args));
1126 args.ucCRTC = crtcID;
1127 args.ucEnable = command;
1129 atom_execute_table(gAtomContext, index, (uint32*)&args);
1133 void
1134 display_crtc_memreq(uint8 crtcID, int command)
1136 TRACE("%s\n", __func__);
1137 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq);
1138 ENABLE_CRTC_PS_ALLOCATION args;
1140 memset(&args, 0, sizeof(args));
1142 args.ucCRTC = crtcID;
1143 args.ucEnable = command;
1145 atom_execute_table(gAtomContext, index, (uint32*)&args);