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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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 &current, 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 <stdio.h>
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;
}