* Work in progress to support the i965 chipset as well; still works on i865, but

doesn't work on i965 yet.
* B_GET_DISPLAY_MODE now returns the mode actually configured in the chip instead
  of the last mode set; while this isn't really necessary, it allows to check what
  mode was used during startup.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21321 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-06-04 15:32:01 +00:00
parent 189360b5d8
commit 3bac9ea19a
5 changed files with 333 additions and 68 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2006, Haiku, Inc. All Rights Reserved. * Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -24,9 +24,12 @@
#define INTEL_TYPE_GROUP_MASK 0xf0 #define INTEL_TYPE_GROUP_MASK 0xf0
#define INTEL_TYPE_7xx 0x01 #define INTEL_TYPE_7xx 0x01
#define INTEL_TYPE_8xx 0x02 #define INTEL_TYPE_8xx 0x02
#define INTEL_TYPE_9xx 0x03 #define INTEL_TYPE_9xx 0x04
#define INTEL_TYPE_83x 0x10 #define INTEL_TYPE_83x 0x10
#define INTEL_TYPE_85x 0x20 #define INTEL_TYPE_85x 0x20
#define INTEL_TYPE_915 0x10
#define INTEL_TYPE_945 0x20
#define INTEL_TYPE_965 0x40
#define DEVICE_NAME "intel_extreme" #define DEVICE_NAME "intel_extreme"
#define INTEL_ACCELERANT_NAME "intel_extreme.accelerant" #define INTEL_ACCELERANT_NAME "intel_extreme.accelerant"
@ -220,9 +223,12 @@ struct intel_free_graphics_memory {
#define DISPLAY_PLL_2X_CLOCK (1UL << 30) #define DISPLAY_PLL_2X_CLOCK (1UL << 30)
#define DISPLAY_PLL_SYNC_LOCK_ENABLED (1UL << 29) #define DISPLAY_PLL_SYNC_LOCK_ENABLED (1UL << 29)
#define DISPLAY_PLL_NO_VGA_CONTROL (1UL << 28) #define DISPLAY_PLL_NO_VGA_CONTROL (1UL << 28)
#define DISPLAY_PLL_MODE_ANALOG (1UL << 26)
#define DISPLAY_PLL_DIVIDE_HIGH (1UL << 24)
#define DISPLAY_PLL_DIVIDE_4X (1UL << 23) #define DISPLAY_PLL_DIVIDE_4X (1UL << 23)
#define DISPLAY_PLL_POST_DIVISOR_MASK 0x001f0000 #define DISPLAY_PLL_POST1_DIVISOR_MASK 0x001f0000
#define DISPLAY_PLL_POST_DIVISOR_SHIFT 16 #define DISPLAY_PLL_9xx_POST1_DIVISOR_MASK 0x00ff0000
#define DISPLAY_PLL_POST1_DIVISOR_SHIFT 16
#define DISPLAY_PLL_DIVISOR_1 (1UL << 8) #define DISPLAY_PLL_DIVISOR_1 (1UL << 8)
#define DISPLAY_PLL_N_DIVISOR_MASK 0x001f0000 #define DISPLAY_PLL_N_DIVISOR_MASK 0x001f0000
#define DISPLAY_PLL_M1_DIVISOR_MASK 0x00001f00 #define DISPLAY_PLL_M1_DIVISOR_MASK 0x00001f00
@ -230,6 +236,7 @@ struct intel_free_graphics_memory {
#define DISPLAY_PLL_N_DIVISOR_SHIFT 16 #define DISPLAY_PLL_N_DIVISOR_SHIFT 16
#define DISPLAY_PLL_M1_DIVISOR_SHIFT 8 #define DISPLAY_PLL_M1_DIVISOR_SHIFT 8
#define DISPLAY_PLL_M2_DIVISOR_SHIFT 0 #define DISPLAY_PLL_M2_DIVISOR_SHIFT 0
#define DISPLAY_PLL_PULSE_PHASE_SHIFT 9
#define INTEL_DISPLAY_A_ANALOG_PORT 0x61100 #define INTEL_DISPLAY_A_ANALOG_PORT 0x61100
#define DISPLAY_MONITOR_PORT_ENABLED (1UL << 31) #define DISPLAY_MONITOR_PORT_ENABLED (1UL << 31)

View File

@ -1,7 +1,10 @@
/* /*
* Copyright 2006, Haiku, Inc. All Rights Reserved. * Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Support for i915 chipset and up based on the X driver,
* Copyright 2006 Intel Corporation.
*
* Authors: * Authors:
* Axel Dörfler, axeld@pinc-software.de * Axel Dörfler, axeld@pinc-software.de
*/ */
@ -11,6 +14,7 @@
#include "accelerant.h" #include "accelerant.h"
#include "utility.h" #include "utility.h"
#include <stdio.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
@ -29,6 +33,40 @@ extern "C" void _sPrintf(const char *format, ...);
(B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS | B_SUPPORTS_OVERLAYS) (B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS | B_SUPPORTS_OVERLAYS)
struct display_registers {
uint32 pll;
uint32 divisors;
uint32 control;
uint32 pipe_config;
uint32 horiz_total;
uint32 horiz_blank;
uint32 horiz_sync;
uint32 vert_total;
uint32 vert_blank;
uint32 vert_sync;
uint32 size;
uint32 stride;
uint32 position;
uint32 pipe_source;
};
struct pll_divisors {
uint32 post;
uint32 post1;
uint32 post2;
bool post2_high;
uint32 n;
uint32 m;
uint32 m1;
uint32 m2;
};
struct pll_limits {
pll_divisors min;
pll_divisors max;
float min_post2_frequency;
};
static const display_mode kBaseModeList[] = { static const display_mode kBaseModeList[] = {
{{25175, 640, 656, 752, 800, 350, 387, 389, 449, B_POSITIVE_HSYNC}, B_CMAP8, 640, 350, 0, 0, MODE_FLAGS}, /* 640x350 - www.epanorama.net/documents/pc/vga_timing.html) */ {{25175, 640, 656, 752, 800, 350, 387, 389, 449, B_POSITIVE_HSYNC}, B_CMAP8, 640, 350, 0, 0, MODE_FLAGS}, /* 640x350 - www.epanorama.net/documents/pc/vga_timing.html) */
{{25175, 640, 656, 752, 800, 400, 412, 414, 449, B_POSITIVE_VSYNC}, B_CMAP8, 640, 400, 0, 0, MODE_FLAGS}, /* 640x400 - www.epanorama.net/documents/pc/vga_timing.html) */ {{25175, 640, 656, 752, 800, 400, 412, 414, 449, B_POSITIVE_VSYNC}, B_CMAP8, 640, 400, 0, 0, MODE_FLAGS}, /* 640x400 - www.epanorama.net/documents/pc/vga_timing.html) */
@ -69,10 +107,10 @@ static const uint32 kNumBaseModes = sizeof(kBaseModeList) / sizeof(display_mode)
static const uint32 kMaxNumModes = kNumBaseModes * 4; static const uint32 kMaxNumModes = kNumBaseModes * 4;
/** Creates the initial mode list of the primary accelerant. /*!
* It's called from intel_init_accelerant(). Creates the initial mode list of the primary accelerant.
*/ It's called from intel_init_accelerant().
*/
status_t status_t
create_mode_list(void) create_mode_list(void)
{ {
@ -119,30 +157,95 @@ wait_for_vblank(void)
static void static void
compute_pll_divisors(const display_mode &current, uint32 &postDivisor, get_pll_limits(pll_limits &limits)
uint32 &nDivisor, uint32 &m1Divisor, uint32 &m2Divisor) {
// Note, the limits are taken from the X driver; they have not yet been tested
if ((gInfo->shared_info->device_type & INTEL_TYPE_9xx) != 0) {
// 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
};
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
};
limits = kLimits;
}
TRACE(("PLL limits, min: p %lu (p1 %lu, p2 %lu), n %lu, m %lu (m1 %lu, m2 %lu)\n",
limits.min.post, limits.min.post1, limits.min.post2, limits.min.n,
limits.min.m, limits.min.m1, limits.min.m2));
TRACE(("PLL limits, max: p %lu (p1 %lu, p2 %lu), n %lu, m %lu (m1 %lu, m2 %lu)\n",
limits.max.post, limits.max.post1, limits.max.post2, limits.max.n,
limits.max.m, limits.max.m1, limits.max.m2));
}
static bool
valid_pll_divisors(const pll_divisors& divisors, const pll_limits& limits)
{
pll_info &info = gInfo->shared_info->pll_info;
uint32 vco = info.reference_frequency * divisors.m / divisors.n;
uint32 frequency = vco / divisors.post;
if (divisors.post < limits.min.post || divisors.post > limits.max.post
|| divisors.m < limits.min.m || divisors.m > limits.max.m
|| frequency < info.min_frequency || frequency > info.max_frequency)
return false;
return true;
}
static void
compute_pll_divisors(const display_mode &current, pll_divisors& divisors)
{ {
float requestedPixelClock = current.timing.pixel_clock / 1000.0f; float requestedPixelClock = current.timing.pixel_clock / 1000.0f;
float referenceClock = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; float referenceClock = gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
pll_limits limits;
get_pll_limits(limits);
TRACE(("required MHz: %g\n", requestedPixelClock)); TRACE(("required MHz: %g\n", requestedPixelClock));
if (current.timing.pixel_clock < limits.min_post2_frequency) {
divisors.post2 = limits.min.post2;
divisors.post2_high = limits.min.post2_high;
} else {
divisors.post2 = limits.max.post2;
divisors.post2_high = limits.max.post2_high;
}
float best = requestedPixelClock; float best = requestedPixelClock;
uint32 bestP = 0, bestN = 0, bestM = 0; pll_divisors bestDivisors;
// Note, the limits are taken from the X driver; they have not yet been tested 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++) {
divisors.m = 5 * divisors.m1 + divisors.m2;
divisors.post = divisors.post1 * divisors.post2;
for (uint32 p = 3; p < 31; p++) { if (!valid_pll_divisors(divisors, limits))
for (uint32 n = 3; n < 16; n++) { continue;
for (uint32 m1 = 6; m1 < 26; m1++) {
for (uint32 m2 = 6; m2 < 16; m2++) { float error = fabs(requestedPixelClock
uint32 m = m1 * 5 + m2; - ((referenceClock * divisors.m) / divisors.n) / divisors.post);
float error = fabs(requestedPixelClock - ((referenceClock * m) / n) / (p*4));
if (error < best) { if (error < best) {
best = error; best = error;
bestP = p; bestDivisors = divisors;
bestN = n;
bestM = m;
if (error == 0) if (error == 0)
break; break;
} }
@ -151,19 +254,12 @@ compute_pll_divisors(const display_mode &current, uint32 &postDivisor,
} }
} }
postDivisor = bestP; divisors = bestDivisors;
nDivisor = bestN;
TRACE(("found: %g MHz (p = %lu, n = %lu, m = %lu (m1 = %lu, m2 = %lu)\n", TRACE(("found: %g MHz, p = %lu (p1 = %lu, p2 = %lu), n = %lu, m = %lu (m1 = %lu, m2 = %lu)\n",
((referenceClock * bestM) / bestN) / (bestP*4), bestP, bestN, bestM, ((referenceClock * divisors.m) / divisors.n) / divisors.post,
m1Divisor, m2Divisor)); divisors.post, divisors.post1, divisors.post2, divisors.n,
divisors.m, divisors.m1, divisors.m2));
m1Divisor = bestM / 5;
m2Divisor = bestM % 5;
while (m2Divisor < 6) {
m1Divisor--;
m2Divisor += 5;
}
} }
@ -216,7 +312,8 @@ status_t
intel_get_mode_list(display_mode *modeList) intel_get_mode_list(display_mode *modeList)
{ {
TRACE(("intel_get_mode_info()\n")); TRACE(("intel_get_mode_info()\n"));
memcpy(modeList, gInfo->mode_list, gInfo->shared_info->mode_count * sizeof(display_mode)); memcpy(modeList, gInfo->mode_list,
gInfo->shared_info->mode_count * sizeof(display_mode));
return B_OK; return B_OK;
} }
@ -256,14 +353,34 @@ intel_set_display_mode(display_mode *mode)
if (mode == NULL || intel_propose_display_mode(&target, mode, mode)) if (mode == NULL || intel_propose_display_mode(&target, mode, mode))
return B_BAD_VALUE; return B_BAD_VALUE;
uint32 colorMode, bytesPerRow, bitsPerPixel;
get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel);
debug_printf("new resolution: %ux%ux%lu\n", target.timing.h_display, target.timing.v_display, bitsPerPixel);
#if 0
static bool first = true;
if (first) {
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();
}
first = false;
}
#endif
//return B_ERROR;
intel_shared_info &sharedInfo = *gInfo->shared_info; intel_shared_info &sharedInfo = *gInfo->shared_info;
Autolock locker(sharedInfo.accelerant_lock); Autolock locker(sharedInfo.accelerant_lock);
set_display_power_mode(B_DPMS_OFF); set_display_power_mode(B_DPMS_OFF);
uint32 colorMode, bytesPerRow, bitsPerPixel;
get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel);
// free old and allocate new frame buffer in graphics memory // free old and allocate new frame buffer in graphics memory
intel_free_memory(gInfo->frame_buffer_handle); intel_free_memory(gInfo->frame_buffer_handle);
@ -312,8 +429,8 @@ intel_set_display_mode(display_mode *mode)
| ((target.timing.flags & B_POSITIVE_HSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_HSYNC : 0) | ((target.timing.flags & B_POSITIVE_HSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
| ((target.timing.flags & B_POSITIVE_VSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_VSYNC : 0)); | ((target.timing.flags & B_POSITIVE_VSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
uint32 postDivisor, nDivisor, m1Divisor, m2Divisor; pll_divisors divisors;
compute_pll_divisors(target, postDivisor, nDivisor, m1Divisor, m2Divisor); compute_pll_divisors(target, divisors);
// switch divisor register with every mode change (not required) // switch divisor register with every mode change (not required)
uint32 divisorRegister; uint32 divisorRegister;
@ -323,13 +440,41 @@ intel_set_display_mode(display_mode *mode)
divisorRegister = INTEL_DISPLAY_A_PLL_DIVISOR_0; divisorRegister = INTEL_DISPLAY_A_PLL_DIVISOR_0;
write32(divisorRegister, write32(divisorRegister,
(((nDivisor - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) & DISPLAY_PLL_N_DIVISOR_MASK) (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) & DISPLAY_PLL_N_DIVISOR_MASK)
| (((m1Divisor - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) & DISPLAY_PLL_M1_DIVISOR_MASK) | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) & DISPLAY_PLL_M1_DIVISOR_MASK)
| (((m2Divisor - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) & DISPLAY_PLL_M2_DIVISOR_MASK)); | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) & DISPLAY_PLL_M2_DIVISOR_MASK));
uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL;
if ((gInfo->shared_info->device_type & INTEL_TYPE_9xx) != 0) {
// pll |= ((1 << (divisors.post1 - 1)) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
// & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
if (divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_HIGH;
pll |= DISPLAY_PLL_MODE_ANALOG;
if ((gInfo->shared_info->device_type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_965)
pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
} else {
if (divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_4X;
pll |= DISPLAY_PLL_2X_CLOCK;
pll |= (((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_POST1_DIVISOR_MASK);
}
pll |= (divisorRegister == INTEL_DISPLAY_A_PLL_DIVISOR_1 ? DISPLAY_PLL_DIVISOR_1 : 0);
debug_printf("PLL is %#lx, write: %#lx\n", read32(INTEL_DISPLAY_A_PLL), pll);
write32(INTEL_DISPLAY_A_PLL, pll);
#if 0
write32(INTEL_DISPLAY_A_PLL, DISPLAY_PLL_ENABLED | DISPLAY_PLL_2X_CLOCK write32(INTEL_DISPLAY_A_PLL, DISPLAY_PLL_ENABLED | DISPLAY_PLL_2X_CLOCK
| DISPLAY_PLL_NO_VGA_CONTROL | DISPLAY_PLL_DIVIDE_4X | DISPLAY_PLL_NO_VGA_CONTROL | DISPLAY_PLL_DIVIDE_4X
| (((postDivisor - 2) << DISPLAY_PLL_POST_DIVISOR_SHIFT) & DISPLAY_PLL_POST_DIVISOR_MASK) | (((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)); | (divisorRegister == INTEL_DISPLAY_A_PLL_DIVISOR_1 ? DISPLAY_PLL_DIVISOR_1 : 0));
#endif
} }
// These two have to be set for display B, too - this obviously means // These two have to be set for display B, too - this obviously means
@ -366,20 +511,6 @@ intel_set_display_mode(display_mode *mode)
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;
} }
@ -388,7 +519,96 @@ status_t
intel_get_display_mode(display_mode *_currentMode) intel_get_display_mode(display_mode *_currentMode)
{ {
TRACE(("intel_get_display_mode()\n")); TRACE(("intel_get_display_mode()\n"));
*_currentMode = gInfo->shared_info->current_mode;
display_mode &mode = *_currentMode;
uint32 pll = read32(INTEL_DISPLAY_A_PLL);
uint32 pllDivisor = read32((pll & DISPLAY_PLL_DIVISOR_1) != 0
? INTEL_DISPLAY_A_PLL_DIVISOR_1 : INTEL_DISPLAY_A_PLL_DIVISOR_0);
pll_divisors divisors;
divisors.m1 = (pllDivisor & DISPLAY_PLL_M1_DIVISOR_MASK)
>> DISPLAY_PLL_M1_DIVISOR_SHIFT;
divisors.m2 = (pllDivisor & DISPLAY_PLL_M2_DIVISOR_MASK)
>> DISPLAY_PLL_M2_DIVISOR_SHIFT;
divisors.n = (pllDivisor & DISPLAY_PLL_N_DIVISOR_MASK)
>> DISPLAY_PLL_N_DIVISOR_SHIFT;
pll_limits limits;
get_pll_limits(limits);
if ((gInfo->shared_info->device_type & INTEL_TYPE_9xx) != 0) {
divisors.post1 = (pll & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK)
>> DISPLAY_PLL_POST1_DIVISOR_SHIFT;
if ((pll & DISPLAY_PLL_DIVIDE_HIGH) != 0)
divisors.post2 = limits.max.post2;
else
divisors.post2 = limits.min.post2;
} else {
// 8xx
divisors.post1 = (pll & DISPLAY_PLL_POST1_DIVISOR_MASK)
>> DISPLAY_PLL_POST1_DIVISOR_SHIFT;
if ((pll & DISPLAY_PLL_DIVIDE_4X) != 0)
divisors.post2 = limits.max.post2;
else
divisors.post2 = limits.min.post2;
}
divisors.m = 5 * divisors.m1 + divisors.m2;
divisors.post = divisors.post1 * divisors.post2;
float referenceClock = gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
float pixelClock = ((referenceClock * divisors.m) / divisors.n) / divisors.post;
// timing
mode.timing.pixel_clock = uint32(pixelClock * 1000);
mode.timing.flags = 0;
uint32 value = read32(INTEL_DISPLAY_A_HTOTAL);
mode.timing.h_total = (value >> 16) + 1;
mode.timing.h_display = (value & 0xffff) + 1;
value = read32(INTEL_DISPLAY_A_HSYNC);
mode.timing.h_sync_end = (value >> 16) + 1;
mode.timing.h_sync_start = (value & 0xffff) + 1;
value = read32(INTEL_DISPLAY_A_VTOTAL);
mode.timing.v_total = (value >> 16) + 1;
mode.timing.v_display = (value & 0xffff) + 1;
value = read32(INTEL_DISPLAY_A_VSYNC);
mode.timing.v_sync_end = (value >> 16) + 1;
mode.timing.v_sync_start = (value & 0xffff) + 1;
// image size and color space
value = read32(INTEL_DISPLAY_A_IMAGE_SIZE);
mode.virtual_width = (value >> 16) + 1;
mode.virtual_height = (value & 0xffff) + 1;
value = read32(INTEL_DISPLAY_A_CONTROL);
switch (value & DISPLAY_CONTROL_COLOR_MASK) {
case DISPLAY_CONTROL_RGB32:
default:
mode.space = B_RGB32;
break;
case DISPLAY_CONTROL_RGB16:
mode.space = B_RGB16;
break;
case DISPLAY_CONTROL_RGB15:
mode.space = B_RGB15;
break;
case DISPLAY_CONTROL_CMAP8:
mode.space = B_CMAP8;
break;
}
mode.h_display_start = 0;
mode.v_display_start = 0;
mode.flags = 0;
return B_OK; return B_OK;
} }

View File

@ -57,7 +57,7 @@ device_hooks gDeviceHooks = {
static status_t static status_t
checkDeviceInfo(struct intel_info *info) check_device_info(struct intel_info *info)
{ {
if (!info || info->cookie_magic != INTEL_COOKIE_MAGIC) if (!info || info->cookie_magic != INTEL_COOKIE_MAGIC)
return B_BAD_VALUE; return B_BAD_VALUE;
@ -66,6 +66,38 @@ checkDeviceInfo(struct intel_info *info)
} }
static int
getset_register(int argc, char **argv)
{
if (argc < 2 || argc > 3) {
kprintf("usage: %s <register> [set-to-value]\n", argv[0]);
return 0;
}
uint32 reg = parse_expression(argv[1]);
uint32 value = 0;
bool set = argc == 3;
if (set)
value = parse_expression(argv[2]);
kprintf("intel_extreme register %#lx\n", reg);
intel_info &info = *gDeviceInfo[0];
uint32 oldValue = read32(info.registers + reg);
kprintf(" %svalue: %#lx (%lu)\n", set ? "old " : "", oldValue, oldValue);
if (set) {
write32(info.registers + reg, value);
value = read32(info.registers + reg);
kprintf(" new value: %#lx (%lu)\n", value, value);
}
return 0;
}
// #pragma mark - Device Hooks // #pragma mark - Device Hooks
@ -94,10 +126,15 @@ device_open(const char *name, uint32 /*flags*/, void **_cookie)
status_t status = B_OK; status_t status = B_OK;
// TODO: the second open will succeed even though the first one failed!
if (info->open_count++ == 0) { if (info->open_count++ == 0) {
// this device has been opened for the first time, so // this device has been opened for the first time, so
// we allocate needed resources and initialize the structure // we allocate needed resources and initialize the structure
status = intel_extreme_init(*info); status = intel_extreme_init(*info);
if (status == B_OK) {
add_debugger_command("ie_reg", getset_register,
"dumps or sets the specified intel_extreme register");
}
} }
release_lock(&gLock); release_lock(&gLock);
@ -112,11 +149,10 @@ device_close(void *data)
TRACE((DEVICE_NAME ": close\n")); TRACE((DEVICE_NAME ": close\n"));
struct intel_info *info; struct intel_info *info;
if (checkDeviceInfo(info = (intel_info *)data) != B_OK) if (check_device_info(info = (intel_info *)data) != B_OK)
return B_BAD_VALUE; return B_BAD_VALUE;
info->cookie_magic = INTEL_FREE_COOKIE_MAGIC; info->cookie_magic = INTEL_FREE_COOKIE_MAGIC;
return B_OK; return B_OK;
} }
@ -135,6 +171,7 @@ device_free(void *data)
if (info->open_count-- == 1) { if (info->open_count-- == 1) {
// release info structure // release info structure
info->cookie_magic = 0; info->cookie_magic = 0;
remove_debugger_command("ie_reg", getset_register);
intel_extreme_uninit(*info); intel_extreme_uninit(*info);
} }
@ -149,7 +186,7 @@ device_ioctl(void *data, uint32 op, void *buffer, size_t bufferLength)
{ {
struct intel_info *info; struct intel_info *info;
if (checkDeviceInfo(info = (intel_info *)data) != B_OK) if (check_device_info(info = (intel_info *)data) != B_OK)
return B_BAD_VALUE; return B_BAD_VALUE;
switch (op) { switch (op) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2006, Haiku, Inc. All Rights Reserved. * Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -49,6 +49,7 @@ const struct supported_device {
{0x2592, INTEL_TYPE_9xx, "i915GM"}, {0x2592, INTEL_TYPE_9xx, "i915GM"},
{0x2772, INTEL_TYPE_9xx, "i945G"}, {0x2772, INTEL_TYPE_9xx, "i945G"},
{0x27a2, INTEL_TYPE_9xx, "i945GM"}, {0x27a2, INTEL_TYPE_9xx, "i945GM"},
{0x29a2, INTEL_TYPE_9xx | INTEL_TYPE_965, "i965G"}
#endif #endif
}; };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2006, Haiku, Inc. All Rights Reserved. * Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@ -418,14 +418,14 @@ intel_extreme_init(intel_info &info)
info.shared_info->frame_buffer_offset = 0; info.shared_info->frame_buffer_offset = 0;
info.shared_info->dpms_mode = B_DPMS_ON; info.shared_info->dpms_mode = B_DPMS_ON;
if (info.device_type == INTEL_TYPE_9xx) { if ((info.device_type & INTEL_TYPE_9xx) != 0) {
info.shared_info->pll_info.reference_frequency = 96000; // 96 kHz info.shared_info->pll_info.reference_frequency = 96000; // 96 kHz
info.shared_info->pll_info.max_frequency = 400000; // 400 MHz RAM DAC speed info.shared_info->pll_info.max_frequency = 400000; // 400 MHz RAM DAC speed
info.shared_info->pll_info.min_frequency = 20000; // 20 MHz (not tested) info.shared_info->pll_info.min_frequency = 20000; // 20 MHz
} else { } else {
info.shared_info->pll_info.reference_frequency = 48000; // 48 kHz info.shared_info->pll_info.reference_frequency = 48000; // 48 kHz
info.shared_info->pll_info.max_frequency = 350000; // 350 MHz RAM DAC speed info.shared_info->pll_info.max_frequency = 350000; // 350 MHz RAM DAC speed
info.shared_info->pll_info.min_frequency = 25000; // 25 MHz (not tested) info.shared_info->pll_info.min_frequency = 25000; // 25 MHz
} }
info.shared_info->pll_info.divisor_register = INTEL_DISPLAY_A_PLL_DIVISOR_0; info.shared_info->pll_info.divisor_register = INTEL_DISPLAY_A_PLL_DIVISOR_0;