Some work to support output on the digital interface like laptop panels.

Need to clean this up, though. It even sort of worked on tic's IBM X40
on BeGeistert - if you weren't irritated by the fact some parts of the
screen were just black, that is :-)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17565 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-05-23 16:16:16 +00:00
parent 06bf290c26
commit a0902420ff
5 changed files with 149 additions and 56 deletions
@@ -180,7 +180,7 @@ struct intel_free_graphics_memory {
#define INTEL_RING_BUFFER_HEAD_MASK 0x001ffffc #define INTEL_RING_BUFFER_HEAD_MASK 0x001ffffc
#define INTEL_RING_BUFFER_ENABLED 1 #define INTEL_RING_BUFFER_ENABLED 1
// display // display A
#define INTEL_DISPLAY_HTOTAL 0x60000 #define INTEL_DISPLAY_HTOTAL 0x60000
#define INTEL_DISPLAY_HBLANK 0x60004 #define INTEL_DISPLAY_HBLANK 0x60004
#define INTEL_DISPLAY_HSYNC 0x60008 #define INTEL_DISPLAY_HSYNC 0x60008
@@ -193,6 +193,7 @@ struct intel_free_graphics_memory {
#define INTEL_DISPLAY_BASE 0x70184 #define INTEL_DISPLAY_BASE 0x70184
#define INTEL_DISPLAY_BYTES_PER_ROW 0x70188 #define INTEL_DISPLAY_BYTES_PER_ROW 0x70188
#define DISPLAY_CONTROL_ENABLED (1UL << 31) #define DISPLAY_CONTROL_ENABLED (1UL << 31)
#define DISPLAY_CONTROL_GAMMA (1UL << 30)
#define DISPLAY_CONTROL_COLOR_MASK (0x0fUL << 26) #define DISPLAY_CONTROL_COLOR_MASK (0x0fUL << 26)
#define DISPLAY_CONTROL_CMAP8 (2UL << 26) #define DISPLAY_CONTROL_CMAP8 (2UL << 26)
#define DISPLAY_CONTROL_RGB15 (4UL << 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_HSYNC (1UL << 3)
#define DISPLAY_MONITOR_POSITIVE_VSYNC (2UL << 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 // cursor
#define INTEL_CURSOR_CONTROL 0x70080 #define INTEL_CURSOR_CONTROL 0x70080
#define INTEL_CURSOR_BASE 0x70084 #define INTEL_CURSOR_BASE 0x70084
@@ -185,6 +185,16 @@ intel_init_accelerant(int device)
setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer"); setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer");
setup_ring_buffer(info.secondary_ring_buffer, "intel secondary 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(); status = create_mode_list();
if (status != B_OK) { if (status != B_OK) {
uninit_common(); uninit_common();
@@ -51,9 +51,14 @@ struct accelerant_info {
uint8 *cursor_memory; uint8 *cursor_memory;
int device; int device;
uint8 head_mode;
bool is_clone; bool is_clone;
}; };
#define HEAD_MODE_A_ANALOG 0x01
#define HEAD_MODE_B_DIGITAL 0x02
#define HEAD_MODE_CLONE 0x03
extern accelerant_info *gInfo; extern accelerant_info *gInfo;
// register access // 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); extern void setup_ring_buffer(ring_buffer &ringBuffer, const char *name);
// modes.cpp // modes.cpp
extern void wait_for_vblank(void);
extern status_t create_mode_list(void); extern status_t create_mode_list(void);
// memory.cpp // memory.cpp
+39 -14
View File
@@ -23,16 +23,26 @@ extern "C" void _sPrintf(const char *format, ...);
void void
enable_display_plane(bool enable) 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) { if (enable) {
// when enabling the display, the register values are updated automatically // 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 { } else {
// when disabling it, we have to trigger the update using a write to // when disabling it, we have to trigger the update using a write to
// the display base address // the display base address
write32(INTEL_DISPLAY_CONTROL, oldValue & ~DISPLAY_CONTROL_ENABLED); if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
write32(INTEL_DISPLAY_BASE, gInfo->shared_info->frame_buffer_offset); 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 static void
enable_display_pipe(bool enable) enable_display_pipe(bool enable)
{ {
uint32 oldValue = read32(INTEL_DISPLAY_PIPE_CONTROL); uint32 pipeAControl = read32(INTEL_DISPLAY_PIPE_CONTROL);
if (enable) uint32 pipeBControl = read32(INTEL_DISPLAY_B_PIPE_CONTROL);
write32(INTEL_DISPLAY_PIPE_CONTROL, oldValue | DISPLAY_PIPE_ENABLED);
else if (enable) {
write32(INTEL_DISPLAY_PIPE_CONTROL, oldValue & ~DISPLAY_PIPE_ENABLED); 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); enable_display_plane(true);
} }
// TODO: wait for vblank! wait_for_vblank();
snooze(10000);
switch (mode) { switch (mode) {
case B_DPMS_ON: case B_DPMS_ON:
@@ -76,9 +94,16 @@ set_display_power_mode(uint32 mode)
break; break;
} }
write32(INTEL_DISPLAY_ANALOG_PORT, (read32(INTEL_DISPLAY_ANALOG_PORT) if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED)) write32(INTEL_DISPLAY_ANALOG_PORT, (read32(INTEL_DISPLAY_ANALOG_PORT)
| monitorMode | (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0)); & ~(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) { if (mode != B_DPMS_ON) {
enable_display_plane(false); enable_display_plane(false);
+82 -41
View File
@@ -102,6 +102,13 @@ create_mode_list(void)
} }
void
wait_for_vblank(void)
{
acquire_sem(gInfo->shared_info->vblank_sem);
}
static void static void
compute_pll_divisors(const display_mode &current, uint32 &postDivisor, compute_pll_divisors(const display_mode &current, uint32 &postDivisor,
uint32 &nDivisor, uint32 &m1Divisor, uint32 &m2Divisor) 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; return B_BAD_VALUE;
} }
#include <stdio.h>
status_t status_t
intel_set_display_mode(display_mode *mode) 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) write32(DISPLAY_VGA_DISPLAY_CONTROL, read32(DISPLAY_VGA_DISPLAY_CONTROL)
| VGA_DISPLAY_DISABLED); | 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) write32(INTEL_DISPLAY_VTOTAL, ((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.h_display - 1)); | ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_HBLANK, ((uint32)(target.timing.h_total - 1) << 16) write32(INTEL_DISPLAY_VBLANK, ((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.h_display - 1)); | ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_HSYNC, ((uint32)(target.timing.h_sync_end - 1) << 16) write32(INTEL_DISPLAY_VSYNC, ((uint32)(target.timing.v_sync_end - 1) << 16)
| ((uint32)target.timing.h_sync_start - 1)); | ((uint32)target.timing.v_sync_start - 1));
write32(INTEL_DISPLAY_VTOTAL, ((uint32)(target.timing.v_total - 1) << 16) write32(INTEL_DISPLAY_IMAGE_SIZE, ((uint32)(target.timing.h_display - 1) << 16)
| ((uint32)target.timing.v_display - 1)); | ((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) write32(INTEL_DISPLAY_ANALOG_PORT, (read32(INTEL_DISPLAY_ANALOG_PORT)
| ((uint32)target.timing.v_display - 1)); & ~(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) uint32 postDivisor, nDivisor, m1Divisor, m2Divisor;
& ~(DISPLAY_MONITOR_POLARITY_MASK | DISPLAY_MONITOR_VGA_POLARITY)) compute_pll_divisors(target, postDivisor, nDivisor, m1Divisor, m2Divisor);
| ((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; // switch divisor register with every mode change (not required)
compute_pll_divisors(target, postDivisor, nDivisor, m1Divisor, m2Divisor); 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) write32(divisorRegister,
uint32 divisorRegister; (((nDivisor - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) & DISPLAY_PLL_N_DIVISOR_MASK)
if (gInfo->shared_info->pll_info.divisor_register == INTEL_DISPLAY_PLL_DIVISOR_0) | (((m1Divisor - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) & DISPLAY_PLL_M1_DIVISOR_MASK)
divisorRegister = INTEL_DISPLAY_PLL_DIVISOR_1; | (((m2Divisor - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) & DISPLAY_PLL_M2_DIVISOR_MASK));
else write32(INTEL_DISPLAY_PLL, DISPLAY_PLL_ENABLED | DISPLAY_PLL_2X_CLOCK
divisorRegister = INTEL_DISPLAY_PLL_DIVISOR_0; | DISPLAY_PLL_NO_VGA_CONTROL | DISPLAY_PLL_DIVIDE_4X
| (((postDivisor - 2) << DISPLAY_PLL_POST_DIVISOR_SHIFT) & DISPLAY_PLL_POST_DIVISOR_MASK)
write32(divisorRegister, | (divisorRegister == INTEL_DISPLAY_PLL_DIVISOR_1 ? DISPLAY_PLL_DIVISOR_1 : 0));
(((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) 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); set_display_power_mode(sharedInfo.dpms_mode);
// changing bytes per row seems to be ignored if the plane/pipe is turned off // 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); if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
// triggers writing back double-buffered registers 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 // update shared info
sharedInfo.bytes_per_row = bytesPerRow; sharedInfo.bytes_per_row = bytesPerRow;
sharedInfo.current_mode = target; sharedInfo.current_mode = target;
sharedInfo.bits_per_pixel = bitsPerPixel; 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; return B_OK;
} }