1 /*
2 * Copyright 2006-2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Support for i915 chipset and up based on the X driver,
6 * Copyright 2006-2007 Intel Corporation.
7 *
8 * Authors:
9 * Axel Dörfler, axeld@pinc-software.de
10 * Alexander von Gluck, kallisti5@unixzen.com
11 */
12
13
14 #include "mode.h"
15
16 #include <create_display_modes.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <math.h>
20
21 #include "accelerant.h"
22 #include "accelerant_protos.h"
23 #include "bios.h"
24 #include "connector.h"
25 #include "display.h"
26 #include "displayport.h"
27 #include "encoder.h"
28 #include "pll.h"
29 #include "utility.h"
30
31
32 #define TRACE_MODE
33 #ifdef TRACE_MODE
34 extern "C" void _sPrintf(const char* format, ...);
35 # define TRACE(x...) _sPrintf("radeon_hd: " x)
36 #else
37 # define TRACE(x...) ;
38 #endif
39
40 #define ERROR(x...) _sPrintf("radeon_hd: " x)
41
42
43 status_t
create_mode_list(void)44 create_mode_list(void)
45 {
46 // TODO: multi-monitor? for now we use VESA and not gDisplay edid
47 uint8 crtcID = 0;
48
49 const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE,
50 B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8};
51
52 gInfo->mode_list_area = create_display_modes("radeon HD modes",
53 &gDisplay[crtcID]->edidData, NULL, 0, kRadeonHDSpaces,
54 B_COUNT_OF(kRadeonHDSpaces), is_mode_supported, &gInfo->mode_list,
55 &gInfo->shared_info->mode_count);
56 if (gInfo->mode_list_area < B_OK)
57 return gInfo->mode_list_area;
58
59 gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
60
61 return B_OK;
62 }
63
64
65 // #pragma mark -
66
67
68 uint32
radeon_accelerant_mode_count(void)69 radeon_accelerant_mode_count(void)
70 {
71 TRACE("%s\n", __func__);
72 // TODO: multi-monitor? we need crtcid here
73
74 return gInfo->shared_info->mode_count;
75 }
76
77
78 status_t
radeon_get_mode_list(display_mode * modeList)79 radeon_get_mode_list(display_mode* modeList)
80 {
81 TRACE("%s\n", __func__);
82 // TODO: multi-monitor? we need crtcid here
83 memcpy(modeList, gInfo->mode_list,
84 gInfo->shared_info->mode_count * sizeof(display_mode));
85 return B_OK;
86 }
87
88
89 status_t
radeon_get_preferred_mode(display_mode * preferredMode)90 radeon_get_preferred_mode(display_mode* preferredMode)
91 {
92 TRACE("%s\n", __func__);
93 // TODO: multi-monitor? we need crtcid here
94
95 uint8_t crtc = 0;
96
97 if (gDisplay[crtc]->preferredMode.virtual_width > 0
98 && gDisplay[crtc]->preferredMode.virtual_height > 0) {
99 TRACE("%s: preferred mode was found for display %" B_PRIu8 "\n",
100 __func__, crtc);
101 memcpy(preferredMode, &gDisplay[crtc]->preferredMode,
102 sizeof(gDisplay[crtc]->preferredMode));
103 return B_OK;
104 }
105
106 return B_ERROR;
107 }
108
109
110 status_t
radeon_get_edid_info(void * info,size_t size,uint32 * edid_version)111 radeon_get_edid_info(void* info, size_t size, uint32* edid_version)
112 {
113 // TODO: multi-monitor? for now we use display 0
114 uint8 crtcID = 0;
115
116 TRACE("%s\n", __func__);
117 if (!gInfo->shared_info->has_edid)
118 return B_ERROR;
119 if (size < sizeof(struct edid1_info))
120 return B_BUFFER_OVERFLOW;
121
122 //memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
123 // VESA
124 memcpy(info, &gDisplay[crtcID]->edidData, sizeof(struct edid1_info));
125 // Display 0
126
127 *edid_version = EDID_VERSION_1;
128
129 return B_OK;
130 }
131
132
133 uint32
radeon_dpms_capabilities(void)134 radeon_dpms_capabilities(void)
135 {
136 // These should be pretty universally supported on Radeon HD cards
137 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
138 }
139
140
141 uint32
radeon_dpms_mode(void)142 radeon_dpms_mode(void)
143 {
144 // TODO: this really isn't a good long-term solution
145 // we may need to look at the encoder dpms scratch registers
146 return gInfo->dpms_mode;
147 }
148
149
150 void
radeon_dpms_set(uint8 id,int mode)151 radeon_dpms_set(uint8 id, int mode)
152 {
153 if (mode == B_DPMS_ON) {
154 display_crtc_dpms(id, mode);
155 encoder_dpms_set(id, mode);
156 } else {
157 encoder_dpms_set(id, mode);
158 display_crtc_dpms(id, mode);
159 }
160 gInfo->dpms_mode = mode;
161 }
162
163
164 void
radeon_dpms_set_hook(int mode)165 radeon_dpms_set_hook(int mode)
166 {
167 // TODO: multi-monitor?
168
169 uint8 crtcID = 0;
170
171 if (gDisplay[crtcID]->attached)
172 radeon_dpms_set(crtcID, mode);
173 }
174
175
176 status_t
radeon_set_display_mode(display_mode * mode)177 radeon_set_display_mode(display_mode* mode)
178 {
179 // TODO: multi-monitor? For now we set the mode on
180 // the first display found.
181
182 TRACE("%s\n", __func__);
183 TRACE(" mode->space: %#" B_PRIx32 "\n", mode->space);
184 TRACE(" mode->virtual_width: %" B_PRIu16 "\n", mode->virtual_width);
185 TRACE(" mode->virtual_height: %" B_PRIu16 "\n", mode->virtual_height);
186 TRACE(" mode->h_display_start: %" B_PRIu16 "\n", mode->h_display_start);
187 TRACE(" mode->v_display_start: %" B_PRIu16 "\n", mode->v_display_start);
188 TRACE(" mode->flags: %#" B_PRIx32 "\n", mode->flags);
189
190 uint8 crtcID = 0;
191
192 if (gDisplay[crtcID]->attached == false)
193 return B_ERROR;
194
195 // Copy this display mode into the "current mode" for the display
196 memcpy(&gDisplay[crtcID]->currentMode, mode, sizeof(display_mode));
197
198 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
199
200 // Determine DP lanes if DP
201 if (connector_is_dp(connectorIndex)) {
202 dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo;
203 dpInfo->laneCount = dp_get_lane_count(connectorIndex, mode);
204 dpInfo->linkRate = dp_get_link_rate(connectorIndex, mode);
205 }
206
207 // *** crtc and encoder prep
208 encoder_output_lock(true);
209 display_crtc_lock(crtcID, ATOM_ENABLE);
210 radeon_dpms_set(crtcID, B_DPMS_OFF);
211
212 // *** Set up encoder -> crtc routing
213 encoder_assign_crtc(crtcID);
214
215 // *** CRT controler mode set
216 // Set up PLL for connector
217 pll_pick(connectorIndex);
218 pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
219 TRACE("%s: pll %d selected for connector %" B_PRIu32 "\n", __func__,
220 pll->id, connectorIndex);
221 pll_set(mode, crtcID);
222
223 display_crtc_set_dtd(crtcID, mode);
224
225 display_crtc_fb_set(crtcID, mode);
226 // atombios_overscan_setup
227 display_crtc_scale(crtcID, mode);
228
229 // *** encoder mode set
230 encoder_mode_set(crtcID);
231
232 // *** encoder and CRT controller commit
233 radeon_dpms_set(crtcID, B_DPMS_ON);
234 display_crtc_lock(crtcID, ATOM_DISABLE);
235 encoder_output_lock(false);
236
237 #ifdef TRACE_MODE
238 // for debugging
239 debug_dp_info();
240
241 TRACE("D1CRTC_STATUS Value: 0x%X\n",
242 Read32(CRT, AVIVO_D1CRTC_STATUS));
243 TRACE("D2CRTC_STATUS Value: 0x%X\n",
244 Read32(CRT, AVIVO_D2CRTC_STATUS));
245 TRACE("D1CRTC_CONTROL Value: 0x%X\n",
246 Read32(CRT, AVIVO_D1CRTC_CONTROL));
247 TRACE("D2CRTC_CONTROL Value: 0x%X\n",
248 Read32(CRT, AVIVO_D2CRTC_CONTROL));
249 TRACE("D1GRPH_ENABLE Value: 0x%X\n",
250 Read32(CRT, AVIVO_D1GRPH_ENABLE));
251 TRACE("D2GRPH_ENABLE Value: 0x%X\n",
252 Read32(CRT, AVIVO_D2GRPH_ENABLE));
253 TRACE("D1SCL_ENABLE Value: 0x%X\n",
254 Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE));
255 TRACE("D2SCL_ENABLE Value: 0x%X\n",
256 Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE));
257 TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n",
258 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
259 TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n",
260 Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
261 #endif
262
263 return B_OK;
264 }
265
266
267 status_t
radeon_get_display_mode(display_mode * _currentMode)268 radeon_get_display_mode(display_mode* _currentMode)
269 {
270 TRACE("%s\n", __func__);
271
272 *_currentMode = gInfo->shared_info->current_mode;
273 //*_currentMode = gDisplay[X]->currentMode;
274 return B_OK;
275 }
276
277
278 status_t
radeon_get_frame_buffer_config(frame_buffer_config * config)279 radeon_get_frame_buffer_config(frame_buffer_config* config)
280 {
281 TRACE("%s\n", __func__);
282
283 config->frame_buffer = gInfo->shared_info->frame_buffer;
284 config->frame_buffer_dma = (uint8*)gInfo->shared_info->frame_buffer_phys;
285
286 config->bytes_per_row = gInfo->shared_info->bytes_per_row;
287
288 TRACE(" config->frame_buffer: %#" B_PRIxADDR "\n",
289 (phys_addr_t)config->frame_buffer);
290 TRACE(" config->frame_buffer_dma: %#" B_PRIxADDR "\n",
291 (phys_addr_t)config->frame_buffer_dma);
292 TRACE(" config->bytes_per_row: %" B_PRIu32 "\n", config->bytes_per_row);
293
294 return B_OK;
295 }
296
297
298 status_t
radeon_get_pixel_clock_limits(display_mode * mode,uint32 * _low,uint32 * _high)299 radeon_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high)
300 {
301 TRACE("%s\n", __func__);
302
303 if (_low != NULL) {
304 // lower limit of about 48Hz vertical refresh
305 uint32 totalClocks = (uint32)mode->timing.h_total
306 * (uint32)mode->timing.v_total;
307 uint32 low = (totalClocks * 48L) / 1000L;
308
309 if (low < PLL_MIN_DEFAULT)
310 low = PLL_MIN_DEFAULT;
311 else if (low > PLL_MAX_DEFAULT)
312 return B_ERROR;
313
314 *_low = low;
315 }
316
317 if (_high != NULL)
318 *_high = PLL_MAX_DEFAULT;
319
320 //*_low = 48L;
321 //*_high = 100 * 1000000L;
322 return B_OK;
323 }
324
325
326 bool
is_mode_supported(display_mode * mode)327 is_mode_supported(display_mode* mode)
328 {
329 bool sane = true;
330
331 // Validate modeline is within a sane range
332 if (is_mode_sane(mode) != B_OK)
333 sane = false;
334
335 // TODO: is_mode_supported on *which* display?
336 uint32 crtid = 0;
337
338 // if we have edid info, check frequency adginst crt reported valid ranges
339 if (gInfo->shared_info->has_edid
340 && gDisplay[crtid]->foundRanges) {
341
342 // validate horizontal frequency range
343 uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total;
344 if (hfreq > gDisplay[crtid]->hfreqMax + 1
345 || hfreq < gDisplay[crtid]->hfreqMin - 1) {
346 //TRACE("!!! mode below falls outside of hfreq range!\n");
347 sane = false;
348 }
349
350 // validate vertical frequency range
351 uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total
352 * mode->timing.h_total) / 1000);
353 if (vfreq > gDisplay[crtid]->vfreqMax + 1
354 || vfreq < gDisplay[crtid]->vfreqMin - 1) {
355 //TRACE("!!! mode below falls outside of vfreq range!\n");
356 sane = false;
357 }
358 }
359
360 #if 0
361 // Lots of spam, but good for understanding what modelines are in use
362 TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d is %s\n",
363 mode->timing.pixel_clock, mode->timing.h_display,
364 mode->timing.h_sync_start, mode->timing.h_sync_end,
365 mode->timing.h_total, mode->timing.v_display,
366 mode->timing.v_sync_start, mode->timing.v_sync_end,
367 mode->timing.v_total,
368 sane ? "OK." : "BAD, out of range!");
369 #endif
370
371 return sane;
372 }
373
374
375 /*
376 * A quick sanity check of the provided display_mode
377 */
378 status_t
is_mode_sane(display_mode * mode)379 is_mode_sane(display_mode* mode)
380 {
381 // horizontal timing
382 // validate h_sync_start is less then h_sync_end
383 if (mode->timing.h_sync_start > mode->timing.h_sync_end) {
384 TRACE("%s: ERROR: (%dx%d) "
385 "received h_sync_start greater then h_sync_end!\n",
386 __func__, mode->timing.h_display, mode->timing.v_display);
387 return B_ERROR;
388 }
389 // validate h_total is greater then h_display
390 if (mode->timing.h_total < mode->timing.h_display) {
391 TRACE("%s: ERROR: (%dx%d) "
392 "received h_total greater then h_display!\n",
393 __func__, mode->timing.h_display, mode->timing.v_display);
394 return B_ERROR;
395 }
396
397 // vertical timing
398 // validate v_start is less then v_end
399 if (mode->timing.v_sync_start > mode->timing.v_sync_end) {
400 TRACE("%s: ERROR: (%dx%d) "
401 "received v_sync_start greater then v_sync_end!\n",
402 __func__, mode->timing.h_display, mode->timing.v_display);
403 return B_ERROR;
404 }
405 // validate v_total is greater then v_display
406 if (mode->timing.v_total < mode->timing.v_display) {
407 TRACE("%s: ERROR: (%dx%d) "
408 "received v_total greater then v_display!\n",
409 __func__, mode->timing.h_display, mode->timing.v_display);
410 return B_ERROR;
411 }
412
413 // calculate refresh rate for given timings to whole int (in Hz)
414 int refresh = mode->timing.pixel_clock * 1000
415 / (mode->timing.h_total * mode->timing.v_total);
416
417 if (refresh < 30 || refresh > 250) {
418 TRACE("%s: ERROR: (%dx%d) "
419 "refresh rate of %dHz is unlikely for any kind of monitor!\n",
420 __func__, mode->timing.h_display, mode->timing.v_display, refresh);
421 return B_ERROR;
422 }
423
424 return B_OK;
425 }
426
427
428 uint32
get_mode_bpp(display_mode * mode)429 get_mode_bpp(display_mode* mode)
430 {
431 // Get bitsPerPixel for given mode
432
433 switch (mode->space) {
434 case B_CMAP8:
435 return 8;
436 case B_RGB15_LITTLE:
437 return 15;
438 case B_RGB16_LITTLE:
439 return 16;
440 case B_RGB24_LITTLE:
441 case B_RGB32_LITTLE:
442 return 32;
443 }
444 ERROR("%s: Unknown colorspace for mode, guessing 32 bits per pixel\n",
445 __func__);
446 return 32;
447 }
448
449
450 static uint32_t
radeon_get_backlight_register()451 radeon_get_backlight_register()
452 {
453 // R600 and up is 0x172c else its 0x0018
454 if (gInfo->shared_info->chipsetID >= RADEON_R600)
455 return 0x172c;
456 return 0x0018;
457 }
458
459
460 status_t
radeon_set_brightness(float brightness)461 radeon_set_brightness(float brightness)
462 {
463 TRACE("%s (%f)\n", __func__, brightness);
464
465 if (brightness < 0 || brightness > 1)
466 return B_BAD_VALUE;
467
468 uint32_t backlightReg = radeon_get_backlight_register();
469 uint8_t brightnessRaw = (uint8_t)ceilf(brightness * 255);
470 uint32_t level = Read32(OUT, backlightReg);
471 TRACE("brightness level = %lx\n", level);
472 level &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
473 level |= (( brightnessRaw << ATOM_S2_CURRENT_BL_LEVEL_SHIFT )
474 & ATOM_S2_CURRENT_BL_LEVEL_MASK);
475 TRACE("new brightness level = %lx\n", level);
476
477 Write32(OUT, backlightReg, level);
478
479 //TODO crtcID = 0: see create_mode
480 // TODO: multi-monitor? for now we use VESA and not gDisplay edid
481 uint8 crtcID = 0;
482 //TODO : test if it is a LCD ?
483 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
484 connector_info* connector = gConnector[connectorIndex];
485 pll_info* pll = &connector->encoder.pll;
486
487 transmitter_dig_setup(connectorIndex, pll->pixelClock,
488 0, 0, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL);
489 transmitter_dig_setup(connectorIndex, pll->pixelClock,
490 0, 0, ATOM_TRANSMITTER_ACTION_LCD_BLON);
491
492 return B_OK;
493 }
494
495
496 status_t
radeon_get_brightness(float * brightness)497 radeon_get_brightness(float* brightness)
498 {
499 TRACE("%s\n", __func__);
500
501 if (brightness == NULL)
502 return B_BAD_VALUE;
503
504 uint32_t backlightReg = Read32(OUT, radeon_get_backlight_register());
505 uint8_t brightnessRaw = ((backlightReg & ATOM_S2_CURRENT_BL_LEVEL_MASK) >>
506 ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
507 *brightness = (float)brightnessRaw / 255;
508
509 return B_OK;
510 }
511