* 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
This commit is contained in:
parent
9c7408528e
commit
cbd4081064
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user