From ccb666bc0e384dd7be48cd85df95683a90db3f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sat, 13 May 2006 09:19:56 +0000 Subject: [PATCH] * 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 --- .../graphics/intel_extreme/intel_extreme.h | 24 ++- .../accelerants/intel_extreme/accelerant.cpp | 15 +- .../accelerants/intel_extreme/accelerant.h | 1 + .../intel_extreme/accelerant_protos.h | 2 +- .../drivers/graphics/intel_extreme/driver.cpp | 4 +- .../graphics/intel_extreme/intel_extreme.cpp | 158 ++++++++++++++---- 6 files changed, 159 insertions(+), 45 deletions(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 38a772939f..1cf6ca7683 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -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 diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.cpp b/src/add-ons/accelerants/intel_extreme/accelerant.cpp index f642d0e4ed..1141790359 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.cpp +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -18,7 +18,7 @@ #include -//#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); diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.h b/src/add-ons/accelerants/intel_extreme/accelerant.h index 86ce0a68a7..dfb0afaf7c 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.h +++ b/src/add-ons/accelerants/intel_extreme/accelerant.h @@ -49,6 +49,7 @@ struct accelerant_info { hardware_status *status; uint8 *cursor_memory; + area_id cursor_area; int device; bool is_clone; diff --git a/src/add-ons/accelerants/intel_extreme/accelerant_protos.h b/src/add-ons/accelerants/intel_extreme/accelerant_protos.h index 5a724c0886..bf68e29026 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant_protos.h +++ b/src/add-ons/accelerants/intel_extreme/accelerant_protos.h @@ -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); diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp index 2cb162d07f..ad174111f8 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp @@ -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; diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp index ff8cceae9d..303fd98104 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp @@ -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); }