* Prepared having hardware cursor support; got quite complicated because there

is no good (or reliable) way to retrieve the physical address of "stolen"
  (by the BIOS) graphics memory.
* Implemented allocation of additional graphics memory in case the BIOS was
  a bit too cheap. We now guarantee 8 MB of memory available to the graphics
  chip - would be nicer to only allocate that on demand, though.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17433 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-05-13 09:19:56 +00:00
parent c8609aed8c
commit ccb666bc0e
6 changed files with 159 additions and 45 deletions

View File

@ -20,11 +20,11 @@
#define VENDOR_ID_INTEL 0x8086
enum {
INTEL_TYPE_7xx,
INTEL_TYPE_8xx,
INTEL_TYPE_9xx,
};
#define INTEL_TYPE_7xx 0x01
#define INTEL_TYPE_8xx 0x02
#define INTEL_TYPE_9xx 0x03
#define INTEL_TYPE_83x 0x10
#define INTEL_TYPE_85x 0x20
#define DEVICE_NAME "intel_extreme"
#define INTEL_ACCELERANT_NAME "intel_extreme.accelerant"
@ -64,6 +64,7 @@ struct intel_shared_info {
area_id registers_area; // area of memory mapped registers
uint8 *physical_status_page;
area_id cursor_area;
uint8 *physical_cursor_memory;
area_id graphics_memory_area;
uint8 *graphics_memory;
@ -94,12 +95,15 @@ struct intel_info {
area_id registers_area;
struct intel_shared_info *shared_info;
area_id shared_area;
area_id cursor_area;
struct overlay_registers *overlay_registers;
// update buffer, shares an area with shared_info
uint8 *graphics_memory;
area_id graphics_memory_area;
area_id additional_memory_area;
// allocated memory beyond the "stolen" amount
mem_info *memory_manager;
const char *device_identifier;
@ -162,10 +166,12 @@ struct intel_free_graphics_memory {
#define i855_STOLEN_MEMORY_48M 0x60
#define i855_STOLEN_MEMORY_64M 0x70
#define INTEL_PAGE_TABLE_CONTROL 0x02020
#define INTEL_PAGE_TABLE_ERROR 0x02024
#define INTEL_HARDWARE_STATUS_PAGE 0x02080
#define INTEL_GTT_BASE 0x10000 // (- 0x2ffff)
#define GTT_ENTRY_VALID 0x01
#define GTT_ENTRY_LOCAL_MEMORY 0x02
#define INTEL_PRIMARY_RING_BUFFER 0x02030
#define INTEL_SECONDARY_RING_BUFFER_0 0x02100
@ -232,6 +238,12 @@ struct intel_free_graphics_memory {
#define DISPLAY_MONITOR_POSITIVE_HSYNC (1UL << 3)
#define DISPLAY_MONITOR_POSITIVE_VSYNC (2UL << 3)
#define INTEL_CURSOR_CONTROL 0x70080
#define INTEL_CURSOR_BASE 0x70084
#define INTEL_CURSOR_POSITION 0x70088
#define INTEL_CURSOR_PALETTE 0x70090 // (- 0x7009f)
#define INTEL_CURSOR_SIZE 0x700a0
// ring buffer commands
#define COMMAND_NOOP 0x00

View File

@ -18,7 +18,7 @@
#include <syslog.h>
//#define TRACE_ACCELERANT
#define TRACE_ACCELERANT
#ifdef TRACE_ACCELERANT
extern "C" void _sPrintf(const char *format, ...);
# define TRACE(x) _sPrintf x
@ -128,8 +128,19 @@ init_common(int device, bool isClone)
return status;
}
AreaCloner cursorCloner;
gInfo->cursor_area = cursorCloner.Clone("intel extreme cursor",
(void **)&gInfo->cursor_memory, B_ANY_ADDRESS,
B_READ_AREA | B_WRITE_AREA,
gInfo->shared_info->cursor_area);
if (cursorCloner.InitCheck() < B_OK) {
// we can't do a hardware cursor then...
gInfo->cursor_memory = NULL;
}
sharedCloner.Keep();
regsCloner.Keep();
cursorCloner.Keep();
// The overlay registers, hardware status, and cursor memory share
// a single area with the shared_info
@ -148,6 +159,7 @@ init_common(int device, bool isClone)
static void
uninit_common(void)
{
delete_area(gInfo->cursor_area);
delete_area(gInfo->regs_area);
delete_area(gInfo->shared_info_area);
@ -157,7 +169,6 @@ uninit_common(void)
gInfo->shared_info = NULL;
// close the file handle ONLY if we're the clone
// (this is what Be tells us ;)
if (gInfo->is_clone)
close(gInfo->device);

View File

@ -49,6 +49,7 @@ struct accelerant_info {
hardware_status *status;
uint8 *cursor_memory;
area_id cursor_area;
int device;
bool is_clone;

View File

@ -45,7 +45,7 @@ uint32 intel_dpms_mode(void);
status_t intel_set_dpms_mode(uint32 flags);
// cursor
status_t intel_set_cursor_shape(uint16 width, uint16 height, uint16 hotX, uint16 hotX,
status_t intel_set_cursor_shape(uint16 width, uint16 height, uint16 hotX, uint16 hotY,
uint8 *andMask, uint8 *xorMask);
void intel_move_cursor(uint16 x, uint16 y);
void intel_show_cursor(bool isVisible);

View File

@ -36,8 +36,8 @@ const struct supported_device {
int32 type;
const char *name;
} kSupportedDevices[] = {
{0x2572, INTEL_TYPE_8xx, "i865G"},
{0x3582, INTEL_TYPE_8xx, "i855G"},
{0x2572, INTEL_TYPE_8xx | INTEL_TYPE_85x, "i865G"},
{0x3582, INTEL_TYPE_8xx | INTEL_TYPE_85x, "i855G"},
};
int32 api_version = B_CUR_DRIVER_API_VERSION;

View File

@ -91,6 +91,62 @@ init_overlay_registers(overlay_registers *registers)
}
static size_t
determine_stolen_memory_size(intel_info &info)
{
// read stolen memory from the PCI configuration of the PCI bridge
uint16 memoryConfig = gPCI->read_pci_config(0, 0, 0, INTEL_GRAPHICS_MEMORY_CONTROL, 2);
size_t memorySize = 1024 * 1024;
// TODO: test with different models!
if (info.device_type & INTEL_TYPE_83x) {
switch (memoryConfig & STOLEN_MEMORY_MASK) {
case i830_LOCAL_MEMORY_ONLY:
// TODO: determine its size!
break;
case i830_STOLEN_512K:
memorySize >>= 1;
break;
case i830_STOLEN_8M:
memorySize *= 8;
break;
}
} else if (info.device_type & INTEL_TYPE_85x) {
switch (memoryConfig & STOLEN_MEMORY_MASK) {
case i855_STOLEN_MEMORY_4M:
memorySize *= 4;
break;
case i855_STOLEN_MEMORY_8M:
memorySize *= 8;
break;
case i855_STOLEN_MEMORY_16M:
memorySize *= 16;
break;
case i855_STOLEN_MEMORY_32M:
memorySize *= 32;
break;
case i855_STOLEN_MEMORY_48M:
memorySize *= 48;
break;
case i855_STOLEN_MEMORY_64M:
memorySize *= 64;
break;
}
}
return memorySize;
}
static void
set_gtt_entry(intel_info &info, uint32 offset, uint8 *physicalAddress)
{
write32(info.registers + INTEL_GTT_BASE + (offset >> 10),
(uint32)physicalAddress | GTT_ENTRY_VALID);
}
// #pragma mark -
@ -107,41 +163,35 @@ intel_extreme_init(intel_info &info)
memset((void *)info.shared_info, 0, sizeof(intel_shared_info));
// get chipset info
// Determine the amount of "stolen" (ie. reserved by the BIOS) graphics memory
// and see if we need to allocate some more.
// TODO: introduce a settings value which you can use to cut down the memory
// requirements, or make it allocate the memory on demand!
// read stolen memory from the PCI configuration of the PCI bridge
uint16 memoryConfig = gPCI->read_pci_config(0, 0, 0, INTEL_GRAPHICS_MEMORY_CONTROL, 2);
size_t memorySize = 1024 * 1024;
size_t stolenSize = determine_stolen_memory_size(info);
dprintf(DEVICE_NAME ": detected %ld MB of stolen memory\n", stolenSize / 1024 / 1024);
// TODO: this doesn't work like this on anything older than i855
switch (memoryConfig & STOLEN_MEMORY_MASK) {
case i855_STOLEN_MEMORY_4M:
memorySize *= 4;
break;
case i855_STOLEN_MEMORY_8M:
memorySize *= 8;
break;
case i855_STOLEN_MEMORY_16M:
memorySize *= 16;
break;
case i855_STOLEN_MEMORY_32M:
memorySize *= 32;
break;
case i855_STOLEN_MEMORY_48M:
memorySize *= 48;
break;
case i855_STOLEN_MEMORY_64M:
memorySize *= 64;
break;
}
dprintf(DEVICE_NAME ": detected %ld MB of stolen memory\n", memorySize / 1024 / 1024);
AreaKeeper additionalMemoryCreator;
size_t totalSize = max_c(8 * 1024 * 1024, stolenSize);
uint8 *additionalMemory;
if (stolenSize < totalSize) {
// Every device should have at least 8 MB - we could also allocate them
// on demand only, but we're lazy here...
info.additional_memory_area = additionalMemoryCreator.Create("intel additional memory",
(void **)&additionalMemory, B_ANY_KERNEL_ADDRESS,
totalSize - stolenSize, B_FULL_LOCK, 0);
if (info.additional_memory_area < B_OK)
return info.additional_memory_area;
} else
info.additional_memory_area = B_ERROR;
// map frame buffer, try to map it write combined
AreaKeeper graphicsMapper;
info.graphics_memory_area = graphicsMapper.Map("intel extreme graphics memory",
(void *)info.pci->u.h0.base_registers[0],
memorySize, B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
totalSize, B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
B_READ_AREA | B_WRITE_AREA, (void **)&info.graphics_memory);
if (graphicsMapper.InitCheck() < B_OK) {
// try again without write combining
@ -149,7 +199,7 @@ intel_extreme_init(intel_info &info)
info.graphics_memory_area = graphicsMapper.Map("intel extreme graphics memory",
(void *)info.pci->u.h0.base_registers[0],
memorySize/*info.pci->u.h0.base_register_sizes[0]*/, B_ANY_KERNEL_BLOCK_ADDRESS,
totalSize/*info.pci->u.h0.base_register_sizes[0]*/, B_ANY_KERNEL_BLOCK_ADDRESS,
B_READ_AREA | B_WRITE_AREA, (void **)&info.graphics_memory);
}
if (graphicsMapper.InitCheck() < B_OK) {
@ -163,9 +213,7 @@ intel_extreme_init(intel_info &info)
info.registers_area = mmioMapper.Map("intel extreme mmio",
(void *)info.pci->u.h0.base_registers[1],
info.pci->u.h0.base_register_sizes[1],
B_ANY_KERNEL_BLOCK_ADDRESS,
B_READ_AREA | B_WRITE_AREA,
(void **)&info.registers);
B_ANY_KERNEL_ADDRESS, 0, (void **)&info.registers);
if (mmioMapper.InitCheck() < B_OK) {
dprintf(DEVICE_NAME ": could not map memory I/O!\n");
return info.registers_area;
@ -173,8 +221,8 @@ intel_extreme_init(intel_info &info)
// init graphics memory manager
info.memory_manager = mem_init("intel extreme memory manager", 0, memorySize, 1024,
min_c(memorySize / 1024, 512));
info.memory_manager = mem_init("intel extreme memory manager", 0, totalSize, 1024,
min_c(totalSize / 1024, 512));
if (info.memory_manager == NULL)
return B_NO_MEMORY;
@ -208,7 +256,7 @@ intel_extreme_init(intel_info &info)
info.shared_info->graphics_memory = info.graphics_memory;
info.shared_info->physical_graphics_memory = (uint8 *)info.pci->u.h0.base_registers[0];
info.shared_info->graphics_memory_size = memorySize;
info.shared_info->graphics_memory_size = totalSize;
info.shared_info->frame_buffer_offset = 0;
info.shared_info->dpms_mode = B_DPMS_ON;
info.shared_info->pll_info.reference_frequency = 48000; // 48 kHz
@ -245,6 +293,43 @@ intel_extreme_init(intel_info &info)
B_PAGE_SIZE, &physicalEntry, 1);
info.shared_info->physical_cursor_memory = (uint8 *)physicalEntry.address;
// setup the GTT to point to include the additional memory
if (stolenSize < totalSize) {
for (size_t offset = stolenSize; offset < totalSize;) {
physical_entry physicalEntry;
get_memory_map(additionalMemory + offset - stolenSize,
totalSize - offset, &physicalEntry, 1);
for (size_t i = 0; i < physicalEntry.size; i += B_PAGE_SIZE) {
set_gtt_entry(info, offset + i, (uint8 *)physicalEntry.address + i);
}
offset += physicalEntry.size;
}
}
// We also need to map the cursor memory into the GTT
// This could also be part of the usual graphics memory, but for some
// reason we need its physical address, too - and we only know that of
// the additional memory we allocated.
// Unfortunately, the GTT is not readable - we would need to compute
// the physical location of stolen memory with some heuristics (as it
// should be taken from the top of system memory), and hope that the
// BIOS adhered to this specification.
set_gtt_entry(info, totalSize, info.shared_info->physical_cursor_memory);
AreaKeeper cursorMapper;
info.cursor_area = cursorMapper.Map("intel extreme cursor",
(void *)(info.shared_info->physical_graphics_memory + totalSize),
B_PAGE_SIZE, B_ANY_KERNEL_ADDRESS, 0, (void **)&info.registers);
if (cursorMapper.InitCheck() < B_OK) {
// we can't do a hardware cursor, then...
}
info.shared_info->cursor_area = info.cursor_area;
info.cookie_magic = INTEL_COOKIE_MAGIC;
// this makes the cookie valid to be used
@ -264,5 +349,10 @@ intel_extreme_uninit(intel_info &info)
delete_area(info.graphics_memory_area);
delete_area(info.registers_area);
delete_area(info.shared_area);
delete_area(info.cursor_area);
// we may or may not have allocated additional graphics memory
if (info.additional_memory_area >= B_OK)
delete_area(info.additional_memory_area);
}