diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 6b7e67ca83..2ed6843e0e 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -180,7 +180,7 @@ struct intel_free_graphics_memory { #define INTEL_RING_BUFFER_HEAD_MASK 0x001ffffc #define INTEL_RING_BUFFER_ENABLED 1 -// display +// display A #define INTEL_DISPLAY_HTOTAL 0x60000 #define INTEL_DISPLAY_HBLANK 0x60004 #define INTEL_DISPLAY_HSYNC 0x60008 @@ -193,6 +193,7 @@ struct intel_free_graphics_memory { #define INTEL_DISPLAY_BASE 0x70184 #define INTEL_DISPLAY_BYTES_PER_ROW 0x70188 #define DISPLAY_CONTROL_ENABLED (1UL << 31) +#define DISPLAY_CONTROL_GAMMA (1UL << 30) #define DISPLAY_CONTROL_COLOR_MASK (0x0fUL << 26) #define DISPLAY_CONTROL_CMAP8 (2UL << 26) #define DISPLAY_CONTROL_RGB15 (4UL << 26) @@ -240,6 +241,16 @@ struct intel_free_graphics_memory { #define DISPLAY_MONITOR_POSITIVE_HSYNC (1UL << 3) #define DISPLAY_MONITOR_POSITIVE_VSYNC (2UL << 3) +// display B +#define INTEL_DISPLAY_B_DIGITAL_PORT 0x61000 +#define INTEL_DISPLAY_B_IMAGE_SIZE 0x6101c + +#define INTEL_DISPLAY_B_PIPE_CONTROL 0x71008 + +#define INTEL_DISPLAY_B_CONTROL 0x71180 +#define INTEL_DISPLAY_B_BASE 0x71184 +#define INTEL_DISPLAY_B_BYTES_PER_ROW 0x71188 + // cursor #define INTEL_CURSOR_CONTROL 0x70080 #define INTEL_CURSOR_BASE 0x70084 diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.cpp b/src/add-ons/accelerants/intel_extreme/accelerant.cpp index 07eff47969..fee6bbff3f 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.cpp +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -185,6 +185,16 @@ intel_init_accelerant(int device) setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer"); setup_ring_buffer(info.secondary_ring_buffer, "intel secondary ring buffer"); + // determine head depending on what's already enabled from the BIOS + // TODO: it would be nicer to retrieve this data via DDC - else the + // display is gone for good if the BIOS decides to only show the + // picture on the connected analog monitor! + gInfo->head_mode = 0; + if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) + gInfo->head_mode |= HEAD_MODE_B_DIGITAL; + if (read32(INTEL_DISPLAY_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) + gInfo->head_mode |= HEAD_MODE_A_ANALOG; + status = create_mode_list(); if (status != B_OK) { uninit_common(); diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.h b/src/add-ons/accelerants/intel_extreme/accelerant.h index 2f4841ac43..054cde3c72 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.h +++ b/src/add-ons/accelerants/intel_extreme/accelerant.h @@ -51,9 +51,14 @@ struct accelerant_info { uint8 *cursor_memory; int device; + uint8 head_mode; bool is_clone; }; +#define HEAD_MODE_A_ANALOG 0x01 +#define HEAD_MODE_B_DIGITAL 0x02 +#define HEAD_MODE_CLONE 0x03 + extern accelerant_info *gInfo; // register access @@ -80,6 +85,7 @@ extern void uninit_ring_buffer(ring_buffer &ringBuffer); extern void setup_ring_buffer(ring_buffer &ringBuffer, const char *name); // modes.cpp +extern void wait_for_vblank(void); extern status_t create_mode_list(void); // memory.cpp diff --git a/src/add-ons/accelerants/intel_extreme/dpms.cpp b/src/add-ons/accelerants/intel_extreme/dpms.cpp index 1e49e41b3d..2084eb8a0c 100644 --- a/src/add-ons/accelerants/intel_extreme/dpms.cpp +++ b/src/add-ons/accelerants/intel_extreme/dpms.cpp @@ -23,16 +23,26 @@ extern "C" void _sPrintf(const char *format, ...); void enable_display_plane(bool enable) { - uint32 oldValue = read32(INTEL_DISPLAY_CONTROL); + uint32 planeAControl = read32(INTEL_DISPLAY_CONTROL); + uint32 planeBControl = read32(INTEL_DISPLAY_B_CONTROL); if (enable) { // when enabling the display, the register values are updated automatically - write32(INTEL_DISPLAY_CONTROL, oldValue | DISPLAY_CONTROL_ENABLED); + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) + write32(INTEL_DISPLAY_CONTROL, planeAControl | DISPLAY_CONTROL_ENABLED); + if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) + write32(INTEL_DISPLAY_B_CONTROL, planeBControl | DISPLAY_CONTROL_ENABLED); } else { // when disabling it, we have to trigger the update using a write to // the display base address - write32(INTEL_DISPLAY_CONTROL, oldValue & ~DISPLAY_CONTROL_ENABLED); - write32(INTEL_DISPLAY_BASE, gInfo->shared_info->frame_buffer_offset); + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { + write32(INTEL_DISPLAY_CONTROL, planeAControl & ~DISPLAY_CONTROL_ENABLED); + write32(INTEL_DISPLAY_BASE, gInfo->shared_info->frame_buffer_offset); + } + if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { + write32(INTEL_DISPLAY_B_CONTROL, planeBControl & ~DISPLAY_CONTROL_ENABLED); + write32(INTEL_DISPLAY_B_BASE, gInfo->shared_info->frame_buffer_offset); + } } } @@ -40,11 +50,20 @@ enable_display_plane(bool enable) static void enable_display_pipe(bool enable) { - uint32 oldValue = read32(INTEL_DISPLAY_PIPE_CONTROL); - if (enable) - write32(INTEL_DISPLAY_PIPE_CONTROL, oldValue | DISPLAY_PIPE_ENABLED); - else - write32(INTEL_DISPLAY_PIPE_CONTROL, oldValue & ~DISPLAY_PIPE_ENABLED); + uint32 pipeAControl = read32(INTEL_DISPLAY_PIPE_CONTROL); + uint32 pipeBControl = read32(INTEL_DISPLAY_B_PIPE_CONTROL); + + if (enable) { + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) + write32(INTEL_DISPLAY_PIPE_CONTROL, pipeAControl | DISPLAY_PIPE_ENABLED); + if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) + write32(INTEL_DISPLAY_B_PIPE_CONTROL, pipeBControl | DISPLAY_PIPE_ENABLED); + } else { + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) + write32(INTEL_DISPLAY_PIPE_CONTROL, pipeAControl & ~DISPLAY_PIPE_ENABLED); + if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) + write32(INTEL_DISPLAY_B_PIPE_CONTROL, pipeBControl & ~DISPLAY_PIPE_ENABLED); + } } @@ -58,8 +77,7 @@ set_display_power_mode(uint32 mode) enable_display_plane(true); } - // TODO: wait for vblank! - snooze(10000); + wait_for_vblank(); switch (mode) { case B_DPMS_ON: @@ -76,9 +94,16 @@ set_display_power_mode(uint32 mode) break; } - write32(INTEL_DISPLAY_ANALOG_PORT, (read32(INTEL_DISPLAY_ANALOG_PORT) - & ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED)) - | monitorMode | (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0)); + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { + write32(INTEL_DISPLAY_ANALOG_PORT, (read32(INTEL_DISPLAY_ANALOG_PORT) + & ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED)) + | monitorMode | (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0)); + } + if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { + write32(INTEL_DISPLAY_B_DIGITAL_PORT, (read32(INTEL_DISPLAY_B_DIGITAL_PORT) + & ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED)) + | monitorMode | (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0)); + } if (mode != B_DPMS_ON) { enable_display_plane(false); diff --git a/src/add-ons/accelerants/intel_extreme/mode.cpp b/src/add-ons/accelerants/intel_extreme/mode.cpp index e6e08b538f..10318767c7 100644 --- a/src/add-ons/accelerants/intel_extreme/mode.cpp +++ b/src/add-ons/accelerants/intel_extreme/mode.cpp @@ -102,6 +102,13 @@ create_mode_list(void) } +void +wait_for_vblank(void) +{ + acquire_sem(gInfo->shared_info->vblank_sem); +} + + static void compute_pll_divisors(const display_mode ¤t, uint32 &postDivisor, uint32 &nDivisor, uint32 &m1Divisor, uint32 &m2Divisor) @@ -229,7 +236,7 @@ intel_propose_display_mode(display_mode *target, const display_mode *low, return B_BAD_VALUE; } -#include + status_t intel_set_display_mode(display_mode *mode) { @@ -272,64 +279,98 @@ intel_set_display_mode(display_mode *mode) write32(DISPLAY_VGA_DISPLAY_CONTROL, read32(DISPLAY_VGA_DISPLAY_CONTROL) | VGA_DISPLAY_DISABLED); - // update timing parameters + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { + // update timing parameters + write32(INTEL_DISPLAY_HTOTAL, ((uint32)(target.timing.h_total - 1) << 16) + | ((uint32)target.timing.h_display - 1)); + write32(INTEL_DISPLAY_HBLANK, ((uint32)(target.timing.h_total - 1) << 16) + | ((uint32)target.timing.h_display - 1)); + write32(INTEL_DISPLAY_HSYNC, ((uint32)(target.timing.h_sync_end - 1) << 16) + | ((uint32)target.timing.h_sync_start - 1)); - write32(INTEL_DISPLAY_HTOTAL, ((uint32)(target.timing.h_total - 1) << 16) - | ((uint32)target.timing.h_display - 1)); - write32(INTEL_DISPLAY_HBLANK, ((uint32)(target.timing.h_total - 1) << 16) - | ((uint32)target.timing.h_display - 1)); - write32(INTEL_DISPLAY_HSYNC, ((uint32)(target.timing.h_sync_end - 1) << 16) - | ((uint32)target.timing.h_sync_start - 1)); + write32(INTEL_DISPLAY_VTOTAL, ((uint32)(target.timing.v_total - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + write32(INTEL_DISPLAY_VBLANK, ((uint32)(target.timing.v_total - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + write32(INTEL_DISPLAY_VSYNC, ((uint32)(target.timing.v_sync_end - 1) << 16) + | ((uint32)target.timing.v_sync_start - 1)); - write32(INTEL_DISPLAY_VTOTAL, ((uint32)(target.timing.v_total - 1) << 16) - | ((uint32)target.timing.v_display - 1)); - write32(INTEL_DISPLAY_VBLANK, ((uint32)(target.timing.v_total - 1) << 16) - | ((uint32)target.timing.v_display - 1)); - write32(INTEL_DISPLAY_VSYNC, ((uint32)(target.timing.v_sync_end - 1) << 16) - | ((uint32)target.timing.v_sync_start - 1)); + write32(INTEL_DISPLAY_IMAGE_SIZE, ((uint32)(target.timing.h_display - 1) << 16) + | ((uint32)target.timing.v_display - 1)); - write32(INTEL_DISPLAY_IMAGE_SIZE, ((uint32)(target.timing.h_display - 1) << 16) - | ((uint32)target.timing.v_display - 1)); + write32(INTEL_DISPLAY_ANALOG_PORT, (read32(INTEL_DISPLAY_ANALOG_PORT) + & ~(DISPLAY_MONITOR_POLARITY_MASK | DISPLAY_MONITOR_VGA_POLARITY)) + | ((target.timing.flags & B_POSITIVE_HSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_HSYNC : 0) + | ((target.timing.flags & B_POSITIVE_VSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_VSYNC : 0)); - write32(INTEL_DISPLAY_ANALOG_PORT, (read32(INTEL_DISPLAY_ANALOG_PORT) - & ~(DISPLAY_MONITOR_POLARITY_MASK | DISPLAY_MONITOR_VGA_POLARITY)) - | ((target.timing.flags & B_POSITIVE_HSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_HSYNC : 0) - | ((target.timing.flags & B_POSITIVE_VSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_VSYNC : 0)); + uint32 postDivisor, nDivisor, m1Divisor, m2Divisor; + compute_pll_divisors(target, postDivisor, nDivisor, m1Divisor, m2Divisor); - uint32 postDivisor, nDivisor, m1Divisor, m2Divisor; - compute_pll_divisors(target, postDivisor, nDivisor, m1Divisor, m2Divisor); + // switch divisor register with every mode change (not required) + uint32 divisorRegister; + if (gInfo->shared_info->pll_info.divisor_register == INTEL_DISPLAY_PLL_DIVISOR_0) + divisorRegister = INTEL_DISPLAY_PLL_DIVISOR_1; + else + divisorRegister = INTEL_DISPLAY_PLL_DIVISOR_0; - // switch divisor register with every mode change (not required) - uint32 divisorRegister; - if (gInfo->shared_info->pll_info.divisor_register == INTEL_DISPLAY_PLL_DIVISOR_0) - divisorRegister = INTEL_DISPLAY_PLL_DIVISOR_1; - else - divisorRegister = INTEL_DISPLAY_PLL_DIVISOR_0; - - write32(divisorRegister, - (((nDivisor - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) & DISPLAY_PLL_N_DIVISOR_MASK) - | (((m1Divisor - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) & DISPLAY_PLL_M1_DIVISOR_MASK) - | (((m2Divisor - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) & DISPLAY_PLL_M2_DIVISOR_MASK)); - write32(INTEL_DISPLAY_PLL, DISPLAY_PLL_ENABLED | DISPLAY_PLL_2X_CLOCK - | DISPLAY_PLL_NO_VGA_CONTROL | DISPLAY_PLL_DIVIDE_4X - | (((postDivisor - 2) << DISPLAY_PLL_POST_DIVISOR_SHIFT) & DISPLAY_PLL_POST_DIVISOR_MASK) - | (divisorRegister == INTEL_DISPLAY_PLL_DIVISOR_1 ? DISPLAY_PLL_DIVISOR_1 : 0)); + write32(divisorRegister, + (((nDivisor - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) & DISPLAY_PLL_N_DIVISOR_MASK) + | (((m1Divisor - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) & DISPLAY_PLL_M1_DIVISOR_MASK) + | (((m2Divisor - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) & DISPLAY_PLL_M2_DIVISOR_MASK)); + write32(INTEL_DISPLAY_PLL, DISPLAY_PLL_ENABLED | DISPLAY_PLL_2X_CLOCK + | DISPLAY_PLL_NO_VGA_CONTROL | DISPLAY_PLL_DIVIDE_4X + | (((postDivisor - 2) << DISPLAY_PLL_POST_DIVISOR_SHIFT) & DISPLAY_PLL_POST_DIVISOR_MASK) + | (divisorRegister == INTEL_DISPLAY_PLL_DIVISOR_1 ? DISPLAY_PLL_DIVISOR_1 : 0)); + } + // These two have to be set for display B, too - this obviously means + // that the second head always must adopt the color space of the first + // head. write32(INTEL_DISPLAY_CONTROL, (read32(INTEL_DISPLAY_CONTROL) - & ~DISPLAY_CONTROL_COLOR_MASK) | colorMode); + & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) | colorMode); + + if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { + write32(INTEL_DISPLAY_B_IMAGE_SIZE, ((uint32)(target.timing.h_display - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + + write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL) + & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) | colorMode); + } set_display_power_mode(sharedInfo.dpms_mode); // changing bytes per row seems to be ignored if the plane/pipe is turned off - write32(INTEL_DISPLAY_BYTES_PER_ROW, bytesPerRow); - write32(INTEL_DISPLAY_BASE, sharedInfo.frame_buffer_offset); - // triggers writing back double-buffered registers + + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { + write32(INTEL_DISPLAY_BYTES_PER_ROW, bytesPerRow); + write32(INTEL_DISPLAY_BASE, sharedInfo.frame_buffer_offset); + // triggers writing back double-buffered registers + } + if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { + write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow); + write32(INTEL_DISPLAY_B_BASE, sharedInfo.frame_buffer_offset); + // triggers writing back double-buffered registers + } // update shared info sharedInfo.bytes_per_row = bytesPerRow; sharedInfo.current_mode = target; sharedInfo.bits_per_pixel = bitsPerPixel; +#if 0 +int fd = open("/boot/home/ie.regs", O_CREAT | O_WRONLY, 0644); +if (fd >= 0) { + for (int32 i = 0; i < 0x80000; i += 16) { + char line[512]; + int length = sprintf(line, "%05lx: %08lx %08lx %08lx %08lx\n", + i, read32(i), read32(i + 4), read32(i + 8), read32(i + 12)); + write(fd, line, length); + } + close(fd); + sync(); +} +#endif + return B_OK; }