mirror of
https://review.haiku-os.org/haiku
synced 2025-01-31 18:56:49 +01:00
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:
parent
06bf290c26
commit
a0902420ff
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 <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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user