From cbd4081064f0aee215b62407ecfd0462cdc204ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 24 Sep 2007 09:02:35 +0000 Subject: [PATCH] * Fixed PLL timing computation for the i9xx chips - I mixed post2 min/max values, and did not take the VCO limits into account; both could (and would during testing) create invalid frequencies. * Also reverted the order in which the PLL divisors are traversed to match the order of what is used in the X driver to create comparable output (our error computation is based on float, though, and should therefore create more accurate values). * The i965 introduced a special register for the surface; the former display base register is now only used for the view offset. Instead of setting the base manually here and there, there is now a set_frame_buffer_base() function. * The DPMS code will now also turn off/on the PLL clock generator. * The code needs some more cleanup, and while the driver now produces the correct timing on my i965 system, I'm now greeted by a black screen after startup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22289 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../graphics/intel_extreme/intel_extreme.h | 3 + .../accelerants/intel_extreme/accelerant.h | 1 + .../intel_extreme/accelerant_protos.h | 2 + .../accelerants/intel_extreme/dpms.cpp | 37 ++++- .../accelerants/intel_extreme/mode.cpp | 147 +++++++++++------- 5 files changed, 126 insertions(+), 64 deletions(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index b83c8cc1b5..fe9dd86f9e 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -194,6 +194,7 @@ struct intel_free_graphics_memory { #define INTEL_DISPLAY_A_CONTROL 0x70180 #define INTEL_DISPLAY_A_BASE 0x70184 #define INTEL_DISPLAY_A_BYTES_PER_ROW 0x70188 +#define INTEL_DISPLAY_A_SURFACE 0x7019c // i965 and up only #define DISPLAY_CONTROL_ENABLED (1UL << 31) #define DISPLAY_CONTROL_GAMMA (1UL << 30) #define DISPLAY_CONTROL_COLOR_MASK (0x0fUL << 26) @@ -238,6 +239,7 @@ struct intel_free_graphics_memory { #define INTEL_DISPLAY_A_ANALOG_PORT 0x61100 #define DISPLAY_MONITOR_PORT_ENABLED (1UL << 31) +#define DISPLAY_MONITOR_PIPE_B (1UL << 30) #define DISPLAY_MONITOR_VGA_POLARITY (1UL << 15) #define DISPLAY_MONITOR_MODE_MASK (3UL << 10) #define DISPLAY_MONITOR_ON 0 @@ -257,6 +259,7 @@ struct intel_free_graphics_memory { #define INTEL_DISPLAY_B_CONTROL 0x71180 #define INTEL_DISPLAY_B_BASE 0x71184 #define INTEL_DISPLAY_B_BYTES_PER_ROW 0x71188 +#define INTEL_DISPLAY_B_SURFACE 0x7119c // i965 and up only #define INTEL_DISPLAY_B_PALETTE 0x0a800 diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.h b/src/add-ons/accelerants/intel_extreme/accelerant.h index 054cde3c72..e4243f0a23 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.h +++ b/src/add-ons/accelerants/intel_extreme/accelerant.h @@ -86,6 +86,7 @@ extern void setup_ring_buffer(ring_buffer &ringBuffer, const char *name); // modes.cpp extern void wait_for_vblank(void); +extern void set_frame_buffer_base(void); extern status_t create_mode_list(void); // memory.cpp diff --git a/src/add-ons/accelerants/intel_extreme/accelerant_protos.h b/src/add-ons/accelerants/intel_extreme/accelerant_protos.h index bf68e29026..84a6ebed51 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant_protos.h +++ b/src/add-ons/accelerants/intel_extreme/accelerant_protos.h @@ -17,6 +17,8 @@ extern "C" { #endif +void spin(bigtime_t delay); + // general status_t intel_init_accelerant(int fd); ssize_t intel_accelerant_clone_info_size(void); diff --git a/src/add-ons/accelerants/intel_extreme/dpms.cpp b/src/add-ons/accelerants/intel_extreme/dpms.cpp index 6c47be890f..e21c709723 100644 --- a/src/add-ons/accelerants/intel_extreme/dpms.cpp +++ b/src/add-ons/accelerants/intel_extreme/dpms.cpp @@ -32,17 +32,18 @@ enable_display_plane(bool enable) write32(INTEL_DISPLAY_A_CONTROL, planeAControl | DISPLAY_CONTROL_ENABLED); if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) write32(INTEL_DISPLAY_B_CONTROL, planeBControl | DISPLAY_CONTROL_ENABLED); + + read32(INTEL_DISPLAY_A_BASE); + // flush the eventually cached PCI bus writes } else { // when disabling it, we have to trigger the update using a write to // the display base address - if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) write32(INTEL_DISPLAY_A_CONTROL, planeAControl & ~DISPLAY_CONTROL_ENABLED); - write32(INTEL_DISPLAY_A_BASE, gInfo->shared_info->frame_buffer_offset); - } - if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { + 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); - } + + set_frame_buffer_base(); } } @@ -64,6 +65,9 @@ enable_display_pipe(bool enable) if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) write32(INTEL_DISPLAY_B_PIPE_CONTROL, pipeBControl & ~DISPLAY_PIPE_ENABLED); } + + read32(INTEL_DISPLAY_A_BASE); + // flush the eventually cached PCI bus writes } @@ -73,6 +77,20 @@ set_display_power_mode(uint32 mode) uint32 monitorMode = 0; if (mode == B_DPMS_ON) { + uint32 pll = read32(INTEL_DISPLAY_A_PLL); + if ((pll & DISPLAY_PLL_ENABLED) == 0) { + // reactivate PLL + write32(INTEL_DISPLAY_A_PLL, pll); + read32(INTEL_DISPLAY_A_PLL); + spin(150); + write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED); + read32(INTEL_DISPLAY_A_PLL); + spin(150); + write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED); + read32(INTEL_DISPLAY_A_PLL); + spin(150); + } + enable_display_pipe(true); enable_display_plane(true); } @@ -107,9 +125,16 @@ set_display_power_mode(uint32 mode) if (mode != B_DPMS_ON) { enable_display_plane(false); + wait_for_vblank(); enable_display_pipe(false); } + if (mode == B_DPMS_OFF) { + write32(INTEL_DISPLAY_A_PLL, read32(INTEL_DISPLAY_A_PLL) | DISPLAY_PLL_ENABLED); + read32(INTEL_DISPLAY_A_PLL); + spin(150); + } + read32(INTEL_DISPLAY_A_BASE); // flush the eventually cached PCI bus writes } diff --git a/src/add-ons/accelerants/intel_extreme/mode.cpp b/src/add-ons/accelerants/intel_extreme/mode.cpp index 704af90413..21c7950739 100644 --- a/src/add-ons/accelerants/intel_extreme/mode.cpp +++ b/src/add-ons/accelerants/intel_extreme/mode.cpp @@ -68,7 +68,9 @@ struct pll_divisors { struct pll_limits { pll_divisors min; pll_divisors max; - float min_post2_frequency; + uint32 min_post2_frequency; + uint32 min_vco; + uint32 max_vco; }; static const display_mode kBaseModeList[] = { @@ -156,6 +158,37 @@ set_i2c_signals(void* cookie, int clock, int data) } +void +set_frame_buffer_base() +{ + intel_shared_info &sharedInfo = *gInfo->shared_info; + display_mode &mode = sharedInfo.current_mode; + uint32 baseRegister; + uint32 surfaceRegister; + + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { + baseRegister = INTEL_DISPLAY_A_BASE; + surfaceRegister = INTEL_DISPLAY_A_SURFACE; + } else { + baseRegister = INTEL_DISPLAY_B_BASE; + surfaceRegister = INTEL_DISPLAY_B_SURFACE; + } + + if (sharedInfo.device_type == (INTEL_TYPE_9xx | INTEL_TYPE_965)) { + write32(baseRegister, mode.v_display_start * sharedInfo.bytes_per_row + + mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8); + read32(baseRegister); + write32(surfaceRegister, sharedInfo.frame_buffer_offset); + read32(surfaceRegister); + } else { + write32(baseRegister, sharedInfo.frame_buffer_offset + + mode.v_display_start * sharedInfo.bytes_per_row + + mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8); + read32(baseRegister); + } +} + + /*! Creates the initial mode list of the primary accelerant. It's called from intel_init_accelerant(). @@ -227,18 +260,18 @@ get_pll_limits(pll_limits &limits) // TODO: support LVDS output limits as well static const pll_limits kLimits = { // p, p1, p2, high, n, m, m1, m2 - { 5, 1, 5, false, 5, 70, 12, 7}, // min - { 80, 8, 10, true, 10, 120, 22, 11}, // max - 200000 + { 5, 1, 10, false, 5, 70, 12, 7}, // min + { 80, 8, 5, true, 10, 120, 22, 11}, // max + 200000, 1400000, 2800000 }; limits = kLimits; } else { // TODO: support LVDS output limits as well static const pll_limits kLimits = { // p, p1, p2, high, n, m, m1, m2 - { 4, 2, 2, false, 5, 96, 20, 8}, - {128, 33, 4, true, 18, 140, 28, 18}, - 165000 + { 4, 2, 4, false, 5, 96, 20, 8}, + {128, 33, 2, true, 18, 140, 28, 18}, + 165000, 930000, 1400000 }; limits = kLimits; } @@ -261,6 +294,7 @@ valid_pll_divisors(const pll_divisors& divisors, const pll_limits& limits) if (divisors.post < limits.min.post || divisors.post > limits.max.post || divisors.m < limits.min.m || divisors.m > limits.max.m + || vco < limits.min_vco || vco > limits.max_vco || frequency < info.min_frequency || frequency > info.max_frequency) return false; @@ -279,9 +313,11 @@ compute_pll_divisors(const display_mode ¤t, pll_divisors& divisors) TRACE(("required MHz: %g\n", requestedPixelClock)); if (current.timing.pixel_clock < limits.min_post2_frequency) { + // slow DAC timing divisors.post2 = limits.min.post2; divisors.post2_high = limits.min.post2_high; } else { + // fast DAC timing divisors.post2 = limits.max.post2; divisors.post2_high = limits.max.post2_high; } @@ -289,13 +325,13 @@ compute_pll_divisors(const display_mode ¤t, pll_divisors& divisors) float best = requestedPixelClock; pll_divisors bestDivisors; - for (divisors.post1 = limits.min.post1; divisors.post1 <= limits.max.post1; - divisors.post1++) { - for (divisors.n = limits.min.n; divisors.n <= limits.max.n; divisors.n++) { - for (divisors.m1 = limits.min.m1; divisors.m1 <= limits.max.m1; - divisors.m1++) { - for (divisors.m2 = limits.min.m2; divisors.m2 < divisors.m1 - && divisors.m2 <= limits.max.m2; divisors.m2++) { + for (divisors.m1 = limits.min.m1; divisors.m1 <= limits.max.m1; divisors.m1++) { + for (divisors.m2 = limits.min.m2; divisors.m2 < divisors.m1 + && divisors.m2 <= limits.max.m2; divisors.m2++) { + for (divisors.n = limits.min.n; divisors.n <= limits.max.n; + divisors.n++) { + for (divisors.post1 = limits.min.post1; + divisors.post1 <= limits.max.post1; divisors.post1++) { divisors.m = 5 * divisors.m1 + divisors.m2; divisors.post = divisors.post1 * divisors.post2; @@ -455,7 +491,7 @@ if (first) { * sharedInfo.bytes_per_row, gInfo->frame_buffer_handle, offset) == B_OK) { sharedInfo.frame_buffer_offset = offset; - write32(INTEL_DISPLAY_A_BASE, offset); + set_frame_buffer_base(); } return B_NO_MEMORY; @@ -464,33 +500,13 @@ if (first) { sharedInfo.frame_buffer_offset = offset; // make sure VGA display is disabled - write32(INTEL_VGA_DISPLAY_CONTROL, read32(INTEL_VGA_DISPLAY_CONTROL) - | VGA_DISPLAY_DISABLED); + write32(INTEL_VGA_DISPLAY_CONTROL, VGA_DISPLAY_DISABLED); + read32(INTEL_VGA_DISPLAY_CONTROL); + + if (gInfo->shared_info->device_type != (INTEL_TYPE_8xx | INTEL_TYPE_85x)) { + } if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { - // update timing parameters - write32(INTEL_DISPLAY_A_HTOTAL, ((uint32)(target.timing.h_total - 1) << 16) - | ((uint32)target.timing.h_display - 1)); - write32(INTEL_DISPLAY_A_HBLANK, ((uint32)(target.timing.h_total - 1) << 16) - | ((uint32)target.timing.h_display - 1)); - write32(INTEL_DISPLAY_A_HSYNC, ((uint32)(target.timing.h_sync_end - 1) << 16) - | ((uint32)target.timing.h_sync_start - 1)); - - write32(INTEL_DISPLAY_A_VTOTAL, ((uint32)(target.timing.v_total - 1) << 16) - | ((uint32)target.timing.v_display - 1)); - write32(INTEL_DISPLAY_A_VBLANK, ((uint32)(target.timing.v_total - 1) << 16) - | ((uint32)target.timing.v_display - 1)); - write32(INTEL_DISPLAY_A_VSYNC, ((uint32)(target.timing.v_sync_end - 1) << 16) - | ((uint32)target.timing.v_sync_start - 1)); - - write32(INTEL_DISPLAY_A_IMAGE_SIZE, ((uint32)(target.timing.h_display - 1) << 16) - | ((uint32)target.timing.v_display - 1)); - - write32(INTEL_DISPLAY_A_ANALOG_PORT, (read32(INTEL_DISPLAY_A_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)); - pll_divisors divisors; compute_pll_divisors(target, divisors); @@ -527,12 +543,39 @@ if (first) { debug_printf("PLL is %#lx, write: %#lx\n", read32(INTEL_DISPLAY_A_PLL), pll); write32(INTEL_DISPLAY_A_PLL, pll); + read32(INTEL_DISPLAY_A_PLL); + spin(150); + write32(INTEL_DISPLAY_A_PLL, pll); + read32(INTEL_DISPLAY_A_PLL); + spin(150); #if 0 write32(INTEL_DISPLAY_A_PLL, DISPLAY_PLL_ENABLED | DISPLAY_PLL_2X_CLOCK | DISPLAY_PLL_NO_VGA_CONTROL | DISPLAY_PLL_DIVIDE_4X | (((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) & DISPLAY_PLL_POST1_DIVISOR_MASK) | (divisorRegister == INTEL_DISPLAY_A_PLL_DIVISOR_1 ? DISPLAY_PLL_DIVISOR_1 : 0)); #endif + // update timing parameters + write32(INTEL_DISPLAY_A_HTOTAL, ((uint32)(target.timing.h_total - 1) << 16) + | ((uint32)target.timing.h_display - 1)); + write32(INTEL_DISPLAY_A_HBLANK, ((uint32)(target.timing.h_total - 1) << 16) + | ((uint32)target.timing.h_display - 1)); + write32(INTEL_DISPLAY_A_HSYNC, ((uint32)(target.timing.h_sync_end - 1) << 16) + | ((uint32)target.timing.h_sync_start - 1)); + + write32(INTEL_DISPLAY_A_VTOTAL, ((uint32)(target.timing.v_total - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + write32(INTEL_DISPLAY_A_VBLANK, ((uint32)(target.timing.v_total - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + write32(INTEL_DISPLAY_A_VSYNC, ((uint32)(target.timing.v_sync_end - 1) << 16) + | ((uint32)target.timing.v_sync_start - 1)); + + write32(INTEL_DISPLAY_A_IMAGE_SIZE, ((uint32)(target.timing.h_display - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + + write32(INTEL_DISPLAY_A_ANALOG_PORT, (read32(INTEL_DISPLAY_A_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)); } // These two have to be set for display B, too - this obviously means @@ -553,16 +596,13 @@ if (first) { // changing bytes per row seems to be ignored if the plane/pipe is turned off - if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow); - write32(INTEL_DISPLAY_A_BASE, sharedInfo.frame_buffer_offset); - // triggers writing back double-buffered registers - } - if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { + 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 - } + + set_frame_buffer_base(); + // triggers writing back double-buffered registers // update shared info sharedInfo.bytes_per_row = bytesPerRow; @@ -727,16 +767,7 @@ intel_move_display(uint16 horizontalStart, uint16 verticalStart) mode.h_display_start = horizontalStart; mode.v_display_start = verticalStart; - if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { - write32(INTEL_DISPLAY_A_BASE, sharedInfo.frame_buffer_offset - + verticalStart * sharedInfo.bytes_per_row - + horizontalStart * (sharedInfo.bits_per_pixel + 7) / 8); - } - if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { - write32(INTEL_DISPLAY_B_BASE, sharedInfo.frame_buffer_offset - + verticalStart * sharedInfo.bytes_per_row - + horizontalStart * (sharedInfo.bits_per_pixel + 7) / 8); - } + set_frame_buffer_base(); return B_OK; }