From e404297e56d4d54998a8f21b661def9d2da746d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 24 Mar 2006 21:46:40 +0000 Subject: [PATCH] Very basic driver for the "Intel Extreme Graphics 2" chips, only supports i865G for now. Only mode switches do work, doesn't yet make sure the mode is valid, though. At this point, this driver only works on Haiku, the R5 app_server is crashing for some reason I need to investigate some day (maybe tomorrow :)). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16872 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../graphics/intel_extreme/intel_extreme.h | 158 +++++++ headers/private/graphics/intel_extreme/lock.h | 57 +++ .../private/graphics/intel_extreme/utility.h | 13 + src/add-ons/accelerants/Jamfile | 1 + src/add-ons/accelerants/intel_extreme/Jamfile | 17 + .../accelerants/intel_extreme/accelerant.cpp | 274 ++++++++++++ .../accelerants/intel_extreme/accelerant.h | 53 +++ .../intel_extreme/accelerant_protos.h | 87 ++++ .../accelerants/intel_extreme/dpms.cpp | 106 +++++ .../accelerants/intel_extreme/engine.cpp | 64 +++ .../accelerants/intel_extreme/hooks.cpp | 106 +++++ .../accelerants/intel_extreme/mode.cpp | 390 ++++++++++++++++++ src/add-ons/kernel/drivers/graphics/Jamfile | 1 + .../drivers/graphics/intel_extreme/Jamfile | 19 + .../drivers/graphics/intel_extreme/device.cpp | 237 +++++++++++ .../drivers/graphics/intel_extreme/device.h | 18 + .../drivers/graphics/intel_extreme/driver.cpp | 209 ++++++++++ .../drivers/graphics/intel_extreme/driver.h | 60 +++ .../graphics/intel_extreme/intel_extreme.cpp | 197 +++++++++ 19 files changed, 2067 insertions(+) create mode 100644 headers/private/graphics/intel_extreme/intel_extreme.h create mode 100644 headers/private/graphics/intel_extreme/lock.h create mode 100644 headers/private/graphics/intel_extreme/utility.h create mode 100644 src/add-ons/accelerants/intel_extreme/Jamfile create mode 100644 src/add-ons/accelerants/intel_extreme/accelerant.cpp create mode 100644 src/add-ons/accelerants/intel_extreme/accelerant.h create mode 100644 src/add-ons/accelerants/intel_extreme/accelerant_protos.h create mode 100644 src/add-ons/accelerants/intel_extreme/dpms.cpp create mode 100644 src/add-ons/accelerants/intel_extreme/engine.cpp create mode 100644 src/add-ons/accelerants/intel_extreme/hooks.cpp create mode 100644 src/add-ons/accelerants/intel_extreme/mode.cpp create mode 100644 src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile create mode 100644 src/add-ons/kernel/drivers/graphics/intel_extreme/device.cpp create mode 100644 src/add-ons/kernel/drivers/graphics/intel_extreme/device.h create mode 100644 src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp create mode 100644 src/add-ons/kernel/drivers/graphics/intel_extreme/driver.h create mode 100644 src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h new file mode 100644 index 0000000000..7f02819248 --- /dev/null +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -0,0 +1,158 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef INTEL_EXTREME_H +#define INTEL_EXTREME_H + + +#include +#include +#include + + +#define VENDOR_ID_INTEL 0x8086 +#define DEVICE_ID_i865 0x2572 + +#define DEVICE_NAME "intel_extreme" +#define INTEL_ACCELERANT_NAME "intel_extreme.accelerant" + +#define INTEL_COOKIE_MAGIC 'intl' +#define INTEL_FREE_COOKIE_MAGIC 'itlf' + +// info about PLL on graphics card +struct pll_info { + uint32 reference_frequency; + uint32 max_frequency; + uint32 min_frequency; + uint32 divisor_register; +}; + +struct intel_shared_info { + int32 type; + area_id mode_list_area; // area containing display mode list + uint32 mode_count; + + display_mode current_mode; + uint32 bytes_per_row; + uint32 dpms_mode; + + area_id registers_area; // area of memory mapped registers + area_id frame_buffer_area; // area of frame buffer + uint8 *frame_buffer; // pointer to frame buffer (visible by all apps!) + uint8 *physical_frame_buffer; + + uint32 graphics_memory_size; + struct pll_info pll_info; +}; + +struct intel_info { + uint32 cookie_magic; + int32 open_count; + int32 id; + pci_info *pci; + uint8 *registers; + area_id registers_area; + struct intel_shared_info *shared_info; + area_id shared_area; + uint8 *frame_buffer; + area_id frame_buffer_area; +}; + +//----------------- ioctl() interface ---------------- + +// magic code for ioctls +#define INTEL_PRIVATE_DATA_MAGIC 'itic' + +// list ioctls +enum { + INTEL_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, + + INTEL_GET_DEVICE_NAME, + INTEL_ALLOC_LOCAL_MEMORY, + INTEL_FREE_LOCAL_MEMORY +}; + +// retrieve the area_id of the kernel/accelerant shared info +struct intel_get_private_data { + uint32 magic; // magic number + area_id shared_info_area; +}; + +// allocate graphics memory +struct intel_allocate_graphics_memory { + uint32 magic; + uint32 size; + uint32 fb_offset; + uint32 handle; +}; + +// free graphics memory +struct intel_free_graphics_memory { + uint32 magic; + uint32 handle; +}; + +//---------------------------------------------------------- +// Register definitions, taken from X driver + +#define INTEL_DISPLAY_HTOTAL 0x60000 +#define INTEL_DISPLAY_HBLANK 0x60004 +#define INTEL_DISPLAY_HSYNC 0x60008 +#define INTEL_DISPLAY_VTOTAL 0x6000c +#define INTEL_DISPLAY_VBLANK 0x60010 +#define INTEL_DISPLAY_VSYNC 0x60014 +#define INTEL_DISPLAY_IMAGE_SIZE 0x6001c + +#define INTEL_DISPLAY_CONTROL 0x70180 +#define INTEL_DISPLAY_BASE 0x70184 +#define INTEL_DISPLAY_BYTES_PER_ROW 0x70188 +#define DISPLAY_CONTROL_ENABLED (1UL << 31) +#define DISPLAY_CONTROL_COLOR_MASK (0x0fUL << 26) +#define DISPLAY_CONTROL_CMAP8 (2UL << 26) +#define DISPLAY_CONTROL_RGB15 (4UL << 26) +#define DISPLAY_CONTROL_RGB16 (5UL << 26) +#define DISPLAY_CONTROL_RGB32 (7UL << 26) + +#define INTEL_DISPLAY_PIPE_CONTROL 0x70008 +#define DISPLAY_PIPE_ENABLED (1UL << 31) + +#define INTEL_DISPLAY_PLL 0x06014 +#define INTEL_DISPLAY_PLL_DIVISOR_0 0x06040 +#define INTEL_DISPLAY_PLL_DIVISOR_1 0x06044 +#define DISPLAY_PLL_ENABLED (1UL << 31) +#define DISPLAY_PLL_2X_CLOCK (1UL << 30) +#define DISPLAY_PLL_SYNC_LOCK_ENABLED (1UL << 29) +#define DISPLAY_PLL_NO_VGA_CONTROL (1UL << 28) +#define DISPLAY_PLL_DIVIDE_4X (1UL << 23) +#define DISPLAY_PLL_POST_DIVISOR_MASK 0x001f0000 +#define DISPLAY_PLL_POST_DIVISOR_SHIFT 16 +#define DISPLAY_PLL_DIVISOR_1 (1UL << 8) +#define DISPLAY_PLL_N_DIVISOR_MASK 0x001f0000 +#define DISPLAY_PLL_M1_DIVISOR_MASK 0x00001f00 +#define DISPLAY_PLL_M2_DIVISOR_MASK 0x0000001f +#define DISPLAY_PLL_N_DIVISOR_SHIFT 16 +#define DISPLAY_PLL_M1_DIVISOR_SHIFT 8 +#define DISPLAY_PLL_M2_DIVISOR_SHIFT 0 + +#define INTEL_DISPLAY_ANALOG_PORT 0x61100 +#define DISPLAY_MONITOR_PORT_ENABLED (1UL << 31) +#define DISPLAY_MONITOR_VGA_POLARITY (1UL << 15) +#define DISPLAY_MONITOR_MODE_MASK (3UL << 10) +#define DISPLAY_MONITOR_ON 0 +#define DISPLAY_MONITOR_SUSPEND (1UL << 10) +#define DISPLAY_MONITOR_STAND_BY (2UL << 10) +#define DISPLAY_MONITOR_OFF (3UL << 10) +#define DISPLAY_MONITOR_POLARITY_MASK (3UL << 3) +#define DISPLAY_MONITOR_POSITIVE_HSYNC (1UL << 3) +#define DISPLAY_MONITOR_POSITIVE_VSYNC (2UL << 3) + +//---------------------------------------------------------- + +extern status_t intel_extreme_init(intel_info &info); +extern void intel_extreme_uninit(intel_info &info); + +#endif /* INTEL_EXTREME_H */ diff --git a/headers/private/graphics/intel_extreme/lock.h b/headers/private/graphics/intel_extreme/lock.h new file mode 100644 index 0000000000..3c11f24c02 --- /dev/null +++ b/headers/private/graphics/intel_extreme/lock.h @@ -0,0 +1,57 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef LOCK_H +#define LOCK_H + + +#include + + +typedef struct lock { + sem_id sem; + vint32 count; +} lock; + + +static inline status_t +init_lock(struct lock *lock, const char *name) +{ + lock->sem = create_sem(0, name); + lock->count = 0; + + return lock->sem < B_OK ? lock->sem : B_OK; +} + + +static inline void +uninit_lock(struct lock *lock) +{ + delete_sem(lock->sem); +} + + +static inline status_t +acquire_lock(struct lock *lock) +{ + if (atomic_add(&lock->count, 1) > 0) + return acquire_sem(lock->sem); + + return B_OK; +} + + +static inline status_t +release_lock(struct lock *lock) +{ + if (atomic_add(&lock->count, -1) > 1) + return release_sem(lock->sem); + + return B_OK; +} + +#endif /* LOCK_H */ diff --git a/headers/private/graphics/intel_extreme/utility.h b/headers/private/graphics/intel_extreme/utility.h new file mode 100644 index 0000000000..eae3c06660 --- /dev/null +++ b/headers/private/graphics/intel_extreme/utility.h @@ -0,0 +1,13 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef UTILITY_H +#define UTILITY_H + +#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1)) + +#endif /* UTILITY_H */ diff --git a/src/add-ons/accelerants/Jamfile b/src/add-ons/accelerants/Jamfile index 61031b11d3..923283b154 100644 --- a/src/add-ons/accelerants/Jamfile +++ b/src/add-ons/accelerants/Jamfile @@ -2,6 +2,7 @@ SubDir HAIKU_TOP src add-ons accelerants ; SubInclude HAIKU_TOP src add-ons accelerants common ; SubInclude HAIKU_TOP src add-ons accelerants et6x00 ; +SubInclude HAIKU_TOP src add-ons accelerants intel_extreme ; SubInclude HAIKU_TOP src add-ons accelerants matrox ; SubInclude HAIKU_TOP src add-ons accelerants neomagic ; SubInclude HAIKU_TOP src add-ons accelerants nvidia ; diff --git a/src/add-ons/accelerants/intel_extreme/Jamfile b/src/add-ons/accelerants/intel_extreme/Jamfile new file mode 100644 index 0000000000..195a98490c --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/Jamfile @@ -0,0 +1,17 @@ +SubDir HAIKU_TOP src add-ons accelerants intel_extreme ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics intel_extreme ] ; +UsePrivateHeaders [ FDirName graphics common ] ; + +Addon intel_extreme.accelerant : accelerants : + accelerant.cpp + dpms.cpp + engine.cpp + hooks.cpp + mode.cpp + : false + : be +; diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.cpp b/src/add-ons/accelerants/intel_extreme/accelerant.cpp new file mode 100644 index 0000000000..9afa155f8e --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -0,0 +1,274 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "accelerant_protos.h" +#include "accelerant.h" + +#include +#include +#include +#include + + +#define TRACE_ACCELERANT +#ifdef TRACE_ACCELERANT +extern "C" void _sPrintf(const char *format, ...); +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +struct accelerant_info *gInfo; + + +class AreaCloner { + public: + AreaCloner(); + ~AreaCloner(); + + area_id Clone(const char *name, void **_address, uint32 spec, + uint32 protection, area_id sourceArea); + status_t InitCheck() { return fArea < B_OK ? (status_t)fArea : B_OK; } + void Keep(); + + private: + area_id fArea; +}; + + +AreaCloner::AreaCloner() + : + fArea(-1) +{ +} + + +AreaCloner::~AreaCloner() +{ + if (fArea >= B_OK) + delete_area(fArea); +} + + +area_id +AreaCloner::Clone(const char *name, void **_address, uint32 spec, + uint32 protection, area_id sourceArea) +{ + fArea = clone_area(name, _address, spec, protection, sourceArea); + return fArea; +} + + +void +AreaCloner::Keep() +{ + fArea = -1; +} + + +// #pragma mark - + + +/** This is the common accelerant_info initializer. It is called by + * both, the first accelerant and all clones. + */ + +static status_t +init_common(int device, bool isClone) +{ + // initialize global accelerant info structure + + gInfo = (accelerant_info *)malloc(sizeof(accelerant_info)); + if (gInfo == NULL) + return B_NO_MEMORY; + + memset(gInfo, 0, sizeof(accelerant_info)); + + gInfo->is_clone = isClone; + gInfo->device = device; + + // get basic info from driver + + intel_get_private_data data; + data.magic = INTEL_PRIVATE_DATA_MAGIC; + + if (ioctl(device, INTEL_GET_PRIVATE_DATA, &data, sizeof(intel_get_private_data)) != 0) { + free(gInfo); + return B_ERROR; + } + + AreaCloner sharedCloner; + gInfo->shared_info_area = sharedCloner.Clone("intel extreme shared info", + (void **)&gInfo->shared_info, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, + data.shared_info_area); + status_t status = sharedCloner.InitCheck(); + if (status < B_OK) { + free(gInfo); + return status; + } + + AreaCloner regsCloner; + gInfo->regs_area = regsCloner.Clone("intel extreme regs", + (void **)&gInfo->regs, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, + gInfo->shared_info->registers_area); + status = regsCloner.InitCheck(); + if (status < B_OK) { + free(gInfo); + return status; + } + + sharedCloner.Keep(); + regsCloner.Keep(); + + return B_OK; +} + + +/** Clean up data common to both primary and cloned accelerant */ + +static void +uninit_common(void) +{ + delete_area(gInfo->regs_area); + delete_area(gInfo->shared_info_area); + + gInfo->regs_area = gInfo->shared_info_area = -1; + + gInfo->regs = NULL; + 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); + + free(gInfo); +} + + +// #pragma mark - public accelerant functions + + +/** Init primary accelerant */ + +status_t +intel_init_accelerant(int device) +{ + syslog(LOG_ERR, "intel_extreme.accelerant here!\n"); + + status_t status = init_common(device, false); + if (status != B_OK) + return status; + + status = create_mode_list(); + if (status != B_OK) { + uninit_common(); + return status; + } + + return B_OK; +} + + +ssize_t +intel_accelerant_clone_info_size(void) +{ + // clone info is device name, so return its maximum size + return B_PATH_NAME_LENGTH; +} + + +void +intel_get_accelerant_clone_info(void *info) +{ + ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); +} + + +status_t +intel_clone_accelerant(void *info) +{ + TRACE(("intel_clone_accelerant()\n")); + + // create full device name + char path[B_PATH_NAME_LENGTH]; + strcpy(path, "/dev/"); +#ifdef __HAIKU__ + strlcat(path, (const char *)info, sizeof(path)); +#else + strcat(path, (const char *)info); +#endif + + int fd = open(path, B_READ_WRITE); + if (fd < 0) + return fd; + + status_t status = init_common(fd, true); + if (status != B_OK) + goto err1; + + // get read-only clone of supported display modes + status = gInfo->mode_list_area = clone_area( + "intel extreme cloned modes", (void **)&gInfo->mode_list, + B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); + if (status < B_OK) + goto err2; + + return B_OK; + +err2: + uninit_common(); +err1: + close(fd); + return status; +} + + +/** This function is called for both, the primary accelerant and all of + * its clones. + */ + +void +intel_uninit_accelerant(void) +{ + TRACE(("intel_uninit_accelerant()\n")); + + // delete accelerant instance data + delete_area(gInfo->mode_list_area); + gInfo->mode_list = NULL; + + uninit_common(); +} + + +status_t +intel_get_accelerant_device_info(accelerant_device_info *info) +{ + info->version = B_ACCELERANT_VERSION; + strcpy(info->name, "Intel Extreme Graphics 2"); + strcpy(info->chipset, "i865G"); + // TODO: provide some more insight here once we support more than that one chip... + strcpy(info->serial_no, "None"); + + info->memory = gInfo->shared_info->graphics_memory_size; + info->dac_speed = gInfo->shared_info->pll_info.max_frequency; + + return B_OK; +} + + +sem_id +intel_accelerant_retrace_semaphore() +{ + return -1; +} + diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.h b/src/add-ons/accelerants/intel_extreme/accelerant.h new file mode 100644 index 0000000000..a35fa9b222 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/accelerant.h @@ -0,0 +1,53 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef INTEL_EXTREME_ACCELERANT_H +#define INTEL_EXTREME_ACCELERANT_H + + +#include "intel_extreme.h" + + +typedef struct accelerant_info { + vuint8 *regs; + area_id regs_area; + + intel_shared_info *shared_info; + area_id shared_info_area; + + display_mode *mode_list; // cloned list of standard display modes + area_id mode_list_area; + + int device; + bool is_clone; +} accelerant_info; + +extern accelerant_info *gInfo; + +// register access + +inline uint32 +read32(uint32 offset) +{ + return *(volatile uint32 *)(gInfo->regs + offset); +} + +inline void +write32(uint32 offset, uint32 value) +{ + *(volatile uint32 *)(gInfo->regs + offset) = value; +} + + +// dpms.cpp +extern void enable_display_plane(bool enable); +extern void set_display_power_mode(uint32 mode); + +// modes.cpp +extern status_t create_mode_list(void); + +#endif /* INTEL_EXTREME_ACCELERANT_H */ diff --git a/src/add-ons/accelerants/intel_extreme/accelerant_protos.h b/src/add-ons/accelerants/intel_extreme/accelerant_protos.h new file mode 100644 index 0000000000..f3c04bb065 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/accelerant_protos.h @@ -0,0 +1,87 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef ACCELERANT_PROTOS_H +#define ACCELERANT_PROTOS_H + + +#include +#include "video_overlay.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +// general +status_t intel_init_accelerant(int fd); +ssize_t intel_accelerant_clone_info_size(void); +void intel_get_accelerant_clone_info(void *data); +status_t intel_clone_accelerant(void *data); +void intel_uninit_accelerant(void); +status_t intel_get_accelerant_device_info(accelerant_device_info *info); +sem_id intel_accelerant_retrace_semaphore(void); + +// modes & constraints +uint32 intel_accelerant_mode_count(void); +status_t intel_get_mode_list(display_mode *dm); +status_t intel_propose_display_mode(display_mode *target, const display_mode *low, + const display_mode *high); +status_t intel_set_display_mode(display_mode *mode); +status_t intel_get_display_mode(display_mode *currentMode); +status_t intel_get_frame_buffer_config(frame_buffer_config *config); +status_t intel_get_pixel_clock_limits(display_mode *mode, uint32 *low, uint32 *high); +status_t intel_move_display(uint16 hDisplayStart, uint16 vDisplayStart); +status_t intel_get_timing_constraints(display_timing_constraints *constraints); +void intel_set_indexed_colors(uint count, uint8 first, uint8 *colorData, uint32 flags); + +// DPMS +uint32 intel_dpms_capabilities(void); +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, + uint8 *andMask, uint8 *xorMask); +void intel_move_cursor(uint16 x, uint16 y); +void intel_show_cursor(bool isVisible); + +// accelerant engine +uint32 intel_accelerant_engine_count(void); +status_t intel_acquire_engine(uint32 capabilities, uint32 maxWait, + sync_token *syncToken, engine_token **_engineToken); +status_t intel_release_engine(engine_token *engineToken, sync_token *syncToken); +void intel_wait_engine_idle(void); +status_t intel_get_sync_token(engine_token *engineToken, sync_token *syncToken); +status_t intel_sync_to_token(sync_token *syncToken); + +// 2D acceleration +void intel_screen_to_screen_blit(engine_token *engineToken, blit_params *list, uint32 count); +void intel_fill_rectangle(engine_token *engineToken, uint32 color, fill_rect_params *list, + uint32 count); +void intel_invert_rectangle(engine_token *engineToken, fill_rect_params *list, uint32 count); +void intel_fill_span(engine_token *engineToken, uint32 color, uint16 *list, uint32 count); + +// overlay +uint32 intel_overlay_count(const display_mode *dm); +const uint32 *intel_overlay_supported_spaces(const display_mode *dm); +uint32 intel_overlay_supported_features(uint32 a_color_space); +const overlay_buffer *intel_allocate_overlay_buffer(color_space space, uint16 width, + uint16 height); +status_t intel_release_overlay_buffer(const overlay_buffer *buffer); +status_t intel_get_overlay_constraints(const display_mode *mode, const overlay_buffer *buffer, + overlay_constraints *constraints); +overlay_token intel_allocate_overlay(void); +status_t intel_release_overlay(overlay_token overlayToken); +status_t intel_configure_overlay(overlay_token overlayToken, const overlay_buffer *buffer, + const overlay_window *window, const overlay_view *view); + +#ifdef __cplusplus +} +#endif + +#endif /* ACCELERANT_PROTOS_H */ diff --git a/src/add-ons/accelerants/intel_extreme/dpms.cpp b/src/add-ons/accelerants/intel_extreme/dpms.cpp new file mode 100644 index 0000000000..d6addf3ef9 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/dpms.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "accelerant_protos.h" +#include "accelerant.h" + + +void +enable_display_plane(bool enable) +{ + uint32 oldValue = read32(INTEL_DISPLAY_CONTROL); + + if (enable) { + // when enabling the display, the register values are updated automatically + write32(INTEL_DISPLAY_CONTROL, oldValue | 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, 0); + } +} + + +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); +} + + +void +set_display_power_mode(uint32 mode) +{ + uint32 monitorMode = 0; + + if (mode == B_DPMS_ON) { + enable_display_pipe(true); + enable_display_plane(true); + } + + // TODO: wait for vblank! + snooze(10000); + + switch (mode) { + case B_DPMS_ON: + monitorMode = DISPLAY_MONITOR_ON; + break; + case B_DPMS_SUSPEND: + monitorMode = DISPLAY_MONITOR_SUSPEND; + break; + case B_DPMS_STAND_BY: + monitorMode = DISPLAY_MONITOR_STAND_BY; + break; + case B_DPMS_OFF: + monitorMode = DISPLAY_MONITOR_OFF; + 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 (mode != B_DPMS_ON) { + enable_display_plane(false); + enable_display_pipe(false); + } +} + + +// #pragma mark - + + +uint32 +intel_dpms_capabilities(void) +{ + return B_DPMS_ON | B_DPMS_SUSPEND | B_DPMS_STAND_BY | B_DPMS_OFF; +} + + +uint32 +intel_dpms_mode(void) +{ + return gInfo->shared_info->dpms_mode; +} + + +status_t +intel_set_dpms_mode(uint32 mode) +{ + gInfo->shared_info->dpms_mode = mode; + set_display_power_mode(mode); + + return B_OK; +} + diff --git a/src/add-ons/accelerants/intel_extreme/engine.cpp b/src/add-ons/accelerants/intel_extreme/engine.cpp new file mode 100644 index 0000000000..7017d78ce7 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/engine.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "accelerant_protos.h" +#include "intel_extreme.h" + + +static engine_token sEngineToken = {1, 0 /*B_2D_ACCELERATION*/, NULL}; + + +// public function: return number of hardware engine + +uint32 +intel_accelerant_engine_count(void) +{ + return 1; +} + + +status_t +intel_acquire_engine(uint32 capabilities, uint32 maxWait, sync_token *syncToken, + engine_token **_engineToken) +{ + *_engineToken = &sEngineToken; + + return B_OK; +} + + +status_t +intel_release_engine(engine_token *engineToken, sync_token *syncToken) +{ + if (syncToken != NULL) + syncToken->engine_id = engineToken->engine_id; + + return B_OK; +} + + +void +intel_wait_engine_idle(void) +{ +} + + +status_t +intel_get_sync_token(engine_token *engineToken, sync_token *syncToken) +{ + return B_OK; +} + + +status_t +intel_sync_to_token(sync_token *syncToken) +{ + return B_OK; +} + diff --git a/src/add-ons/accelerants/intel_extreme/hooks.cpp b/src/add-ons/accelerants/intel_extreme/hooks.cpp new file mode 100644 index 0000000000..4138812a67 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/hooks.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "accelerant_protos.h" + + +extern "C" void * +get_accelerant_hook(uint32 feature, void *data) +{ + switch (feature) { + /* general */ + case B_INIT_ACCELERANT: + return intel_init_accelerant; + case B_UNINIT_ACCELERANT: + return intel_uninit_accelerant; + case B_CLONE_ACCELERANT: + return intel_clone_accelerant; + case B_ACCELERANT_CLONE_INFO_SIZE: + return intel_accelerant_clone_info_size; + case B_GET_ACCELERANT_CLONE_INFO: + return intel_get_accelerant_clone_info; + case B_GET_ACCELERANT_DEVICE_INFO: + return intel_get_accelerant_device_info; + case B_ACCELERANT_RETRACE_SEMAPHORE: + return intel_accelerant_retrace_semaphore; + + /* mode configuration */ + case B_ACCELERANT_MODE_COUNT: + return intel_accelerant_mode_count; + case B_GET_MODE_LIST: + return intel_get_mode_list; + case B_PROPOSE_DISPLAY_MODE: + return intel_propose_display_mode; + case B_SET_DISPLAY_MODE: + return intel_set_display_mode; + case B_GET_DISPLAY_MODE: + return intel_get_display_mode; + case B_GET_FRAME_BUFFER_CONFIG: + return intel_get_frame_buffer_config; + case B_GET_PIXEL_CLOCK_LIMITS: + return intel_get_pixel_clock_limits; + case B_MOVE_DISPLAY: + return intel_move_display; + case B_SET_INDEXED_COLORS: + return intel_set_indexed_colors; + case B_GET_TIMING_CONSTRAINTS: + return intel_get_timing_constraints; + + /* DPMS */ + case B_DPMS_CAPABILITIES: + return intel_dpms_capabilities; + case B_DPMS_MODE: + return intel_dpms_mode; + case B_SET_DPMS_MODE: + return intel_set_dpms_mode; + + /* cursor managment */ +/* case B_SET_CURSOR_SHAPE: + return intel_set_cursor_shape; + case B_MOVE_CURSOR: + return intel_move_cursor; + case B_SHOW_CURSOR: + return intel_show_cursor; +*/ + /* engine/synchronization */ + case B_ACCELERANT_ENGINE_COUNT: + return intel_accelerant_engine_count; + case B_ACQUIRE_ENGINE: + return intel_acquire_engine; + case B_RELEASE_ENGINE: + return intel_release_engine; + case B_WAIT_ENGINE_IDLE: + return intel_wait_engine_idle; + case B_GET_SYNC_TOKEN: + return intel_get_sync_token; + case B_SYNC_TO_TOKEN: + return intel_sync_to_token; + + /* 2D acceleration */ +/* HOOK(SCREEN_TO_SCREEN_BLIT); + HOOK(FILL_RECTANGLE); + HOOK(INVERT_RECTANGLE); + HOOK(FILL_SPAN); +*/ + // overlay +/* HOOK(OVERLAY_COUNT); + HOOK(OVERLAY_SUPPORTED_SPACES); + HOOK(OVERLAY_SUPPORTED_FEATURES); + HOOK(ALLOCATE_OVERLAY_BUFFER); + HOOK(RELEASE_OVERLAY_BUFFER); + HOOK(GET_OVERLAY_CONSTRAINTS); + HOOK(ALLOCATE_OVERLAY); + HOOK(RELEASE_OVERLAY); + HOOK(CONFIGURE_OVERLAY); +*/ + } + + return NULL; +} + diff --git a/src/add-ons/accelerants/intel_extreme/mode.cpp b/src/add-ons/accelerants/intel_extreme/mode.cpp new file mode 100644 index 0000000000..1da38bef16 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/mode.cpp @@ -0,0 +1,390 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "accelerant_protos.h" +#include "accelerant.h" +#include "utility.h" + + +#define TRACE_MODE +#ifdef TRACE_MODE +extern "C" void _sPrintf(const char *format, ...); +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC) +#define MODE_FLAGS (B_8_BIT_DAC | /*B_HARDWARE_CURSOR |*/ B_PARALLEL_ACCESS | B_DPMS /*| B_SUPPORTS_OVERLAYS*/) + + +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, 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, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */ + {{27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */ + {{30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */ + {{31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */ + {{31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */ + {{36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */ + {{38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */ + {{40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */ + {{49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */ + {{50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */ + {{56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */ + {{65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */ + {{75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */ + {{78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */ + {{94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */ + {{94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ + {{108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */ + {{121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */ + {{108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */ + {{135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */ + {{157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */ + {{162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */ + {{175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */ + {{189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */ + {{202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */ + {{216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */ + {{229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */ +}; +static const uint32 kNumBaseModes = sizeof(kBaseModeList) / sizeof(display_mode); +static const uint32 kMaxNumModes = kNumBaseModes * 4; + + +/** Creates the initial mode list of the primary accelerant. + * It's called from intel_init_accelerant(). + */ + +status_t +create_mode_list(void) +{ + color_space spaces[4] = {B_RGB32_LITTLE, B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; + size_t size = ROUND_TO_PAGE_SIZE(kMaxNumModes * sizeof(display_mode)); + display_mode *list; + + gInfo->mode_list_area = create_area("intel extreme modes", (void **)&list, B_ANY_ADDRESS, + size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + if (gInfo->mode_list_area < B_OK) + return gInfo->mode_list_area; + + // for now, just copy all of the modes with different color spaces + + const display_mode *source = kBaseModeList; + uint32 count = 0; + + for (uint32 i = 0; i < kNumBaseModes; i++) { + for (uint32 j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++) { + list[count] = *source; + list[count].space = spaces[j]; + + count++; + } + + source++; + } + + gInfo->mode_list = list; + gInfo->shared_info->mode_list_area = gInfo->mode_list_area; + gInfo->shared_info->mode_count = count; + + return B_OK; +} + + +static void +compute_pll_divisors(const display_mode ¤t, uint32 &postDivisor, + uint32 &nDivisor, uint32 &m1Divisor, uint32 &m2Divisor) +{ + float requestedPixelClock = current.timing.pixel_clock / 1000.0f; + float referenceClock = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; + + TRACE(("required MHz: %g\n", requestedPixelClock)); + + float best = requestedPixelClock; + uint32 bestP = 0, bestN = 0, bestM = 0; + + // Note, the limits are taken from the X driver; they have not yet been tested + + for (uint32 p = 3; p < 31; p++) { + for (uint32 n = 3; n < 16; n++) { + for (uint32 m1 = 6; m1 < 26; m1++) { + for (uint32 m2 = 6; m2 < 16; m2++) { + uint32 m = m1 * 5 + m2; + float error = fabs(requestedPixelClock - ((referenceClock * m) / n) / (p*4)); + if (error < best) { + best = error; + bestP = p; + bestN = n; + bestM = m; + if (error == 0) + break; + } + } + } + } + } + + postDivisor = bestP; + nDivisor = bestN; + + TRACE(("found: %g MHz (p = %lu, n = %lu, m = %lu (m1 = %lu, m2 = %lu)\n", + ((referenceClock * bestM) / bestN) / (bestP*4), bestP, bestN, bestM, + m1Divisor, m2Divisor)); + + m1Divisor = bestM / 5; + m2Divisor = bestM % 5; + while (m2Divisor < 6) { + m1Divisor--; + m2Divisor += 5; + } +} + + +static void +get_color_space_format(const display_mode &mode, uint32 &colorMode, uint32 &bytesPerRow) +{ + uint32 bytesPerPixel; + + switch (mode.space) { + case B_RGB32_LITTLE: + colorMode = DISPLAY_CONTROL_RGB32; + bytesPerPixel = 4; + break; + case B_RGB16_LITTLE: + colorMode = DISPLAY_CONTROL_RGB16; + bytesPerPixel = 2; + break; + case B_RGB15_LITTLE: + colorMode = DISPLAY_CONTROL_RGB15; + bytesPerPixel = 2; + break; + case B_CMAP8: + default: + colorMode = DISPLAY_CONTROL_CMAP8; + bytesPerPixel = 1; + break; + } + + bytesPerRow = mode.virtual_width * bytesPerPixel; +} + + +// #pragma mark - + + +uint32 +intel_accelerant_mode_count(void) +{ + TRACE(("intel_accelerant_mode_count()\n")); + return gInfo->shared_info->mode_count; +} + + +status_t +intel_get_mode_list(display_mode *modeList) +{ + TRACE(("intel_get_mode_info()\n")); + memcpy(modeList, gInfo->mode_list, gInfo->shared_info->mode_count * sizeof(display_mode)); + return B_OK; +} + + +status_t +intel_propose_display_mode(display_mode *target, const display_mode *low, + const display_mode *high) +{ + TRACE(("intel_propose_display_mode()\n")); + + // just search for the specified mode in the list + + for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { + display_mode *current = &gInfo->mode_list[i]; + + // TODO: improve this, ie. adapt pixel clock to allowed values!!! + + if (target->virtual_width != current->virtual_width + || target->virtual_height != current->virtual_height + || target->space != current->space) + continue; + + *target = *current; + return B_OK; + } + return B_BAD_VALUE; +} + + +status_t +intel_set_display_mode(display_mode *mode) +{ + if (mode == NULL) + return B_BAD_VALUE; + + display_mode current = *mode; + + set_display_power_mode(B_DPMS_OFF); + + uint32 colorMode, bytesPerRow; + get_color_space_format(current, colorMode, bytesPerRow); + + // update timing parameters + + write32(INTEL_DISPLAY_HTOTAL, ((uint32)(current.timing.h_total - 1) << 16) + | ((uint32)current.timing.h_display - 1)); + write32(INTEL_DISPLAY_HBLANK, ((uint32)(current.timing.h_total - 1) << 16) + | ((uint32)current.timing.h_display - 1)); + write32(INTEL_DISPLAY_HSYNC, ((uint32)(current.timing.h_sync_end - 1) << 16) + | ((uint32)current.timing.h_sync_start - 1)); + + write32(INTEL_DISPLAY_VTOTAL, ((uint32)(current.timing.v_total - 1) << 16) + | ((uint32)current.timing.v_display - 1)); + write32(INTEL_DISPLAY_VBLANK, ((uint32)(current.timing.v_total - 1) << 16) + | ((uint32)current.timing.v_display - 1)); + write32(INTEL_DISPLAY_VSYNC, ((uint32)(current.timing.v_sync_end - 1) << 16) + | ((uint32)current.timing.v_sync_start - 1)); + + write32(INTEL_DISPLAY_IMAGE_SIZE, ((uint32)(current.timing.h_display - 1) << 16) + | ((uint32)current.timing.v_display - 1)); + + write32(INTEL_DISPLAY_ANALOG_PORT, (read32(INTEL_DISPLAY_ANALOG_PORT) + & ~(DISPLAY_MONITOR_POLARITY_MASK | DISPLAY_MONITOR_VGA_POLARITY)) + | ((current.timing.flags & B_POSITIVE_HSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_HSYNC : 0) + | ((current.timing.flags & B_POSITIVE_VSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_VSYNC : 0)); + + uint32 postDivisor, nDivisor, m1Divisor, m2Divisor; + compute_pll_divisors(current, 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; + + 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)); + +TRACE(("pll regs: %08lx, 0: %08lx, 1: %08lx\n", read32(INTEL_DISPLAY_PLL), + read32(INTEL_DISPLAY_PLL_DIVISOR_0), read32(INTEL_DISPLAY_PLL_DIVISOR_1))); +uint32 divisor = read32(divisorRegister); +TRACE((" POST %ld\n", + (read32(INTEL_DISPLAY_PLL) & DISPLAY_PLL_POST_DIVISOR_MASK) >> DISPLAY_PLL_POST_DIVISOR_SHIFT)); +TRACE((" 0: N %ld, M1 %ld, M2 %ld\n", + (divisor & DISPLAY_PLL_N_DIVISOR_MASK) >> DISPLAY_PLL_N_DIVISOR_SHIFT, + (divisor & DISPLAY_PLL_M1_DIVISOR_MASK) >> DISPLAY_PLL_M1_DIVISOR_SHIFT, + (divisor & DISPLAY_PLL_M2_DIVISOR_MASK) >> DISPLAY_PLL_M2_DIVISOR_SHIFT)); +divisor = read32(INTEL_DISPLAY_PLL_DIVISOR_1); +TRACE((" 1: N %ld, M1 %ld, M2 %ld\n", + (divisor & DISPLAY_PLL_N_DIVISOR_MASK) >> DISPLAY_PLL_N_DIVISOR_SHIFT, + (divisor & DISPLAY_PLL_M1_DIVISOR_MASK) >> DISPLAY_PLL_M1_DIVISOR_SHIFT, + (divisor & DISPLAY_PLL_M2_DIVISOR_MASK) >> DISPLAY_PLL_M2_DIVISOR_SHIFT)); + +uint32 n = ((divisor & DISPLAY_PLL_N_DIVISOR_MASK) >> DISPLAY_PLL_N_DIVISOR_SHIFT) + 2; +uint32 m1 = ((divisor & DISPLAY_PLL_M1_DIVISOR_MASK) >> DISPLAY_PLL_M1_DIVISOR_SHIFT) + 2; +uint32 m2 = ((divisor & DISPLAY_PLL_M2_DIVISOR_MASK) >> DISPLAY_PLL_M2_DIVISOR_SHIFT) + 2; +uint32 p = ((read32(INTEL_DISPLAY_PLL) & DISPLAY_PLL_POST_DIVISOR_MASK) >> DISPLAY_PLL_POST_DIVISOR_SHIFT) + 2; +//uint32 p2 = (read32(INTEL_DISPLAY_PLL) & DISPLAY_PLL_DIVIDE_4X) ? 2 : 1; +float clock = ((gInfo->shared_info->pll_info.reference_frequency / 1000.0f * (5*m1 + m2)) / n) / (p * 4); +TRACE((" n = %lu, m1 = %lu, m2 = %lu, p = %lu\n", n, m1, m2, p)); +TRACE((" Clock frequency: %g MHz\n", clock)); +TRACE((" h_total %ld, v_total %ld, refresh: %g\n", current.timing.h_total, current.timing.v_total, + clock * 1000000.0f / (current.timing.h_total * current.timing.v_total))); + + write32(INTEL_DISPLAY_CONTROL, (read32(INTEL_DISPLAY_CONTROL) + & ~DISPLAY_CONTROL_COLOR_MASK) | colorMode); + + set_display_power_mode(gInfo->shared_info->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, 0); + // triggers writing back double-buffered registers + + // update shared info + gInfo->shared_info->bytes_per_row = bytesPerRow; + gInfo->shared_info->current_mode = current; + + return B_OK; +} + + +status_t +intel_get_display_mode(display_mode *_currentMode) +{ + TRACE(("intel_get_display_mode()\n")); + *_currentMode = gInfo->shared_info->current_mode; + return B_OK; +} + + +status_t +intel_get_frame_buffer_config(frame_buffer_config *config) +{ + TRACE(("intel_get_frame_buffer_config()\n")); + + config->frame_buffer = gInfo->shared_info->frame_buffer; + config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer; + config->bytes_per_row = gInfo->shared_info->bytes_per_row; + + return B_OK; +} + + +status_t +intel_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high) +{ + TRACE(("intel_get_pixel_clock_limits()\n")); + + if (_low != NULL) { + // lower limit of about 48Hz vertical refresh + uint32 totalClocks = (uint32)mode->timing.h_total * (uint32)mode->timing.v_total; + uint32 low = (totalClocks * 48L) / 1000L; + if (low < gInfo->shared_info->pll_info.max_frequency) + low = gInfo->shared_info->pll_info.max_frequency; + else if (low > gInfo->shared_info->pll_info.max_frequency) + return B_ERROR; + + *_low = low; + } + + if (_high != NULL) + *_high = gInfo->shared_info->pll_info.max_frequency; + + return B_OK; +} + + +status_t +intel_move_display(uint16 horizontalStart, uint16 verticalStart) +{ + return B_ERROR; +} + + +status_t +intel_get_timing_constraints(display_timing_constraints *constraints) +{ + return B_ERROR; +} + + +void +intel_set_indexed_colors(uint count, uint8 first, uint8 *colorData, uint32 flags) +{ +} + diff --git a/src/add-ons/kernel/drivers/graphics/Jamfile b/src/add-ons/kernel/drivers/graphics/Jamfile index ce54ef93e5..0810dd48d0 100644 --- a/src/add-ons/kernel/drivers/graphics/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/Jamfile @@ -2,6 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics common ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics et6x00 ; +SubInclude HAIKU_TOP src add-ons kernel drivers graphics intel_extreme ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics matrox ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics neomagic ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics nvidia ; diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile b/src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile new file mode 100644 index 0000000000..1e59e38319 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile @@ -0,0 +1,19 @@ +SubDir HAIKU_TOP src add-ons kernel drivers graphics intel_extreme ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders [ FDirName graphics intel_extreme ] ; +UsePrivateHeaders [ FDirName graphics common ] ; +UsePrivateHeaders graphics kernel ; + +KernelAddon intel_extreme : kernel drivers bin : + driver.cpp + device.cpp + intel_extreme.cpp + + kernel_cpp.cpp +; + +SEARCH on [ FGristFiles + kernel_cpp.cpp + ] = [ FDirName $(HAIKU_TOP) src system kernel util ] ; diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/device.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/device.cpp new file mode 100644 index 0000000000..d947d730a5 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/device.cpp @@ -0,0 +1,237 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "driver.h" +#include "device.h" +#include "intel_extreme.h" +#include "utility.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define TRACE_DEVICE +#ifdef TRACE_DEVICE +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +/* device hooks prototypes */ + +static status_t device_open(const char *name, uint32 flags, void **_cookie); +static status_t device_close(void *data); +static status_t device_free(void *data); +static status_t device_ioctl(void *data, uint32 opcode, void *buffer, size_t length); +static status_t device_read(void *data, off_t offset, void *buffer, size_t *length); +static status_t device_write(void *data, off_t offset, const void *buffer, size_t *length); + + +device_hooks gDeviceHooks = { + device_open, + device_close, + device_free, + device_ioctl, + device_read, + device_write, + NULL, + NULL, + NULL, + NULL +}; + + +static status_t +checkDeviceInfo(struct intel_info *info) +{ + if (!info || info->cookie_magic != INTEL_COOKIE_MAGIC) + return B_BAD_VALUE; + + return B_OK; +} + + +// #pragma mark - Device Hooks + + +static status_t +device_open(const char *name, uint32 flags, void **_cookie) +{ + TRACE((DEVICE_NAME ": open(name = %s)\n", name)); + int32 id; + + // find accessed device + { + char *thisName; + + // search for device name + for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) { + if (!strcmp(name, thisName)) + break; + } + if (!thisName) + return B_BAD_VALUE; + } + intel_info *info = gDeviceInfo[id]; + *_cookie = info; + + acquire_lock(&gLock); + + status_t status = B_OK; + + if (info->open_count++ == 0) { + // this device has been opened for the first time, so + // we allocate needed resources and initialize the structure + + info->cookie_magic = INTEL_COOKIE_MAGIC; + info->id = id; + info->pci = gPCIInfo[id]; + info->registers = (uint8 *)gPCIInfo[id]->u.h0.base_registers[0]; + + status = intel_extreme_init(*info); + } + + release_lock(&gLock); + + return status; +} + + +static status_t +device_close(void *data) +{ + TRACE((DEVICE_NAME ": close\n")); + struct intel_info *info; + + if (checkDeviceInfo(info = (intel_info *)data) != B_OK) + return B_BAD_VALUE; + + info->cookie_magic = INTEL_FREE_COOKIE_MAGIC; + + return B_OK; +} + + +static status_t +device_free(void *data) +{ + struct intel_info *info = (intel_info *)data; + status_t retval = B_NO_ERROR; + + if (info == NULL || info->cookie_magic != INTEL_FREE_COOKIE_MAGIC) + retval = B_BAD_VALUE; + + acquire_lock(&gLock); + + if (info->open_count-- == 1) { + // release info structure + info->cookie_magic = 0; + intel_extreme_uninit(*info); + } + + release_lock(&gLock); + + return retval; +} + + +static status_t +device_ioctl(void *data, uint32 op, void *buffer, size_t bufferLength) +{ + struct intel_info *info; + + if (checkDeviceInfo(info = (intel_info *)data) != B_OK) + return B_BAD_VALUE; + + switch (op) { + case B_GET_ACCELERANT_SIGNATURE: + strcpy((char *)buffer, INTEL_ACCELERANT_NAME); + TRACE((DEVICE_NAME ": accelerant: %s\n", INTEL_ACCELERANT_NAME)); + return B_OK; + + // needed to share data between kernel and accelerant + case INTEL_GET_PRIVATE_DATA: + { + intel_get_private_data *data = (intel_get_private_data *)buffer; + + if (data->magic == INTEL_PRIVATE_DATA_MAGIC) { + data->shared_info_area = info->shared_area; + return B_OK; + } + break; + } + + // needed for cloning + case INTEL_GET_DEVICE_NAME: +#ifdef __HAIKU__ + if (user_strlcpy((char *)buffer, gDeviceNames[info->id], B_PATH_NAME_LENGTH) < B_OK) + return B_BAD_ADDRESS; +#else + strncpy((char *)buffer, gDeviceNames[info->id], B_PATH_NAME_LENGTH); + ((char *)buffer)[B_PATH_NAME_LENGTH - 1] = '\0'; +#endif + return B_OK; + +/* + // graphics mem manager + case INTEL_ALLOC_LOCAL_MEMORY: + { + intel_alloc_local_mem *allocMemory = (intel_alloc_local_mem *)buffer; + + if (allocMemory->magic == INTEL_PRIVATE_DATA_MAGIC) { + return mem_alloc(di->local_memmgr, allocMemory->size, dev, + &allocMemory->handle, &am->fb_offset); + } + break; + } + + case INTEL_FREE_LOCAL_MEMORY: + { + intel_free_local_mem *freeMemory = (intel_free_local_mem *)buffer; + + if (freeMemory->magic == INTEL_PRIVATE_DATA_MAGIC) + return mem_free(di->local_memmgr, freeMemory->handle, dev); + break; + } +*/ + + default: + TRACE((DEVICE_NAME ": ioctl() unknown message %ld (length = %ld)\n", + op, bufferLength)); + break; + } + + return B_DEV_INVALID_IOCTL; +} + + +static status_t +device_read(void */*data*/, off_t /*pos*/, void */*buffer*/, size_t *_length) +{ + *_length = 0; + return B_NOT_ALLOWED; +} + + +static status_t +device_write(void */*data*/, off_t /*pos*/, const void */*buffer*/, size_t *_length) +{ + *_length = 0; + return B_NOT_ALLOWED; +} + diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/device.h b/src/add-ons/kernel/drivers/graphics/intel_extreme/device.h new file mode 100644 index 0000000000..5b0fe46e4e --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/device.h @@ -0,0 +1,18 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef DEVICE_H +#define DEVICE_H + + +#include + + +/* The published PCI bus interface device hooks */ +extern device_hooks gDeviceHooks; + +#endif /* DEVICE_H */ diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp new file mode 100644 index 0000000000..602c523345 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp @@ -0,0 +1,209 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "driver.h" +#include "device.h" +#include "lock.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define TRACE_DRIVER +#ifdef TRACE_DRIVER +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + +#define MAX_CARDS 4 + +int32 api_version = B_CUR_DRIVER_API_VERSION; + +char *gDeviceNames[MAX_CARDS + 1]; +intel_info *gDeviceInfo[MAX_CARDS]; +pci_info *gPCIInfo[MAX_CARDS]; +pci_module_info *gPCI; +lock gLock; + + +extern "C" { + status_t init_hardware(void); + status_t init_driver(void); + void uninit_driver(void); + const char **publish_devices(void); + device_hooks *find_device(const char *name); +} + + +static status_t +get_next_intel_extreme(int32 *_cookie, pci_info &info) +{ + int32 index = *_cookie; + + // find devices + for (; gPCI->get_nth_pci_info(index, &info) == B_OK; index++) { + if (info.vendor_id == VENDOR_ID_INTEL + && info.device_id == DEVICE_ID_i865) { + *_cookie = index + 1; + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +const char ** +publish_devices(void) +{ + TRACE((DEVICE_NAME ": publish_devices()\n")); + return (const char **)gDeviceNames; +} + + +status_t +init_hardware(void) +{ + status_t status; + + TRACE((DEVICE_NAME ": init_hardware()\n")); + + if ((status = get_module(B_PCI_MODULE_NAME,(module_info **)&gPCI)) != B_OK) { + TRACE((DEVICE_NAME ": pci module unavailable\n")); + return status; + } + + int32 cookie = 0; + pci_info info; + status = get_next_intel_extreme(&cookie, info); +dprintf("found: %s\n", strerror(status)); + + put_module(B_PCI_MODULE_NAME); + return status; +} + + +status_t +init_driver(void) +{ + status_t status; + TRACE((DEVICE_NAME ": init_driver()\n")); + + if ((status = get_module(B_PCI_MODULE_NAME,(module_info **)&gPCI)) != B_OK) { + TRACE((DEVICE_NAME ": pci module unavailable\n")); + return status; + } + + // find devices + + int32 found = 0; + + for (int32 cookie = 0; found < MAX_CARDS;) { + pci_info *info = (pci_info *)malloc(sizeof(pci_info)); + status = get_next_intel_extreme(&cookie, *info); + if (status < B_OK) { + free(info); + break; + } + + // enable bus mastering for device +// pci->write_pci_config(info->bus, info->device, info->function, +// PCI_command, 2, +// PCI_command_master | pci->read_pci_config( +// info->bus, info->device, info->function, +// PCI_command, 2)); + + gPCIInfo[found++] = info; + dprintf(DEVICE_NAME ": (%ld) revision = 0x%x\n", found, info->revision); + } + + if (found == 0) { + put_module(B_PCI_MODULE_NAME); + return ENODEV; + } + + // create device name list & allocate device info structure + { + int32 index = 0; + char name[64]; + + for (; index < found; index++) { + pci_info *info = gPCIInfo[index]; + sprintf(name, "graphics/%04X_%04X_%02X%02X%02X", + info->vendor_id, info->device_id, + info->bus, info->device, + info->function); + gDeviceNames[index] = strdup(name); + + if ((gDeviceInfo[index] = (intel_info *)malloc(sizeof(intel_info))) != NULL) + memset(gDeviceInfo[index], 0, sizeof(intel_info)); + else + free(gDeviceNames[index]); + } + gDeviceNames[index] = NULL; + } + + return init_lock(&gLock, "intel extreme ksync"); +} + + +void +uninit_driver(void) +{ + TRACE((DEVICE_NAME ": uninit_driver()\n")); + + uninit_lock(&gLock); + + // free device related structures + char *name; + for (int32 index = 0; (name = gDeviceNames[index]) != NULL; index++) { + free(gDeviceInfo[index]); + free(gPCIInfo[index]); + free(name); + } + + put_module(B_PCI_MODULE_NAME); +} + + +device_hooks * +find_device(const char *name) +{ + int index; + + TRACE((DEVICE_NAME ": find_device()\n")); + + for (index = 0; gDeviceNames[index] != NULL; index++) + if (!strcmp(name, gDeviceNames[index])) + return &gDeviceHooks; + + return NULL; +} + +/* +void +wake_driver(void) +{ + // for compatibility with Dano, only +} + + +void +suspend_driver(void) +{ + // for compatibility with Dano, only +} +*/ diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.h b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.h new file mode 100644 index 0000000000..dc7ae5b8a3 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.h @@ -0,0 +1,60 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef DRIVER_H +#define DRIVER_H + + +#include +#include + +#include "intel_extreme.h" +#include "lock.h" + +// PCI Communications + +#define IO_PORT_PCI_ACCESS true +//#define MEMORY_MAPPED_PCI_ACCESS true + +#if IO_PORT_PCI_ACCESS +# define write8(address,value) (*pci->write_io_8)((address),(value)) +# define write16(address,value) (*pci->write_io_16)((address),(value)) +# define write32(address,value) (*pci->write_io_32)((address),(value)) +# define read8(address) ((*pci->read_io_8)(address)) +# define read16(address) ((*pci->read_io_16)(address)) +# define read32(address) ((*pci->read_io_32)(address)) +#else /* MEMORY_MAPPED_PCI_ACCESS */ +# define read8(address) (*((volatile uint8*)(address))) +# define read16(address) (*((volatile uint16*)(address))) +# define read32(address) (*((volatile uint32*)(address))) +# define write8(address,data) (*((volatile uint8 *)(address)) = data) +# define write16(address,data) (*((volatile uint16 *)(address)) = (data)) +# define write32(address,data) (*((volatile uint32 *)(address)) = (data)) +#endif + + +extern char *gDeviceNames[]; +extern intel_info *gDeviceInfo[]; +extern pci_info *gPCIInfo[]; +extern pci_module_info *gPCI; +extern struct lock gLock; + + +static inline uint32 +get_pci_config(pci_info *info, uint8 offset, uint8 size) +{ + return gPCI->read_pci_config(info->bus, info->device, info->function, offset, size); +} + + +static inline void +set_pci_config(pci_info *info, uint8 offset, uint8 size, uint32 value) +{ + gPCI->write_pci_config(info->bus, info->device, info->function, offset, size, value); +} + +#endif /* DRIVER_H */ 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 new file mode 100644 index 0000000000..44edcb7c6e --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp @@ -0,0 +1,197 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "intel_extreme.h" +#include "driver.h" +#include "utility.h" + +#include + +#include +#include +#include +#include + +// ToDo: do this correctly +extern "C" void write_isa_io(uchar bus, uchar port, uchar offset); +extern "C" uchar read_isa_io(uchar bus, uchar port, uchar offset); + + +class PhysicalMemoryMapper { + public: + PhysicalMemoryMapper(); + ~PhysicalMemoryMapper(); + + area_id Map(const char *name, void *physicalAddress, size_t numBytes, + uint32 spec, uint32 protection, void **virtualAddress); + status_t InitCheck() { return fArea < B_OK ? (status_t)fArea : B_OK; } + void Keep(); + + private: + area_id fArea; +}; + + +PhysicalMemoryMapper::PhysicalMemoryMapper() + : + fArea(-1) +{ +} + + +PhysicalMemoryMapper::~PhysicalMemoryMapper() +{ + if (fArea >= B_OK) + delete_area(fArea); +} + + +area_id +PhysicalMemoryMapper::Map(const char *name, void *physicalAddress, size_t numBytes, + uint32 spec, uint32 protection, void **virtualAddress) +{ + fArea = map_physical_memory(name, physicalAddress, numBytes, spec, protection, virtualAddress); + return fArea; +} + + +void +PhysicalMemoryMapper::Keep() +{ + fArea = -1; +} + + +// #pragma mark - + + +#define DUMPED_BLOCK_SIZE 16 + +void +dumpBlock(int file, const uint8 *buffer, int size) +{ + int i; + + for (i = 0; i < size;) { + int start = i; + char line[512]; + + int pos = sprintf(line, "%06x: ", start); + + for (; i < start+DUMPED_BLOCK_SIZE; i++) { + if (!(i % 4)) + pos += snprintf(line + pos, sizeof(line) - pos, " "); + + if (i >= size) + break; + + pos += snprintf(line + pos, sizeof(line) - pos, "%02x", + *(buffer + i)); + } + pos += snprintf(line + pos, sizeof(line) - pos, "\n"); + write(file, line, pos); + } +} + + +status_t +intel_extreme_init(intel_info &info) +{ + info.shared_area = create_area("intel extreme shared info", + (void **)&info.shared_info, B_ANY_KERNEL_ADDRESS, + ROUND_TO_PAGE_SIZE(sizeof(intel_shared_info)), + B_FULL_LOCK, 0); + if (info.shared_area < B_OK) + return info.shared_area; + + memset((void *)info.shared_info, 0, sizeof(intel_shared_info)); + + // get chipset info + + // TODO: read this out of the PCI configuration of the PCI bridge + size_t memorySize = 8 * 1024 * 1024; + + // map frame buffer, try to map it write combined + + PhysicalMemoryMapper fbMapper; + info.frame_buffer_area = fbMapper.Map("intel extreme frame buffer", + (void *)info.pci->u.h0.base_registers[0], + memorySize, B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, + B_READ_AREA | B_WRITE_AREA, (void **)&info.frame_buffer); + if (fbMapper.InitCheck() < B_OK) { + // try again without write combining + dprintf(DEVICE_NAME ": enabling write combined mode failed.\n"); + + info.frame_buffer_area = fbMapper.Map("intel extreme frame buffer", + (void *)info.pci->u.h0.base_registers[0], + memorySize/*info.pci->u.h0.base_register_sizes[0]*/, B_ANY_KERNEL_BLOCK_ADDRESS, + B_READ_AREA | B_WRITE_AREA, (void **)&info.frame_buffer); + } + if (fbMapper.InitCheck() < B_OK) { + dprintf(DEVICE_NAME ": could not map frame buffer!\n"); + return info.frame_buffer_area; + } + + // memory mapped I/O + + PhysicalMemoryMapper mmioMapper; + 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); + if (mmioMapper.InitCheck() < B_OK) { + dprintf(DEVICE_NAME ": could not map memory I/O!\n"); + return info.registers_area; + } + +#if 0 +// dump registers to a file +int file = open("/boot/home/intel_extreme_registers", O_CREAT | O_TRUNC | O_WRONLY, 0666); +if (file >= 0) { + dumpBlock(file, info.registers, info.pci->u.h0.base_register_sizes[1]); + close(file); + sync(); +} else + dprintf("intel_extreme: could not log (%s)!!\n", strerror(errno)); +#endif + + // no errors, so keep mappings + fbMapper.Keep(); + mmioMapper.Keep(); + + info.shared_info->frame_buffer_area = info.frame_buffer_area; + info.shared_info->registers_area = info.registers_area; + info.shared_info->frame_buffer = info.frame_buffer; + info.shared_info->physical_frame_buffer = (uint8 *)info.pci->u.h0.base_registers[0]; + + info.shared_info->graphics_memory_size = memorySize; + info.shared_info->dpms_mode = B_DPMS_ON; + info.shared_info->pll_info.reference_frequency = 48000; // 48 kHz + info.shared_info->pll_info.min_frequency = 100000; // 100 MHz (not tested) + info.shared_info->pll_info.max_frequency = 350000; // 350 MHz RAM DAC speed + info.shared_info->pll_info.divisor_register = INTEL_DISPLAY_PLL_DIVISOR_0; + + dprintf(DEVICE_NAME "intel_extreme_init() completed successfully!\n"); + + return B_OK; +} + + +void +intel_extreme_uninit(intel_info &info) +{ + dprintf(DEVICE_NAME": intel_extreme_uninit()\n"); + + delete_area(info.frame_buffer_area); + delete_area(info.registers_area); + delete_area(info.shared_area); +} +