From a90ebd77eeae5eca9600d039dc1298898e38278a Mon Sep 17 00:00:00 2001 From: Clemens Zeidler Date: Tue, 13 Apr 2010 22:35:53 +0000 Subject: [PATCH] Work in progress of a Radeon HD 3200 driver to change the display mode (status when I leave the coding spring). At least it shows a picture but with a wrong scaling. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36243 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../private/graphics/radeon_hd/AreaKeeper.h | 75 ++ headers/private/graphics/radeon_hd/lock.h | 84 +++ .../private/graphics/radeon_hd/radeon_hd.h | 655 ++++++++++++++++++ headers/private/graphics/radeon_hd/utility.h | 13 + src/add-ons/accelerants/Jamfile | 1 + .../accelerants/intel_extreme/accelerant.cpp | 16 - .../intel_extreme/accelerant_protos.h | 10 +- src/add-ons/accelerants/radeon_hd/Jamfile | 21 + .../accelerants/radeon_hd/accelerant.cpp | 289 ++++++++ .../accelerants/radeon_hd/accelerant.h | 66 ++ .../accelerants/radeon_hd/accelerant_protos.h | 49 ++ src/add-ons/accelerants/radeon_hd/engine.cpp | 57 ++ src/add-ons/accelerants/radeon_hd/hooks.cpp | 57 ++ src/add-ons/accelerants/radeon_hd/memory.cpp | 57 ++ src/add-ons/accelerants/radeon_hd/mode.cpp | 361 ++++++++++ src/add-ons/kernel/drivers/graphics/Jamfile | 1 + .../kernel/drivers/graphics/radeon_hd/Jamfile | 24 + .../drivers/graphics/radeon_hd/device.cpp | 272 ++++++++ .../drivers/graphics/radeon_hd/device.h | 18 + .../drivers/graphics/radeon_hd/driver.cpp | 228 ++++++ .../drivers/graphics/radeon_hd/driver.h | 54 ++ .../drivers/graphics/radeon_hd/radeon_hd.cpp | 293 ++++++++ .../graphics/radeon_hd/radeon_hd_private.h | 50 ++ 23 files changed, 2730 insertions(+), 21 deletions(-) create mode 100644 headers/private/graphics/radeon_hd/AreaKeeper.h create mode 100644 headers/private/graphics/radeon_hd/lock.h create mode 100644 headers/private/graphics/radeon_hd/radeon_hd.h create mode 100644 headers/private/graphics/radeon_hd/utility.h create mode 100644 src/add-ons/accelerants/radeon_hd/Jamfile create mode 100644 src/add-ons/accelerants/radeon_hd/accelerant.cpp create mode 100644 src/add-ons/accelerants/radeon_hd/accelerant.h create mode 100644 src/add-ons/accelerants/radeon_hd/accelerant_protos.h create mode 100644 src/add-ons/accelerants/radeon_hd/engine.cpp create mode 100644 src/add-ons/accelerants/radeon_hd/hooks.cpp create mode 100644 src/add-ons/accelerants/radeon_hd/memory.cpp create mode 100644 src/add-ons/accelerants/radeon_hd/mode.cpp create mode 100644 src/add-ons/kernel/drivers/graphics/radeon_hd/Jamfile create mode 100644 src/add-ons/kernel/drivers/graphics/radeon_hd/device.cpp create mode 100644 src/add-ons/kernel/drivers/graphics/radeon_hd/device.h create mode 100644 src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp create mode 100644 src/add-ons/kernel/drivers/graphics/radeon_hd/driver.h create mode 100644 src/add-ons/kernel/drivers/graphics/radeon_hd/radeon_hd.cpp create mode 100644 src/add-ons/kernel/drivers/graphics/radeon_hd/radeon_hd_private.h diff --git a/headers/private/graphics/radeon_hd/AreaKeeper.h b/headers/private/graphics/radeon_hd/AreaKeeper.h new file mode 100644 index 0000000000..2ca69bcd17 --- /dev/null +++ b/headers/private/graphics/radeon_hd/AreaKeeper.h @@ -0,0 +1,75 @@ +/* + * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef AREA_KEEPER_H +#define AREA_KEEPER_H + + +#include +#include + +#include + + +class AreaKeeper { + public: + AreaKeeper(); + ~AreaKeeper(); + + area_id Create(const char *name, void **_virtualAddress, uint32 spec, + size_t size, uint32 lock, uint32 protection); + 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 Detach(); + + private: + area_id fArea; +}; + + +AreaKeeper::AreaKeeper() + : + fArea(-1) +{ +} + + +AreaKeeper::~AreaKeeper() +{ + if (fArea >= B_OK) + delete_area(fArea); +} + + +area_id +AreaKeeper::Create(const char *name, void **_virtualAddress, uint32 spec, + size_t size, uint32 lock, uint32 protection) +{ + fArea = create_area(name, _virtualAddress, spec, size, lock, protection); + return fArea; +} + + +area_id +AreaKeeper::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 +AreaKeeper::Detach() +{ + fArea = -1; +} + +#endif // AREA_KEEPER_H diff --git a/headers/private/graphics/radeon_hd/lock.h b/headers/private/graphics/radeon_hd/lock.h new file mode 100644 index 0000000000..9c0f8423fa --- /dev/null +++ b/headers/private/graphics/radeon_hd/lock.h @@ -0,0 +1,84 @@ +/* + * 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; +} + + +class Autolock { + public: + Autolock(struct lock &lock) + : + fLock(&lock) + { + fStatus = acquire_lock(fLock); + } + + ~Autolock() + { + if (fStatus == B_OK) + release_lock(fLock); + } + + bool + IsLocked() const + { + return fStatus == B_OK; + } + + private: + status_t fStatus; + struct lock *fLock; +}; + +#endif /* LOCK_H */ diff --git a/headers/private/graphics/radeon_hd/radeon_hd.h b/headers/private/graphics/radeon_hd/radeon_hd.h new file mode 100644 index 0000000000..98c4bfe826 --- /dev/null +++ b/headers/private/graphics/radeon_hd/radeon_hd.h @@ -0,0 +1,655 @@ +/* + * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef RADEON_HD_H +#define RADEON_HD_H + + +#include "lock.h" + +#include +#include +#include + + +#define VENDOR_ID_ATI 0x8086 + +#define RADEON_TYPE_FAMILY_MASK 0xf000 +#define RADEON_TYPE_GROUP_MASK 0xfff0 +#define RADEON_TYPE_MODEL_MASK 0xffff +// families +#define RADEON_TYPE_7xx 0x1000 +#define RADEON_TYPE_8xx 0x2000 +#define RADEON_TYPE_9xx 0x4000 +// groups +#define RADEON_TYPE_83x (RADEON_TYPE_8xx | 0x0010) +#define RADEON_TYPE_85x (RADEON_TYPE_8xx | 0x0020) +#define RADEON_TYPE_91x (RADEON_TYPE_9xx | 0x0040) +#define RADEON_TYPE_94x (RADEON_TYPE_9xx | 0x0080) +#define RADEON_TYPE_96x (RADEON_TYPE_9xx | 0x0100) +#define RADEON_TYPE_Gxx (RADEON_TYPE_9xx | 0x0200) +#define RADEON_TYPE_G4x (RADEON_TYPE_9xx | 0x0400) +// models +#define RADEON_TYPE_MOBILE 0x0008 +#define RADEON_TYPE_915 (RADEON_TYPE_91x) +#define RADEON_TYPE_945 (RADEON_TYPE_94x) +#define RADEON_TYPE_945M (RADEON_TYPE_94x | RADEON_TYPE_MOBILE) +#define RADEON_TYPE_965 (RADEON_TYPE_96x) +#define RADEON_TYPE_965M (RADEON_TYPE_96x | RADEON_TYPE_MOBILE) +#define RADEON_TYPE_G33 (RADEON_TYPE_Gxx) +#define RADEON_TYPE_G45 (RADEON_TYPE_G4x) +#define RADEON_TYPE_GM45 (RADEON_TYPE_G4x | RADEON_TYPE_MOBILE) + +#define DEVICE_NAME "radeon_hd" +#define RADEON_ACCELERANT_NAME "radeon_hd.accelerant" + +struct DeviceType { + uint32 type; + + DeviceType(int t) + { + type = t; + } + + DeviceType& operator=(int t) + { + type = t; + return *this; + } + + bool InFamily(uint32 family) const + { + return (type & RADEON_TYPE_FAMILY_MASK) == family; + } + + bool InGroup(uint32 group) const + { + return (type & RADEON_TYPE_GROUP_MASK) == group; + } + + bool IsModel(uint32 model) const + { + return (type & RADEON_TYPE_MODEL_MASK) == model; + } +}; + +// info about PLL on graphics card +struct pll_info { + uint32 reference_frequency; + uint32 max_frequency; + uint32 min_frequency; + uint32 divisor_register; +}; + +struct ring_buffer { + struct lock lock; + uint32 register_base; + uint32 offset; + uint32 size; + uint32 position; + uint32 space_left; + uint8* base; +}; + +struct overlay_registers; + +struct radeon_shared_info { + area_id mode_list_area; // area containing display mode list + uint32 mode_count; + + display_mode current_mode; + uint32 bytes_per_row; + uint32 bits_per_pixel; + uint32 dpms_mode; + + area_id registers_area; // area of memory mapped registers + uint8* status_page; + addr_t physical_status_page; + uint8* graphics_memory; + addr_t physical_graphics_memory; + uint32 graphics_memory_size; + + addr_t frame_buffer; + uint32 frame_buffer_offset; + + struct lock accelerant_lock; + struct lock engine_lock; + + ring_buffer primary_ring_buffer; + + int32 overlay_channel_used; + bool overlay_active; + uint32 overlay_token; + addr_t physical_overlay_registers; + uint32 overlay_offset; + + bool hardware_cursor_enabled; + sem_id vblank_sem; + + uint8* cursor_memory; + addr_t physical_cursor_memory; + uint32 cursor_buffer_offset; + uint32 cursor_format; + bool cursor_visible; + uint16 cursor_hot_x; + uint16 cursor_hot_y; + + DeviceType device_type; + char device_identifier[32]; + struct pll_info pll_info; +}; + +//----------------- ioctl() interface ---------------- + +// magic code for ioctls +#define RADEON_PRIVATE_DATA_MAGIC 'rdhd' + +// list ioctls +enum { + RADEON_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, + + RADEON_GET_DEVICE_NAME, + RADEON_ALLOCATE_GRAPHICS_MEMORY, + RADEON_FREE_GRAPHICS_MEMORY +}; + +// retrieve the area_id of the kernel/accelerant shared info +struct radeon_get_private_data { + uint32 magic; // magic number + area_id shared_info_area; +}; + +// allocate graphics memory +struct radeon_allocate_graphics_memory { + uint32 magic; + uint32 size; + uint32 alignment; + uint32 flags; + uint32 buffer_base; +}; + +// free graphics memory +struct radeon_free_graphics_memory { + uint32 magic; + uint32 buffer_base; +}; + +//---------------------------------------------------------- +// Register definitions, taken from X driver + +// PCI bridge memory management +#define RADEON_GRAPHICS_MEMORY_CONTROL 0x52 // GGC - (G)MCH Graphics Control Register +#define MEMORY_CONTROL_ENABLED 0x0004 +#define MEMORY_MASK 0x0001 +#define STOLEN_MEMORY_MASK 0x00f0 +#define i965_GTT_MASK 0x000e +#define G33_GTT_MASK 0x0300 +#define G4X_GTT_MASK 0x0f00 // GGMS (GSM Memory Size) mask + +// models i830 and up +#define i830_LOCAL_MEMORY_ONLY 0x10 +#define i830_STOLEN_512K 0x20 +#define i830_STOLEN_1M 0x30 +#define i830_STOLEN_8M 0x40 +#define i830_FRAME_BUFFER_64M 0x01 +#define i830_FRAME_BUFFER_128M 0x00 + +// models i855 and up +#define i855_STOLEN_MEMORY_1M 0x10 +#define i855_STOLEN_MEMORY_4M 0x20 +#define i855_STOLEN_MEMORY_8M 0x30 +#define i855_STOLEN_MEMORY_16M 0x40 +#define i855_STOLEN_MEMORY_32M 0x50 +#define i855_STOLEN_MEMORY_48M 0x60 +#define i855_STOLEN_MEMORY_64M 0x70 +#define i855_STOLEN_MEMORY_128M 0x80 +#define i855_STOLEN_MEMORY_256M 0x90 + +#define G4X_STOLEN_MEMORY_96MB 0xa0 // GMS - Graphics Mode Select +#define G4X_STOLEN_MEMORY_160MB 0xb0 +#define G4X_STOLEN_MEMORY_224MB 0xc0 +#define G4X_STOLEN_MEMORY_352MB 0xd0 + + +// graphics page translation table +#define RADEON_PAGE_TABLE_CONTROL 0x02020 +#define PAGE_TABLE_ENABLED 0x00000001 +#define RADEON_PAGE_TABLE_ERROR 0x02024 +#define RADEON_HARDWARE_STATUS_PAGE 0x02080 +#define i915_GTT_BASE 0x1c +#define i830_GTT_BASE 0x10000 // (- 0x2ffff) +#define i830_GTT_SIZE 0x20000 +#define i965_GTT_BASE 0x80000 // (- 0xfffff) +#define i965_GTT_SIZE 0x80000 +#define i965_GTT_128K (2 << 1) +#define i965_GTT_256K (1 << 1) +#define i965_GTT_512K (0 << 1) +#define G33_GTT_1M (1 << 8) +#define G33_GTT_2M (2 << 8) +#define G4X_GTT_NONE 0x000 // GGMS - GSM Memory Size +#define G4X_GTT_1M_NO_IVT 0x100 // no Intel Virtualization Tech. +#define G4X_GTT_2M_NO_IVT 0x300 +#define G4X_GTT_2M_IVT 0x900 // with Intel Virt. Tech. +#define G4X_GTT_3M_IVT 0xa00 +#define G4X_GTT_4M_IVT 0xb00 + + +#define GTT_ENTRY_VALID 0x01 +#define GTT_ENTRY_LOCAL_MEMORY 0x02 +#define GTT_PAGE_SHIFT 12 + +// interrupts +#define RADEON_INTERRUPT_ENABLED 0x020a0 +#define RADEON_INTERRUPT_IDENTITY 0x020a4 +#define RADEON_INTERRUPT_MASK 0x020a8 +#define RADEON_INTERRUPT_STATUS 0x020ac +#define INTERRUPT_VBLANK (1 << 7) + +// ring buffer +#define RADEON_PRIMARY_RING_BUFFER 0x02030 +#define RADEON_SECONDARY_RING_BUFFER_0 0x02100 +#define RADEON_SECONDARY_RING_BUFFER_1 0x02110 +// offsets for the ring buffer base registers above +#define RING_BUFFER_TAIL 0x0 +#define RING_BUFFER_HEAD 0x4 +#define RING_BUFFER_START 0x8 +#define RING_BUFFER_CONTROL 0xc +#define RADEON_RING_BUFFER_SIZE_MASK 0x001ff000 +#define RADEON_RING_BUFFER_HEAD_MASK 0x001ffffc +#define RADEON_RING_BUFFER_ENABLED 1 + +// display ports +#define RADEON_DISPLAY_A_ANALOG_PORT 0x61100 +#define DISPLAY_MONITOR_PORT_ENABLED (1UL << 31) +#define DISPLAY_MONITOR_PIPE_B (1UL << 30) +#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) +#define RADEON_DISPLAY_A_DIGITAL_PORT 0x61120 +#define RADEON_DISPLAY_C_DIGITAL 0x61160 +#define RADEON_DISPLAY_LVDS_PORT 0x61180 +#define LVDS_POST2_RATE_SLOW 14 // PLL Divisors +#define LVDS_POST2_RATE_FAST 7 +#define LVDS_CLKB_POWER_MASK (3 << 4) +#define LVDS_CLKB_POWER_UP (3 << 4) +#define LVDS_PORT_EN (1 << 31) +#define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +#define LVDS_PIPEB_SELECT (1 << 30) +#define LVDS_B0B3PAIRS_POWER_UP (3 << 2) +#define LVDS_PLL_MODE_LVDS (2 << 26) + +// PLL flags +#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_MODE_ANALOG (1UL << 26) +#define DISPLAY_PLL_DIVIDE_HIGH (1UL << 24) +#define DISPLAY_PLL_DIVIDE_4X (1UL << 23) +#define DISPLAY_PLL_POST1_DIVIDE_2 (1UL << 21) +#define DISPLAY_PLL_POST1_DIVISOR_MASK 0x001f0000 +#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_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 DISPLAY_PLL_PULSE_PHASE_SHIFT 9 + +// display A +#define RADEON_DISPLAY_A_HTOTAL 0x60000 +#define RADEON_DISPLAY_A_HBLANK 0x60004 +#define RADEON_DISPLAY_A_HSYNC 0x60008 +#define RADEON_DISPLAY_A_VTOTAL 0x6000c +#define RADEON_DISPLAY_A_VBLANK 0x60010 +#define RADEON_DISPLAY_A_VSYNC 0x60014 +#define RADEON_DISPLAY_A_IMAGE_SIZE 0x6001c + +#define RADEON_DISPLAY_A_CONTROL 0x70180 +#define RADEON_DISPLAY_A_BASE 0x70184 +#define RADEON_DISPLAY_A_BYTES_PER_ROW 0x70188 +#define RADEON_DISPLAY_A_SURFACE 0x7019c // i965 and up only +#define DISPLAY_CONTROL_ENABLED (1UL << 31) +#define DISPLAY_CONTROL_GAMMA (1UL << 30) +#define DISPLAY_CONTROL_COLOR_MASK (0x0fUL << 26) +#define DISPLAY_CONTROL_CMAP8 (2UL << 26) +#define DISPLAY_CONTROL_RGB15 (4UL << 26) +#define DISPLAY_CONTROL_RGB16 (5UL << 26) +#define DISPLAY_CONTROL_RGB32 (6UL << 26) + +#define RADEON_VGA_DISPLAY_CONTROL 0x71400 +#define VGA_DISPLAY_DISABLED (1UL << 31) + +#define RADEON_DISPLAY_A_PALETTE 0x0a000 + +#define RADEON_DISPLAY_A_PIPE_CONTROL 0x70008 +#define DISPLAY_PIPE_ENABLED (1UL << 31) +#define RADEON_DISPLAY_A_PIPE_STATUS 0x70024 +#define DISPLAY_PIPE_VBLANK_ENABLED (1UL << 17) +#define DISPLAY_PIPE_VBLANK_STATUS (1UL << 1) + +#define RADEON_DISPLAY_A_PLL 0x06014 +#define RADEON_DISPLAY_A_PLL_DIVISOR_0 0x06040 +#define RADEON_DISPLAY_A_PLL_DIVISOR_1 0x06044 + +// display B +#define RADEON_DISPLAY_B_HTOTAL 0x61000 +#define RADEON_DISPLAY_B_HBLANK 0x61004 +#define RADEON_DISPLAY_B_HSYNC 0x61008 +#define RADEON_DISPLAY_B_VTOTAL 0x6100c +#define RADEON_DISPLAY_B_VBLANK 0x61010 +#define RADEON_DISPLAY_B_VSYNC 0x61014 + +#define RADEON_DISPLAY_B_DIGITAL_PORT 0x61140 +#define RADEON_DISPLAY_B_PIPE_SIZE 0x71190 + +#define RADEON_DISPLAY_B_PIPE_CONTROL 0x71008 + +#define RADEON_DISPLAY_B_CONTROL 0x71180 +#define RADEON_DISPLAY_B_BASE 0x71184 +#define RADEON_DISPLAY_B_BYTES_PER_ROW 0x71188 +#define RADEON_DISPLAY_B_POS 0x7118C + +#define RADEON_DISPLAY_B_IMAGE_SIZE 0x6101c +#define RADEON_DISPLAY_B_SURFACE 0x7119c // i965 and up only + +#define RADEON_DISPLAY_B_PALETTE 0x0a800 + +#define RADEON_DISPLAY_B_PLL 0x06018 +#define RADEON_DISPLAY_B_PLL_MULTIPLIER_DIVISOR 0x06020 +#define RADEON_DISPLAY_B_PLL_DIVISOR_0 0x06048 +#define RADEON_DISPLAY_B_PLL_DIVISOR_1 0x0604c + +// LVDS panel +#define RADEON_PANEL_STATUS 0x61200 +#define PANEL_STATUS_POWER_ON (1UL << 31) +#define RADEON_PANEL_CONTROL 0x61204 +#define PANEL_CONTROL_POWER_TARGET_ON (1UL << 0) +#define RADEON_PANEL_FIT_CONTROL 0x61230 +#define RADEON_PANEL_FIT_RATIOS 0x61234 + +// cursor +#define RADEON_CURSOR_CONTROL 0x70080 +#define RADEON_CURSOR_BASE 0x70084 +#define RADEON_CURSOR_POSITION 0x70088 +#define RADEON_CURSOR_PALETTE 0x70090 // (- 0x7009f) +#define RADEON_CURSOR_SIZE 0x700a0 +#define CURSOR_ENABLED (1UL << 31) +#define CURSOR_FORMAT_2_COLORS (0UL << 24) +#define CURSOR_FORMAT_3_COLORS (1UL << 24) +#define CURSOR_FORMAT_4_COLORS (2UL << 24) +#define CURSOR_FORMAT_ARGB (4UL << 24) +#define CURSOR_FORMAT_XRGB (5UL << 24) +#define CURSOR_POSITION_NEGATIVE 0x8000 +#define CURSOR_POSITION_MASK 0x3fff + +// ring buffer commands + +#define COMMAND_NOOP 0x00 +#define COMMAND_WAIT_FOR_EVENT (0x03 << 23) +#define COMMAND_WAIT_FOR_OVERLAY_FLIP (1 << 16) + +#define COMMAND_FLUSH (0x04 << 23) + +// overlay flip +#define COMMAND_OVERLAY_FLIP (0x11 << 23) +#define COMMAND_OVERLAY_CONTINUE (0 << 21) +#define COMMAND_OVERLAY_ON (1 << 21) +#define COMMAND_OVERLAY_OFF (2 << 21) +#define OVERLAY_UPDATE_COEFFICIENTS 0x1 + +// 2D acceleration +#define XY_COMMAND_SOURCE_BLIT 0x54c00006 +#define XY_COMMAND_COLOR_BLIT 0x54000004 +#define XY_COMMAND_SETUP_MONO_PATTERN 0x44400007 +#define XY_COMMAND_SCANLINE_BLIT 0x49400001 +#define COMMAND_COLOR_BLIT 0x50000003 +#define COMMAND_BLIT_RGBA 0x00300000 + +#define COMMAND_MODE_SOLID_PATTERN 0x80 +#define COMMAND_MODE_CMAP8 0x00 +#define COMMAND_MODE_RGB15 0x02 +#define COMMAND_MODE_RGB16 0x01 +#define COMMAND_MODE_RGB32 0x03 + +// i2c + +#define RADEON_I2C_IO_A 0x5010 +#define RADEON_I2C_IO_B 0x5014 +#define RADEON_I2C_IO_C 0x5018 +#define RADEON_I2C_IO_D 0x501c +#define RADEON_I2C_IO_E 0x5020 +#define RADEON_I2C_IO_F 0x5024 +#define RADEON_I2C_IO_G 0x5028 +#define RADEON_I2C_IO_H 0x502c + +#define I2C_CLOCK_DIRECTION_MASK (1 << 0) +#define I2C_CLOCK_DIRECTION_OUT (1 << 1) +#define I2C_CLOCK_VALUE_MASK (1 << 2) +#define I2C_CLOCK_VALUE_OUT (1 << 3) +#define I2C_CLOCK_VALUE_IN (1 << 4) +#define I2C_DATA_DIRECTION_MASK (1 << 8) +#define I2C_DATA_DIRECTION_OUT (1 << 9) +#define I2C_DATA_VALUE_MASK (1 << 10) +#define I2C_DATA_VALUE_OUT (1 << 11) +#define I2C_DATA_VALUE_IN (1 << 12) +#define I2C_RESERVED ((1 << 13) | (1 << 5)) + +// overlay + +#define RADEON_OVERLAY_UPDATE 0x30000 +#define RADEON_OVERLAY_TEST 0x30004 +#define RADEON_OVERLAY_STATUS 0x30008 +#define RADEON_OVERLAY_EXTENDED_STATUS 0x3000c +#define RADEON_OVERLAY_GAMMA_5 0x30010 +#define RADEON_OVERLAY_GAMMA_4 0x30014 +#define RADEON_OVERLAY_GAMMA_3 0x30018 +#define RADEON_OVERLAY_GAMMA_2 0x3001c +#define RADEON_OVERLAY_GAMMA_1 0x30020 +#define RADEON_OVERLAY_GAMMA_0 0x30024 + +struct overlay_scale { + uint32 _reserved0 : 3; + uint32 horizontal_scale_fraction : 12; + uint32 _reserved1 : 1; + uint32 horizontal_downscale_factor : 3; + uint32 _reserved2 : 1; + uint32 vertical_scale_fraction : 12; +}; + +#define OVERLAY_FORMAT_RGB15 0x2 +#define OVERLAY_FORMAT_RGB16 0x3 +#define OVERLAY_FORMAT_RGB32 0x1 +#define OVERLAY_FORMAT_YCbCr422 0x8 +#define OVERLAY_FORMAT_YCbCr411 0x9 +#define OVERLAY_FORMAT_YCbCr420 0xc + +#define OVERLAY_MIRROR_NORMAL 0x0 +#define OVERLAY_MIRROR_HORIZONTAL 0x1 +#define OVERLAY_MIRROR_VERTICAL 0x2 + +// The real overlay registers are written to using an update buffer + +struct overlay_registers { + uint32 buffer_rgb0; + uint32 buffer_rgb1; + uint32 buffer_u0; + uint32 buffer_v0; + uint32 buffer_u1; + uint32 buffer_v1; + // (0x18) OSTRIDE - overlay stride + uint16 stride_rgb; + uint16 stride_uv; + // (0x1c) YRGB_VPH - Y/RGB vertical phase + uint16 vertical_phase0_rgb; + uint16 vertical_phase1_rgb; + // (0x20) UV_VPH - UV vertical phase + uint16 vertical_phase0_uv; + uint16 vertical_phase1_uv; + // (0x24) HORZ_PH - horizontal phase + uint16 horizontal_phase_rgb; + uint16 horizontal_phase_uv; + // (0x28) INIT_PHS - initial phase shift + uint32 initial_vertical_phase0_shift_rgb0 : 4; + uint32 initial_vertical_phase1_shift_rgb0 : 4; + uint32 initial_horizontal_phase_shift_rgb0 : 4; + uint32 initial_vertical_phase0_shift_uv : 4; + uint32 initial_vertical_phase1_shift_uv : 4; + uint32 initial_horizontal_phase_shift_uv : 4; + uint32 _reserved0 : 8; + // (0x2c) DWINPOS - destination window position + uint16 window_left; + uint16 window_top; + // (0x30) DWINSZ - destination window size + uint16 window_width; + uint16 window_height; + // (0x34) SWIDTH - source width + uint16 source_width_rgb; + uint16 source_width_uv; + // (0x38) SWITDHSW - source width in 8 byte steps + uint16 source_bytes_per_row_rgb; + uint16 source_bytes_per_row_uv; + uint16 source_height_rgb; + uint16 source_height_uv; + overlay_scale scale_rgb; + overlay_scale scale_uv; + // (0x48) OCLRC0 - overlay color correction 0 + uint32 brightness_correction : 8; // signed, -128 to 127 + uint32 _reserved1 : 10; + uint32 contrast_correction : 9; // fixed point: 3.6 bits + uint32 _reserved2 : 5; + // (0x4c) OCLRC1 - overlay color correction 1 + uint32 saturation_cos_correction : 10; // fixed point: 3.7 bits + uint32 _reserved3 : 6; + uint32 saturation_sin_correction : 11; // signed fixed point: 3.7 bits + uint32 _reserved4 : 5; + // (0x50) DCLRKV - destination color key value + uint32 color_key_blue : 8; + uint32 color_key_green : 8; + uint32 color_key_red : 8; + uint32 _reserved5 : 8; + // (0x54) DCLRKM - destination color key mask + uint32 color_key_mask_blue : 8; + uint32 color_key_mask_green : 8; + uint32 color_key_mask_red : 8; + uint32 _reserved6 : 7; + uint32 color_key_enabled : 1; + // (0x58) SCHRKVH - source chroma key high value + uint32 source_chroma_key_high_red : 8; + uint32 source_chroma_key_high_blue : 8; + uint32 source_chroma_key_high_green : 8; + uint32 _reserved7 : 8; + // (0x5c) SCHRKVL - source chroma key low value + uint32 source_chroma_key_low_red : 8; + uint32 source_chroma_key_low_blue : 8; + uint32 source_chroma_key_low_green : 8; + uint32 _reserved8 : 8; + // (0x60) SCHRKEN - source chroma key enable + uint32 _reserved9 : 24; + uint32 source_chroma_key_red_enabled : 1; + uint32 source_chroma_key_blue_enabled : 1; + uint32 source_chroma_key_green_enabled : 1; + uint32 _reserved10 : 5; + // (0x64) OCONFIG - overlay configuration + uint32 _reserved11 : 3; + uint32 color_control_output_mode : 1; + uint32 yuv_to_rgb_bypass : 1; + uint32 _reserved12 : 11; + uint32 gamma2_enabled : 1; + uint32 _reserved13 : 1; + uint32 select_pipe : 1; + uint32 slot_time : 8; + uint32 _reserved14 : 5; + // (0x68) OCOMD - overlay command + uint32 overlay_enabled : 1; + uint32 active_field : 1; + uint32 active_buffer : 2; + uint32 test_mode : 1; + uint32 buffer_field_mode : 1; + uint32 _reserved15 : 1; + uint32 tv_flip_field_enabled : 1; + uint32 _reserved16 : 1; + uint32 tv_flip_field_parity : 1; + uint32 source_format : 4; + uint32 ycbcr422_order : 2; + uint32 _reserved18 : 1; + uint32 mirroring_mode : 2; + uint32 _reserved19 : 13; + + uint32 _reserved20; + + uint32 start_0y; + uint32 start_1y; + uint32 start_0u; + uint32 start_0v; + uint32 start_1u; + uint32 start_1v; + uint32 _reserved21[6]; +#if 0 + // (0x70) AWINPOS - alpha blend window position + uint32 awinpos; + // (0x74) AWINSZ - alpha blend window size + uint32 awinsz; + + uint32 _reserved21[10]; +#endif + + // (0xa0) FASTHSCALE - fast horizontal downscale (strangely enough, + // the next two registers switch the usual Y/RGB vs. UV order) + uint16 horizontal_scale_uv; + uint16 horizontal_scale_rgb; + // (0xa4) UVSCALEV - vertical downscale + uint16 vertical_scale_uv; + uint16 vertical_scale_rgb; + + uint32 _reserved22[86]; + + // (0x200) polyphase filter coefficients + uint16 vertical_coefficients_rgb[128]; + uint16 horizontal_coefficients_rgb[128]; + + uint32 _reserved23[64]; + + // (0x500) + uint16 vertical_coefficients_uv[128]; + uint16 horizontal_coefficients_uv[128]; +}; + +// i965 overlay support is currently realized using its 3D hardware +#define RADEON_i965_OVERLAY_STATE_SIZE 36864 +#define RADEON_i965_3D_CONTEXT_SIZE 32768 + +inline bool +radeon_uses_physical_overlay(radeon_shared_info &info) +{ + return !info.device_type.InGroup(RADEON_TYPE_Gxx); +} + + +struct hardware_status { + uint32 interrupt_status_register; + uint32 _reserved0[3]; + void* primary_ring_head_storage; + uint32 _reserved1[3]; + void* secondary_ring_0_head_storage; + void* secondary_ring_1_head_storage; + uint32 _reserved2[2]; + void* binning_head_storage; + uint32 _reserved3[3]; + uint32 store[1008]; +}; + +#endif /* RADEON_HD_H */ diff --git a/headers/private/graphics/radeon_hd/utility.h b/headers/private/graphics/radeon_hd/utility.h new file mode 100644 index 0000000000..eae3c06660 --- /dev/null +++ b/headers/private/graphics/radeon_hd/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 6281ab3c28..09b18cbff2 100644 --- a/src/add-ons/accelerants/Jamfile +++ b/src/add-ons/accelerants/Jamfile @@ -9,6 +9,7 @@ SubInclude HAIKU_TOP src add-ons accelerants neomagic ; SubInclude HAIKU_TOP src add-ons accelerants nvidia_gpgpu ; SubInclude HAIKU_TOP src add-ons accelerants nvidia ; SubInclude HAIKU_TOP src add-ons accelerants radeon ; +SubInclude HAIKU_TOP src add-ons accelerants radeon_hd ; SubInclude HAIKU_TOP src add-ons accelerants s3 ; SubInclude HAIKU_TOP src add-ons accelerants tdfx ; SubInclude HAIKU_TOP src add-ons accelerants vesa ; diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.cpp b/src/add-ons/accelerants/intel_extreme/accelerant.cpp index f73d7578b7..b9e09f30b8 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.cpp +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -134,22 +134,6 @@ init_common(int device, bool isClone) sharedCloner.Keep(); regsCloner.Keep(); - // The overlay registers, hardware status, and cursor memory share - // a single area with the shared_info - - gInfo->overlay_registers = (struct overlay_registers *) - (gInfo->shared_info->graphics_memory - + gInfo->shared_info->overlay_offset); - - if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) { - // allocate some extra memory for the 3D context - if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE, - B_APERTURE_NON_RESERVED, gInfo->context_base) == B_OK) { - gInfo->context_offset = gInfo->context_base - - (addr_t)gInfo->shared_info->graphics_memory; - } - } - return B_OK; } diff --git a/src/add-ons/accelerants/intel_extreme/accelerant_protos.h b/src/add-ons/accelerants/intel_extreme/accelerant_protos.h index 2768ee6483..13b5827de5 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant_protos.h +++ b/src/add-ons/accelerants/intel_extreme/accelerant_protos.h @@ -21,12 +21,12 @@ void spin(bigtime_t delay); // 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); +//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); +//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); diff --git a/src/add-ons/accelerants/radeon_hd/Jamfile b/src/add-ons/accelerants/radeon_hd/Jamfile new file mode 100644 index 0000000000..96e5eb5a73 --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/Jamfile @@ -0,0 +1,21 @@ +SubDir HAIKU_TOP src add-ons accelerants radeon_hd ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders graphics ; +UsePrivateHeaders [ FDirName graphics radeon_hd ] ; +UsePrivateHeaders [ FDirName graphics common ] ; + +Addon radeon_hd.accelerant : + accelerant.cpp + engine.cpp + hooks.cpp + memory.cpp + mode.cpp + : be libaccelerantscommon.a +; + +Package haiku-radeon_hd-cvs : + radeon_hd.accelerant : + boot home config add-ons accelerants ; + diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.cpp b/src/add-ons/accelerants/radeon_hd/accelerant.cpp new file mode 100644 index 0000000000..ea56e44716 --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/accelerant.cpp @@ -0,0 +1,289 @@ +/* + * Copyright 2006-2009, 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" + +#include +#include +#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 < 0 ? (status_t)fArea : B_OK; } + void Keep(); + +private: + area_id fArea; +}; + + +AreaCloner::AreaCloner() + : + fArea(-1) +{ +} + + +AreaCloner::~AreaCloner() +{ + if (fArea >= 0) + 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 + + radeon_get_private_data data; + data.magic = RADEON_PRIVATE_DATA_MAGIC; + + if (ioctl(device, RADEON_GET_PRIVATE_DATA, &data, + sizeof(radeon_get_private_data)) != 0) { + free(gInfo); + return B_ERROR; + } + + AreaCloner sharedCloner; + gInfo->shared_info_area = sharedCloner.Clone("radeon hd 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); + TRACE(("radeon_init_accelerant() failed shared area%i, %i\n", data.shared_info_area, + gInfo->shared_info_area)); + return status; + } + + AreaCloner regsCloner; + gInfo->regs_area = regsCloner.Clone("radeon hd 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; + + // close the file handle ONLY if we're the clone + if (gInfo->is_clone) + close(gInfo->device); + + free(gInfo); +} + + +// #pragma mark - public accelerant functions + + +/*! Init primary accelerant */ +status_t +radeon_init_accelerant(int device) +{ + TRACE(("radeon_init_accelerant()\n")); + + status_t status = init_common(device, false); + if (status != B_OK) + return status; + + radeon_shared_info &info = *gInfo->shared_info; + + init_lock(&info.accelerant_lock, "radeon hd accelerant"); + init_lock(&info.engine_lock, "radeon hd engine"); + + + status = create_mode_list(); + if (status != B_OK) { + uninit_common(); + return status; + } + + TRACE(("radeon_init_accelerant() done\n")); + return B_OK; +} + +/* +ssize_t +radeon_accelerant_clone_info_size(void) +{ + TRACE(("radeon_accelerant_clone_info_size()\n")); + // clone info is device name, so return its maximum size + return B_PATH_NAME_LENGTH; +} + + +void +radeon_get_accelerant_clone_info(void *info) +{ + TRACE(("radeon_get_accelerant_clone_info()\n")); + ioctl(gInfo->device, RADEON_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); +} + + +status_t +radeon_clone_accelerant(void *info) +{ + TRACE(("radeon_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 errno; + + 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 +radeon_uninit_accelerant(void) +{ + TRACE(("radeon_uninit_accelerant()\n")); + + gInfo->mode_list = NULL; + + radeon_shared_info &info = *gInfo->shared_info; + + uninit_lock(&info.accelerant_lock); + uninit_lock(&info.engine_lock); + + uninit_common(); +} + +/* +status_t +radeon_get_accelerant_device_info(accelerant_device_info *info) +{ + TRACE(("radeon_get_accelerant_device_info()\n")); + + info->version = B_ACCELERANT_VERSION; + strcpy(info->name, gInfo->shared_info->device_type.InFamily(RADEON_TYPE_7xx) + ? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2"); + strcpy(info->chipset, gInfo->shared_info->device_identifier); + 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 +radeon_accelerant_retrace_semaphore() +{ + TRACE(("radeon_accelerant_retrace_semaphore()\n")); + return gInfo->shared_info->vblank_sem; +}*/ + diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h b/src/add-ons/accelerants/radeon_hd/accelerant.h new file mode 100644 index 0000000000..8006c03cc8 --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/accelerant.h @@ -0,0 +1,66 @@ +/* + * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef RADEON_HD_ACCELERANT_H +#define RADEON_HD_ACCELERANT_H + + +#include "radeon_hd.h" + + +#include + + +struct accelerant_info { + vuint8 *regs; + area_id regs_area; + + radeon_shared_info *shared_info; + area_id shared_info_area; + + display_mode *mode_list; // cloned list of standard display modes + area_id mode_list_area; + + edid1_info edid_info; + bool has_edid; + + int device; + bool is_clone; + + // LVDS panel mode passed from the bios/startup. + display_mode lvds_panel_mode; +}; + +#define HEAD_MODE_A_ANALOG 0x01 +#define HEAD_MODE_B_DIGITAL 0x02 +#define HEAD_MODE_CLONE 0x03 +#define HEAD_MODE_LVDS_PANEL 0x08 + +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; +} + +// memory.cpp +extern void radeon_free_memory(uint32 base); +extern status_t radeon_allocate_memory(size_t size, uint32 flags, uint32 &base); + +// modes.cpp +extern status_t create_mode_list(void); + +#endif /* RADEON_HD_ACCELERANT_H */ diff --git a/src/add-ons/accelerants/radeon_hd/accelerant_protos.h b/src/add-ons/accelerants/radeon_hd/accelerant_protos.h new file mode 100644 index 0000000000..1eeedbe05d --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/accelerant_protos.h @@ -0,0 +1,49 @@ +/* + * Copyright 2006-2007, 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 + +void spin(bigtime_t delay); + +// general +status_t radeon_init_accelerant(int fd); +ssize_t radeon_accelerant_clone_info_size(void); +void radeon_get_accelerant_clone_info(void *data); +status_t radeon_clone_accelerant(void *data); +void radeon_uninit_accelerant(void); +status_t radeon_get_accelerant_device_info(accelerant_device_info *info); +sem_id radeon_accelerant_retrace_semaphore(void); + +// modes & constraints +uint32 radeon_accelerant_mode_count(void); +status_t radeon_get_mode_list(display_mode *dm); +status_t radeon_set_display_mode(display_mode *mode); +status_t radeon_get_display_mode(display_mode *currentMode); +status_t radeon_get_frame_buffer_config(frame_buffer_config *config); +status_t radeon_get_pixel_clock_limits(display_mode *mode, uint32 *low, uint32 *high); + +// accelerant engine +status_t radeon_acquire_engine(uint32 capabilities, uint32 maxWait, + sync_token *syncToken, engine_token **_engineToken); +status_t radeon_release_engine(engine_token *engineToken, sync_token *syncToken); + + +#ifdef __cplusplus +} +#endif + +#endif /* ACCELERANT_PROTOS_H */ diff --git a/src/add-ons/accelerants/radeon_hd/engine.cpp b/src/add-ons/accelerants/radeon_hd/engine.cpp new file mode 100644 index 0000000000..008b36ae10 --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/engine.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include + +#include "accelerant.h" +#include "accelerant_protos.h" + + +#undef TRACE + +//#define TRACE_ENGINE +#ifdef TRACE_ENGINE +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +static engine_token sEngineToken = {1, 0 /*B_2D_ACCELERATION*/, NULL}; + + +// #pragma mark - engine management + + +status_t +radeon_acquire_engine(uint32 capabilities, uint32 maxWait, sync_token *syncToken, + engine_token **_engineToken) +{ + TRACE(("radeon_acquire_engine()\n")); + *_engineToken = &sEngineToken; + + if (acquire_lock(&gInfo->shared_info->engine_lock) != B_OK) + return B_ERROR; + + return B_OK; +} + + +status_t +radeon_release_engine(engine_token *engineToken, sync_token *syncToken) +{ + TRACE(("radeon_release_engine()\n")); + if (syncToken != NULL) + syncToken->engine_id = engineToken->engine_id; + + release_lock(&gInfo->shared_info->engine_lock); + return B_OK; +} + + diff --git a/src/add-ons/accelerants/radeon_hd/hooks.cpp b/src/add-ons/accelerants/radeon_hd/hooks.cpp new file mode 100644 index 0000000000..2103d34445 --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/hooks.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2006-2009, 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" + + +extern "C" void * +get_accelerant_hook(uint32 feature, void *data) +{ + switch (feature) { + /* general */ + case B_INIT_ACCELERANT: + return (void*)radeon_init_accelerant; + case B_UNINIT_ACCELERANT: + return (void*)radeon_uninit_accelerant; + /*case B_CLONE_ACCELERANT: + return (void*)radeon_clone_accelerant; + case B_ACCELERANT_CLONE_INFO_SIZE: + return (void*)radeon_accelerant_clone_info_size; + case B_GET_ACCELERANT_CLONE_INFO: + return (void*)radeon_get_accelerant_clone_info; + case B_GET_ACCELERANT_DEVICE_INFO: + return (void*)radeon_get_accelerant_device_info; + case B_ACCELERANT_RETRACE_SEMAPHORE: + return (void*)radeon_accelerant_retrace_semaphore; +*/ + /* mode configuration */ + case B_ACCELERANT_MODE_COUNT: + return (void*)radeon_accelerant_mode_count; + case B_GET_MODE_LIST: + return (void*)radeon_get_mode_list; + case B_SET_DISPLAY_MODE: + return (void*)radeon_set_display_mode; + case B_GET_DISPLAY_MODE: + return (void*)radeon_get_display_mode; + + case B_GET_FRAME_BUFFER_CONFIG: + return (void*)radeon_get_frame_buffer_config; + case B_GET_PIXEL_CLOCK_LIMITS: + return (void*)radeon_get_pixel_clock_limits; + + case B_ACQUIRE_ENGINE: + return (void*)radeon_acquire_engine; + case B_RELEASE_ENGINE: + return (void*)radeon_release_engine; + } + + return NULL; +} + diff --git a/src/add-ons/accelerants/radeon_hd/memory.cpp b/src/add-ons/accelerants/radeon_hd/memory.cpp new file mode 100644 index 0000000000..c6f90312c0 --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/memory.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "accelerant.h" +#include "radeon_hd.h" + +#include +#include + + +//#define TRACE_MEMORY +#ifdef TRACE_MEMORY +extern "C" void _sPrintf(const char *format, ...); +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +void +radeon_free_memory(uint32 base) +{ + if (base == 0) + return; + + radeon_free_graphics_memory freeMemory; + freeMemory.magic = RADEON_PRIVATE_DATA_MAGIC; + freeMemory.buffer_base = base; + + ioctl(gInfo->device, RADEON_FREE_GRAPHICS_MEMORY, &freeMemory, + sizeof(freeMemory)); +} + + +status_t +radeon_allocate_memory(size_t size, uint32 flags, uint32 &base) +{ + radeon_allocate_graphics_memory allocMemory; + allocMemory.magic = RADEON_PRIVATE_DATA_MAGIC; + allocMemory.size = size; + allocMemory.alignment = 0; + allocMemory.flags = flags; + + if (ioctl(gInfo->device, RADEON_ALLOCATE_GRAPHICS_MEMORY, &allocMemory, + sizeof(allocMemory)) < 0) + return errno; + + base = allocMemory.buffer_base; + return B_OK; +} + diff --git a/src/add-ons/accelerants/radeon_hd/mode.cpp b/src/add-ons/accelerants/radeon_hd/mode.cpp new file mode 100644 index 0000000000..ee5b742536 --- /dev/null +++ b/src/add-ons/accelerants/radeon_hd/mode.cpp @@ -0,0 +1,361 @@ +/* + * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Support for i915 chipset and up based on the X driver, + * Copyright 2006-2007 Intel Corporation. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "accelerant_protos.h" +#include "accelerant.h" +#include "utility.h" + +#include +#include +#include + +#include +#include +#include + + +#define TRACE_MODE +#ifdef TRACE_MODE +extern "C" void _sPrintf(const char *format, ...); +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +static display_mode gDisplayMode; + + +status_t +create_mode_list(void) +{ + gDisplayMode.timing.pixel_clock = 71500; + gDisplayMode.timing.h_display = 1366; /* in pixels (not character clocks) */ + gDisplayMode.timing.h_sync_start = 1406; + gDisplayMode.timing.h_sync_end = 1438; + gDisplayMode.timing.h_total = 1510; + gDisplayMode.timing.v_display = 768; /* in lines */ + gDisplayMode.timing.v_sync_start = 771; + gDisplayMode.timing.v_sync_end = 777; + gDisplayMode.timing.v_total = 789; + gDisplayMode.timing.flags = 0; /* sync polarity, etc. */ + + gDisplayMode.space = B_RGB32_LITTLE; /* pixel configuration */ + gDisplayMode.virtual_width = 1366; /* in pixels */ + gDisplayMode.virtual_height = 768; /* in lines */ + gDisplayMode.h_display_start = 0; /* first displayed pixel in line */ + gDisplayMode.v_display_start = 0; /* first displayed line */ + gDisplayMode.flags = 0; /* mode flags (Some drivers use this */ + + gInfo->mode_list = &gDisplayMode; + gInfo->shared_info->mode_count = 1; + return B_OK; +} + + +// #pragma mark - + + +uint32 +radeon_accelerant_mode_count(void) +{ + TRACE(("radeon_accelerant_mode_count()\n")); + + return gInfo->shared_info->mode_count; +} + + +status_t +radeon_get_mode_list(display_mode *modeList) +{ + TRACE(("radeon_get_mode_info()\n")); + memcpy(modeList, gInfo->mode_list, + gInfo->shared_info->mode_count * sizeof(display_mode)); + return B_OK; +} + + +inline void +write32AtMask(uint32 adress, uint32 value, uint32 mask) +{ + uint32 temp; + temp = read32(adress); + temp &= ~mask; + temp |= value & mask; + write32(adress, temp); +} + + +enum { + /* CRTC1 registers */ + D1CRTC_H_TOTAL = 0x6000, + D1CRTC_H_BLANK_START_END = 0x6004, + D1CRTC_H_SYNC_A = 0x6008, + D1CRTC_H_SYNC_A_CNTL = 0x600C, + D1CRTC_H_SYNC_B = 0x6010, + D1CRTC_H_SYNC_B_CNTL = 0x6014, + + D1CRTC_V_TOTAL = 0x6020, + D1CRTC_V_BLANK_START_END = 0x6024, + D1CRTC_V_SYNC_A = 0x6028, + D1CRTC_V_SYNC_A_CNTL = 0x602C, + D1CRTC_V_SYNC_B = 0x6030, + D1CRTC_V_SYNC_B_CNTL = 0x6034, + + D1CRTC_CONTROL = 0x6080, + D1CRTC_BLANK_CONTROL = 0x6084, + D1CRTC_INTERLACE_CONTROL = 0x6088, + D1CRTC_BLACK_COLOR = 0x6098, + D1CRTC_STATUS = 0x609C, + D1CRTC_COUNT_CONTROL = 0x60B4, + + /* D1GRPH registers */ + D1GRPH_ENABLE = 0x6100, + D1GRPH_CONTROL = 0x6104, + D1GRPH_LUT_SEL = 0x6108, + D1GRPH_SWAP_CNTL = 0x610C, + D1GRPH_PRIMARY_SURFACE_ADDRESS = 0x6110, + D1GRPH_SECONDARY_SURFACE_ADDRESS = 0x6118, + D1GRPH_PITCH = 0x6120, + D1GRPH_SURFACE_OFFSET_X = 0x6124, + D1GRPH_SURFACE_OFFSET_Y = 0x6128, + D1GRPH_X_START = 0x612C, + D1GRPH_Y_START = 0x6130, + D1GRPH_X_END = 0x6134, + D1GRPH_Y_END = 0x6138, + D1GRPH_UPDATE = 0x6144, + + /* D1MODE */ + D1MODE_DESKTOP_HEIGHT = 0x652C, + D1MODE_VLINE_START_END = 0x6538, + D1MODE_VLINE_STATUS = 0x653C, + D1MODE_VIEWPORT_START = 0x6580, + D1MODE_VIEWPORT_SIZE = 0x6584, + D1MODE_EXT_OVERSCAN_LEFT_RIGHT = 0x6588, + D1MODE_EXT_OVERSCAN_TOP_BOTTOM = 0x658C, + D1MODE_DATA_FORMAT = 0x6528 +}; + + +static void +get_color_space_format(const display_mode &mode, uint32 &colorMode, + uint32 &bytesPerRow, uint32 &bitsPerPixel) +{ + uint32 bytesPerPixel; + + switch (mode.space) { + case B_RGB32_LITTLE: + colorMode = DISPLAY_CONTROL_RGB32; + bytesPerPixel = 4; + bitsPerPixel = 32; + break; + case B_RGB16_LITTLE: + colorMode = DISPLAY_CONTROL_RGB16; + bytesPerPixel = 2; + bitsPerPixel = 16; + break; + case B_RGB15_LITTLE: + colorMode = DISPLAY_CONTROL_RGB15; + bytesPerPixel = 2; + bitsPerPixel = 15; + break; + case B_CMAP8: + default: + colorMode = DISPLAY_CONTROL_CMAP8; + bytesPerPixel = 1; + bitsPerPixel = 8; + break; + } + + bytesPerRow = mode.virtual_width * bytesPerPixel; + + // Make sure bytesPerRow is a multiple of 64 + // TODO: check if the older chips have the same restriction! + if ((bytesPerRow & 63) != 0) + bytesPerRow = (bytesPerRow + 63) & ~63; +} + +#define D1_REG_OFFSET 0x0000 +#define D2_REG_OFFSET 0x0800 + + +static void +DxModeSet(display_mode *mode) +{ + uint32 regOffset = D1_REG_OFFSET; + + display_timing& displayTiming = mode->timing; + + + /* enable read requests */ + write32AtMask(regOffset + D1CRTC_CONTROL, 0, 0x01000000); + + /* Horizontal */ + write32(regOffset + D1CRTC_H_TOTAL, displayTiming.h_total - 1); + + uint16 blankStart = displayTiming.h_sync_end; + uint16 blankEnd = displayTiming.h_total; + write32(regOffset + D1CRTC_H_BLANK_START_END, + blankStart | (blankEnd << 16)); + + write32(regOffset + D1CRTC_H_SYNC_A, + (displayTiming.h_sync_end - displayTiming.h_sync_start) << 16); + //write32(regOffset + D1CRTC_H_SYNC_A_CNTL, Mode->Flags & V_NHSYNC); + //!!!write32(regOffset + D1CRTC_H_SYNC_A_CNTL, V_NHSYNC); + + /* Vertical */ + write32(regOffset + D1CRTC_V_TOTAL, displayTiming.v_total - 1); + + blankStart = displayTiming.v_sync_end; + blankEnd = displayTiming.v_total; + write32(regOffset + D1CRTC_V_BLANK_START_END, + blankStart | (blankEnd << 16)); + + /* set interlaced */ + //if (Mode->Flags & V_INTERLACE) { + if (0) { + write32(regOffset + D1CRTC_INTERLACE_CONTROL, 0x1); + write32(regOffset + D1MODE_DATA_FORMAT, 0x1); + } else { + write32(regOffset + D1CRTC_INTERLACE_CONTROL, 0x0); + write32(regOffset + D1MODE_DATA_FORMAT, 0x0); + } + + write32(regOffset + D1CRTC_V_SYNC_A, + (displayTiming.v_sync_end - displayTiming.v_sync_start) << 16); + //write32(regOffset + D1CRTC_V_SYNC_A_CNTL, Mode->Flags & V_NVSYNC); + //!!!write32(regOffset + D1CRTC_V_SYNC_A_CNTL, V_NVSYNC); + + /* set D1CRTC_HORZ_COUNT_BY2_EN to 0; should only be set to 1 on 30bpp DVI modes */ + write32AtMask(regOffset + D1CRTC_COUNT_CONTROL, 0x0, 0x1); + +} + + +status_t +radeon_set_display_mode(display_mode *mode) +{ + //DxModeSet(mode); + + + uint32 colorMode, bytesPerRow, bitsPerPixel; + get_color_space_format(*mode, colorMode, bytesPerRow, bitsPerPixel); + + uint32 regOffset = D1_REG_OFFSET; + + write32AtMask(regOffset + D1GRPH_ENABLE, 1, 0x00000001); + + /* disable R/B swap, disable tiling, disable 16bit alpha, etc. */ + write32(regOffset + D1GRPH_CONTROL, 0); + + switch (mode->space) { + case B_CMAP8: + write32AtMask(regOffset + D1GRPH_CONTROL, 0, 0x00000703); + break; + case B_RGB15_LITTLE: + write32AtMask(regOffset + D1GRPH_CONTROL, 0x000001, 0x00000703); + break; + case B_RGB16_LITTLE: + write32AtMask(regOffset + D1GRPH_CONTROL, 0x000101, 0x00000703); + break; + case B_RGB24_LITTLE: + case B_RGB32_LITTLE: + default: + write32AtMask(regOffset + D1GRPH_CONTROL, 0x000002, 0x00000703); + break; + /* TODO: 64bpp ;p */ + } + + /* Make sure that we are not swapping colours around */ + //if (rhdPtr->ChipSet > RHD_R600) + write32(regOffset + D1GRPH_SWAP_CNTL, 0); + /* R5xx - RS690 case is GRPH_CONTROL bit 16 */ + +#define R6XX_CONFIG_FB_BASE 0x542C /* AKA CONFIG_F0_BASE */ + + uint32 fbIntAddress = read32(R6XX_CONFIG_FB_BASE); + + uint32 offset = gInfo->shared_info->frame_buffer_offset; + write32(regOffset + D1GRPH_PRIMARY_SURFACE_ADDRESS, + fbIntAddress + offset); + write32(regOffset + D1GRPH_PITCH, bytesPerRow / 4); + write32(regOffset + D1GRPH_SURFACE_OFFSET_X, 0); + write32(regOffset + D1GRPH_SURFACE_OFFSET_Y, 0); + write32(regOffset + D1GRPH_X_START, 0); + write32(regOffset + D1GRPH_Y_START, 0); + write32(regOffset + D1GRPH_X_END, mode->virtual_width); + write32(regOffset + D1GRPH_Y_END, mode->virtual_height); + + /* D1Mode registers */ + write32(regOffset + D1MODE_DESKTOP_HEIGHT, mode->virtual_height); + + // update shared info + gInfo->shared_info->bytes_per_row = bytesPerRow; + gInfo->shared_info->current_mode = *mode; + gInfo->shared_info->bits_per_pixel = bitsPerPixel; + + return B_OK; +} + + +status_t +radeon_get_display_mode(display_mode *_currentMode) +{ + TRACE(("radeon_get_display_mode()\n")); + + *_currentMode = gDisplayMode; + return B_OK; +} + + +status_t +radeon_get_frame_buffer_config(frame_buffer_config *config) +{ + TRACE(("radeon_get_frame_buffer_config()\n")); + + uint32 offset = gInfo->shared_info->frame_buffer_offset; + + config->frame_buffer = gInfo->shared_info->graphics_memory + offset; + config->frame_buffer_dma + = (uint8 *)gInfo->shared_info->physical_graphics_memory + offset; + config->bytes_per_row = gInfo->shared_info->bytes_per_row; + + return B_OK; +} + + +status_t +radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high) +{ + TRACE(("radeon_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.min_frequency) + low = gInfo->shared_info->pll_info.min_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; +*/ + *_low = 48L; + *_high = 100 * 1000000L; + return B_OK; +} + + diff --git a/src/add-ons/kernel/drivers/graphics/Jamfile b/src/add-ons/kernel/drivers/graphics/Jamfile index b9d4ddcb29..340fa13d75 100644 --- a/src/add-ons/kernel/drivers/graphics/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/Jamfile @@ -9,6 +9,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers graphics neomagic ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics nvidia ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics nvidia_gpgpu ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics radeon ; +SubInclude HAIKU_TOP src add-ons kernel drivers graphics radeon_hd ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics s3 ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics tdfx ; SubInclude HAIKU_TOP src add-ons kernel drivers graphics skeleton ; diff --git a/src/add-ons/kernel/drivers/graphics/radeon_hd/Jamfile b/src/add-ons/kernel/drivers/graphics/radeon_hd/Jamfile new file mode 100644 index 0000000000..803d6c8772 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon_hd/Jamfile @@ -0,0 +1,24 @@ +SubDir HAIKU_TOP src add-ons kernel drivers graphics radeon_hd ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders [ FDirName graphics radeon_hd ] ; +UsePrivateHeaders [ FDirName graphics common ] ; +UsePrivateHeaders graphics kernel ; +UsePrivateHeaders shared ; + +KernelAddon radeon_hd : + driver.cpp + device.cpp + radeon_hd.cpp + : libgraphicscommon.a +; + +SEARCH on [ FGristFiles + kernel_cpp.cpp + ] = [ FDirName $(HAIKU_TOP) src system kernel util ] ; + +Package haiku-radeon_hd-cvs : + radeon_hd : + boot home config add-ons kernel drivers bin ; +PackageDriverSymLink haiku-radeon_hd-cvs : graphics radeon_hd ; diff --git a/src/add-ons/kernel/drivers/graphics/radeon_hd/device.cpp b/src/add-ons/kernel/drivers/graphics/radeon_hd/device.cpp new file mode 100644 index 0000000000..9d5d78dcba --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon_hd/device.cpp @@ -0,0 +1,272 @@ +/* + * Copyright 2006-2009, 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 "radeon_hd.h" +#include "utility.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +//#define DEBUG_COMMANDS + +#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 +}; + + +#ifdef DEBUG_COMMANDS +static int +getset_register(int argc, char **argv) +{ + if (argc < 2 || argc > 3) { + kprintf("usage: %s [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("radeon_extreme register %#lx\n", reg); + + radeon_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; +} +#endif // DEBUG_COMMANDS + + +// #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; + } + TRACE((DEVICE_NAME ": device id %i\n", id)); + + radeon_info *info = gDeviceInfo[id]; + + mutex_lock(&gLock); + + if (info->open_count == 0) { + // this device has been opened for the first time, so + // we allocate needed resources and initialize the structure + info->init_status = radeon_hd_init(*info); + if (info->init_status == B_OK) { + info->open_count++; + } + } + + mutex_unlock(&gLock); + + if (info->init_status == B_OK) + *_cookie = info; + + return info->init_status; +} + + +static status_t +device_close(void */*data*/) +{ + TRACE((DEVICE_NAME ": close\n")); + return B_OK; +} + + +static status_t +device_free(void *data) +{ + struct radeon_info *info = (radeon_info *)data; + + mutex_lock(&gLock); + + if (info->open_count-- == 1) { + // release info structure + info->init_status = B_NO_INIT; + radeon_hd_uninit(*info); + } + mutex_unlock(&gLock); + return B_OK; +} + + +static status_t +device_ioctl(void *data, uint32 op, void *buffer, size_t bufferLength) +{ + struct radeon_info *info = (radeon_info *)data; + + switch (op) { + case B_GET_ACCELERANT_SIGNATURE: + strcpy((char *)buffer, RADEON_ACCELERANT_NAME); + TRACE((DEVICE_NAME ": accelerant: %s\n", RADEON_ACCELERANT_NAME)); + return B_OK; + + // needed to share data between kernel and accelerant + case RADEON_GET_PRIVATE_DATA: + { + radeon_get_private_data *data = (radeon_get_private_data *)buffer; + + if (data->magic == RADEON_PRIVATE_DATA_MAGIC) { + data->shared_info_area = info->shared_area; + return B_OK; + } + break; + } + + // needed for cloning + case RADEON_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 RADEON_ALLOCATE_GRAPHICS_MEMORY: + { + radeon_allocate_graphics_memory allocMemory; +#ifdef __HAIKU__ + if (user_memcpy(&allocMemory, buffer, + sizeof(radeon_allocate_graphics_memory)) < B_OK) + return B_BAD_ADDRESS; +#else + memcpy(&allocMemory, buffer, sizeof(radeon_allocate_graphics_memory)); +#endif + + if (allocMemory.magic != RADEON_PRIVATE_DATA_MAGIC) + return B_BAD_VALUE; + + status_t status = radeon_allocate_memory(*info, allocMemory.size, + allocMemory.alignment, allocMemory.flags, + (addr_t *)&allocMemory.buffer_base); + if (status == B_OK) { + // copy result +#ifdef __HAIKU__ + if (user_memcpy(buffer, &allocMemory, + sizeof(radeon_allocate_graphics_memory)) < B_OK) + return B_BAD_ADDRESS; +#else + memcpy(buffer, &allocMemory, + sizeof(radeon_allocate_graphics_memory)); +#endif + } + return status; + } + + case RADEON_FREE_GRAPHICS_MEMORY: + { + radeon_free_graphics_memory freeMemory; +#ifdef __HAIKU__ + if (user_memcpy(&freeMemory, buffer, + sizeof(radeon_free_graphics_memory)) < B_OK) + return B_BAD_ADDRESS; +#else + memcpy(&freeMemory, buffer, sizeof(radeon_free_graphics_memory)); +#endif + + if (freeMemory.magic == RADEON_PRIVATE_DATA_MAGIC) + return radeon_free_memory(*info, freeMemory.buffer_base); + 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/radeon_hd/device.h b/src/add-ons/kernel/drivers/graphics/radeon_hd/device.h new file mode 100644 index 0000000000..5b0fe46e4e --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon_hd/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/radeon_hd/driver.cpp b/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp new file mode 100644 index 0000000000..94746960df --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp @@ -0,0 +1,228 @@ +/* + Copyright (c) 2002, Thomas Kurschel + + +*/ + +#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 1 + + +// list of supported devices +const struct supported_device { + uint32 device_id; + int32 type; + const char* name; +} kSupportedDevices[] = { + {0x9612, 0, "HD 3200"} +}; + + +const uint32 kATIVendorId = 0x1002; + + +int32 api_version = B_CUR_DRIVER_API_VERSION; + + +char* gDeviceNames[MAX_CARDS + 1]; +radeon_info* gDeviceInfo[MAX_CARDS]; +pci_module_info* gPCI; +agp_gart_module_info* gGART; +mutex gLock; + + +static status_t +get_next_radeon_hd(int32 *_cookie, pci_info &info, uint32 &type) +{ + int32 index = *_cookie; + + // find devices + + for (; gPCI->get_nth_pci_info(index, &info) == B_OK; index++) { + // check vendor + if (info.vendor_id != kATIVendorId + || info.class_base != PCI_display + || info.class_sub != PCI_vga) + continue; + + // check device + for (uint32 i = 0; i < sizeof(kSupportedDevices) + / sizeof(kSupportedDevices[0]); i++) { + if (info.device_id == kSupportedDevices[i].device_id) { + type = i; + *_cookie = index + 1; + return B_OK; + } + } + } + + return B_ENTRY_NOT_FOUND; +} + + +extern "C" const char ** +publish_devices(void) +{ + TRACE((DEVICE_NAME ": publish_devices()\n")); + return (const char **)gDeviceNames; +} + + +extern "C" status_t +init_hardware(void) +{ + TRACE((DEVICE_NAME ": init_hardware()\n")); + + status_t status = get_module(B_PCI_MODULE_NAME,(module_info **)&gPCI); + if (status != B_OK) { + TRACE((DEVICE_NAME ": pci module unavailable\n")); + return status; + } + + int32 cookie = 0; + uint32 type; + pci_info info; + status = get_next_radeon_hd(&cookie, info, type); + + put_module(B_PCI_MODULE_NAME); + return status; +} + + +extern "C" status_t +init_driver(void) +{ + TRACE((DEVICE_NAME ": init_driver()\n")); + + status_t status = get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI); + if (status != B_OK) { + TRACE((DEVICE_NAME ": pci module unavailable\n")); + return status; + } + + status = get_module(B_AGP_GART_MODULE_NAME, (module_info**)&gGART); + if (status != B_OK) { + TRACE((DEVICE_NAME ": AGP GART module unavailable\n")); + put_module(B_PCI_MODULE_NAME); + return status; + } + + mutex_init(&gLock, "intel extreme ksync"); + + // find devices + + int32 found = 0; + + for (int32 cookie = 0; found < MAX_CARDS;) { + pci_info* info = (pci_info*)malloc(sizeof(pci_info)); + if (info == NULL) + break; + + uint32 type; + status = get_next_radeon_hd(&cookie, *info, type); + if (status < B_OK) { + free(info); + break; + } + + // create device names & allocate device info structure + + char name[64]; + sprintf(name, "graphics/radeon_hd_%02x%02x%02x", + info->bus, info->device, + info->function); + + gDeviceNames[found] = strdup(name); + if (gDeviceNames[found] == NULL) + break; + + gDeviceInfo[found] = (radeon_info*)malloc(sizeof(radeon_info)); + if (gDeviceInfo[found] == NULL) { + free(gDeviceNames[found]); + break; + } + + // initialize the structure for later use + + memset(gDeviceInfo[found], 0, sizeof(radeon_info)); + gDeviceInfo[found]->init_status = B_NO_INIT; + gDeviceInfo[found]->id = found; + gDeviceInfo[found]->pci = info; + gDeviceInfo[found]->registers = (uint8 *)info->u.h0.base_registers[0]; + gDeviceInfo[found]->device_identifier = kSupportedDevices[type].name; + gDeviceInfo[found]->device_type = kSupportedDevices[type].type; + + dprintf(DEVICE_NAME ": (%ld) %s, revision = 0x%x\n", found, + kSupportedDevices[type].name, info->revision); + + found++; + } + + gDeviceNames[found] = NULL; + + if (found == 0) { + mutex_destroy(&gLock); + put_module(B_AGP_GART_MODULE_NAME); + put_module(B_PCI_MODULE_NAME); + return ENODEV; + } + + return B_OK; +} + + +extern "C" void +uninit_driver(void) +{ + TRACE((DEVICE_NAME ": uninit_driver()\n")); + + mutex_destroy(&gLock); + + // free device related structures + char* name; + for (int32 index = 0; (name = gDeviceNames[index]) != NULL; index++) { + free(gDeviceInfo[index]); + free(name); + } + + put_module(B_AGP_GART_MODULE_NAME); + put_module(B_PCI_MODULE_NAME); +} + + +extern "C" 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; +} + diff --git a/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.h b/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.h new file mode 100644 index 0000000000..3703b19a0f --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.h @@ -0,0 +1,54 @@ +/* + * Copyright 2006-2009, 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 + + +#include "radeon_hd_private.h" + + +// PCI Communications + +#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)) + + +extern char* gDeviceNames[]; +extern radeon_info* gDeviceInfo[]; +extern pci_module_info* gPCI; +extern agp_gart_module_info* gGART; +extern mutex 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/radeon_hd/radeon_hd.cpp b/src/add-ons/kernel/drivers/graphics/radeon_hd/radeon_hd.cpp new file mode 100644 index 0000000000..b5c265a253 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon_hd/radeon_hd.cpp @@ -0,0 +1,293 @@ +/* + * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "radeon_hd.h" + +#include "AreaKeeper.h" +#include "driver.h" +#include "utility.h" + +#include +#include +#include +#include + +#include +#include + + +#define TRACE_DEVICE +#ifdef TRACE_DEVICE +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +static void +init_overlay_registers(overlay_registers *registers) +{ + memset(registers, 0, B_PAGE_SIZE); + + registers->contrast_correction = 0x48; + registers->saturation_cos_correction = 0x9a; + // this by-passes contrast and saturation correction +} + + +static void +read_settings(bool &hardwareCursor) +{ + hardwareCursor = false; + + void *settings = load_driver_settings("radeon_extreme"); + if (settings != NULL) { + hardwareCursor = get_driver_boolean_parameter(settings, + "hardware_cursor", true, true); + + unload_driver_settings(settings); + } +} + + +static int32 +release_vblank_sem(radeon_info &info) +{ + int32 count; + if (get_sem_count(info.shared_info->vblank_sem, &count) == B_OK + && count < 0) { + release_sem_etc(info.shared_info->vblank_sem, -count, + B_DO_NOT_RESCHEDULE); + return B_INVOKE_SCHEDULER; + } + + return B_HANDLED_INTERRUPT; +} + + +static int32 +radeon_interrupt_handler(void *data) +{ + radeon_info &info = *(radeon_info *)data; + + uint32 identity = read16(info.registers + RADEON_INTERRUPT_IDENTITY); + if (identity == 0) + return B_UNHANDLED_INTERRUPT; + + int32 handled = B_HANDLED_INTERRUPT; + + if ((identity & INTERRUPT_VBLANK) != 0) { + handled = release_vblank_sem(info); + + // make sure we'll get another one of those + write32(info.registers + RADEON_DISPLAY_A_PIPE_STATUS, + DISPLAY_PIPE_VBLANK_STATUS); + } + + // setting the bit clears it! + write16(info.registers + RADEON_INTERRUPT_IDENTITY, identity); + + return handled; +} + + +static void +init_interrupt_handler(radeon_info &info) +{ + info.shared_info->vblank_sem = create_sem(0, "radeon hd vblank"); + if (info.shared_info->vblank_sem < B_OK) + return; + + status_t status = B_OK; + + // We need to change the owner of the sem to the calling team (usually the + // app_server), because userland apps cannot acquire kernel semaphores + thread_id thread = find_thread(NULL); + thread_info threadInfo; + if (get_thread_info(thread, &threadInfo) != B_OK + || set_sem_owner(info.shared_info->vblank_sem, threadInfo.team) != B_OK) { + status = B_ERROR; + } + + if (status == B_OK && info.pci->u.h0.interrupt_pin != 0x00 + && info.pci->u.h0.interrupt_line != 0xff) { + // we've gotten an interrupt line for us to use + + info.fake_interrupts = false; + + status = install_io_interrupt_handler(info.pci->u.h0.interrupt_line, + &radeon_interrupt_handler, (void *)&info, 0); + if (status == B_OK) { + // enable interrupts - we only want VBLANK interrupts + write16(info.registers + RADEON_INTERRUPT_ENABLED, + read16(info.registers + RADEON_INTERRUPT_ENABLED) + | INTERRUPT_VBLANK); + write16(info.registers + RADEON_INTERRUPT_MASK, ~INTERRUPT_VBLANK); + + write32(info.registers + RADEON_DISPLAY_A_PIPE_STATUS, + DISPLAY_PIPE_VBLANK_STATUS); + write16(info.registers + RADEON_INTERRUPT_IDENTITY, ~0); + } + } + if (status < B_OK) { + // There is no interrupt reserved for us, or we couldn't install our + // interrupt handler, let's fake the vblank interrupt for our clients + // using a timer interrupt + info.fake_interrupts = true; + + // TODO: fake interrupts! + status = B_ERROR; + } + + if (status < B_OK) { + delete_sem(info.shared_info->vblank_sem); + info.shared_info->vblank_sem = B_ERROR; + } +} + + +// #pragma mark - + + +status_t +radeon_free_memory(radeon_info &info, addr_t base) +{ + return gGART->free_memory(info.aperture, base); +} + + +status_t +radeon_allocate_memory(radeon_info &info, size_t size, size_t alignment, + uint32 flags, addr_t *_base, addr_t *_physicalBase) +{ + return gGART->allocate_memory(info.aperture, size, alignment, + flags, _base, _physicalBase); +} + + +enum _rs780MCRegs { + RS78_MC_SYSTEM_STATUS = 0x0, + RS78_MC_FB_LOCATION = 0x10, + RS78_K8_FB_LOCATION = 0x11, + RS78_MC_MISC_UMA_CNTL = 0x12 +}; + + +status_t +radeon_hd_init(radeon_info &info) +{ + int fbIndex = 0; + int mmioIndex = 1; + if (info.device_type.InFamily(RADEON_TYPE_9xx)) { + // For some reason Intel saw the need to change the order of the + // mappings with the introduction of the i9xx family + mmioIndex = 0; + fbIndex = 2; + } + + // memory mapped I/O + + // TODO: registers are mapped twice (by us and radeon_gart), maybe we + // can share it between the drivers + +#define RHD_FB_BAR 0 +#define RHD_MMIO_BAR 2 + + + AreaKeeper sharedCreator; + info.shared_area = sharedCreator.Create("radeon hd shared info", + (void **)&info.shared_info, B_ANY_KERNEL_ADDRESS, + ROUND_TO_PAGE_SIZE(sizeof(radeon_shared_info)), B_FULL_LOCK, 0); + if (info.shared_area < B_OK) { + return info.shared_area; + } + + memset((void *)info.shared_info, 0, sizeof(radeon_shared_info)); + + AreaKeeper mmioMapper; + info.registers_area = mmioMapper.Map("radeon hd mmio", + (void *)info.pci->u.h0.base_registers[RHD_MMIO_BAR], + info.pci->u.h0.base_register_sizes[RHD_MMIO_BAR], + B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, + (void **)&info.registers); + if (mmioMapper.InitCheck() < B_OK) { + dprintf(DEVICE_NAME ": could not map memory I/O!\n"); + return info.registers_area; + } + + AreaKeeper frambufferMapper; + info.framebuffer_area = frambufferMapper.Map("radeon hd framebuffer", + (void *)info.pci->u.h0.base_registers[RHD_FB_BAR], + info.pci->u.h0.base_register_sizes[RHD_FB_BAR], + B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, + (void **)&info.shared_info->graphics_memory); + if (frambufferMapper.InitCheck() < B_OK) { + dprintf(DEVICE_NAME ": could not map framebuffer!\n"); + return info.framebuffer_area; + } + + sharedCreator.Detach(); + mmioMapper.Detach(); + frambufferMapper.Detach(); + + info.shared_info->registers_area = info.registers_area; + info.shared_info->frame_buffer_offset = 0; + info.shared_info->physical_graphics_memory = info.pci->u.h0.base_registers[RHD_FB_BAR]; + +//?? init_interrupt_handler(info); + +#define R6XX_CONFIG_MEMSIZE 0x5428 + + uint32 fbLocation = read32(info.registers + RS78_K8_FB_LOCATION); + TRACE((DEVICE_NAME "radeon_hd_init() fb pci location %x, intern location %x \n", + info.shared_info->graphics_memory, fbLocation)); + + uint32 ramSize = read32(info.registers + R6XX_CONFIG_MEMSIZE) >> 10; + TRACE((DEVICE_NAME "radeon_hd_init() ram size %i \n", ramSize)); + + + + /*TRACE((DEVICE_NAME "radeon_hd_init() fb size %i \n", + info.pci->u.h0.base_register_sizes[RHD_FB_BAR])); + + uint8* fbPosition = info.shared_info->graphics_memory; + fbPosition += 90000; + for (int i = 0; i < 90000; i++) { + *fbPosition = 255; + fbPosition++; + *fbPosition = 0; + fbPosition++; + *fbPosition = 0; + fbPosition++; + } + fbPosition += 90000; + for (int i = 0; i < 90000; i++) { + *fbPosition = 255; + fbPosition++; + *fbPosition = 0; + fbPosition++; + *fbPosition = 0; + fbPosition++; + }*/ + + TRACE((DEVICE_NAME "radeon_hd_init() completed successfully!\n")); + return B_OK; +} + + +void +radeon_hd_uninit(radeon_info &info) +{ + TRACE((DEVICE_NAME ": radeon_extreme_uninit()\n")); + + delete_area(info.shared_area); + delete_area(info.registers_area); + delete_area(info.framebuffer_area); +} + diff --git a/src/add-ons/kernel/drivers/graphics/radeon_hd/radeon_hd_private.h b/src/add-ons/kernel/drivers/graphics/radeon_hd/radeon_hd_private.h new file mode 100644 index 0000000000..3058d513a7 --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/radeon_hd/radeon_hd_private.h @@ -0,0 +1,50 @@ +/* + * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef RADEON_RD_PRIVATE_H +#define RADEON_RD_PRIVATE_H + + +#include +#include +#include + + +#include "radeon_hd.h" +#include "lock.h" + + +struct radeon_info { + int32 open_count; + status_t init_status; + int32 id; + pci_info* pci; + addr_t aperture_base; + aperture_id aperture; + uint8* registers; + area_id registers_area; + area_id framebuffer_area; + + struct radeon_shared_info* shared_info; + area_id shared_area; + + struct overlay_registers* overlay_registers; + + bool fake_interrupts; + + const char* device_identifier; + DeviceType device_type; +}; + +extern status_t radeon_free_memory(radeon_info& info, addr_t offset); +extern status_t radeon_allocate_memory(radeon_info& info, size_t size, + size_t alignment, uint32 flags, addr_t* _offset, + addr_t* _physicalBase = NULL); +extern status_t radeon_hd_init(radeon_info& info); +extern void radeon_hd_uninit(radeon_info& info); + +#endif /* RADEON_RD_PRIVATE_H */