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
This commit is contained in:
Clemens Zeidler
2010-04-13 22:35:53 +00:00
parent 2d73faba95
commit a90ebd77ee
23 changed files with 2730 additions and 21 deletions
@@ -0,0 +1,75 @@
/*
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#ifndef AREA_KEEPER_H
#define AREA_KEEPER_H
#include <KernelExport.h>
#include <OS.h>
#include <util/kernel_cpp.h>
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
+84
View File
@@ -0,0 +1,84 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#ifndef LOCK_H
#define LOCK_H
#include <OS.h>
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 */
@@ -0,0 +1,655 @@
/*
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#ifndef RADEON_HD_H
#define RADEON_HD_H
#include "lock.h"
#include <Accelerant.h>
#include <Drivers.h>
#include <PCI.h>
#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 */
@@ -0,0 +1,13 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#ifndef UTILITY_H
#define UTILITY_H
#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
#endif /* UTILITY_H */
+1
View File
@@ -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 ;
@@ -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;
}
@@ -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);
+21
View File
@@ -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 ;
@@ -0,0 +1,289 @@
/*
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#include "accelerant_protos.h"
#include "accelerant.h"
#include "utility.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <AGP.h>
#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;
}*/
@@ -0,0 +1,66 @@
/*
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#ifndef RADEON_HD_ACCELERANT_H
#define RADEON_HD_ACCELERANT_H
#include "radeon_hd.h"
#include <edid.h>
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 */
@@ -0,0 +1,49 @@
/*
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#ifndef ACCELERANT_PROTOS_H
#define ACCELERANT_PROTOS_H
#include <Accelerant.h>
#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 */
@@ -0,0 +1,57 @@
/*
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#include <Debug.h>
#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;
}
@@ -0,0 +1,57 @@
/*
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#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;
}
@@ -0,0 +1,57 @@
/*
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#include "accelerant.h"
#include "radeon_hd.h"
#include <errno.h>
#include <unistd.h>
//#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;
}
+361
View File
@@ -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, [email protected]
*/
#include "accelerant_protos.h"
#include "accelerant.h"
#include "utility.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <create_display_modes.h>
#include <ddc.h>
#include <edid.h>
#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;
}
@@ -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 ;
@@ -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 ;
@@ -0,0 +1,272 @@
/*
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#include "driver.h"
#include "device.h"
#include "radeon_hd.h"
#include "utility.h"
#include <OS.h>
#include <KernelExport.h>
#include <Drivers.h>
#include <PCI.h>
#include <SupportDefs.h>
#include <graphic_driver.h>
#include <image.h>
#include <stdlib.h>
#include <string.h>
//#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 <register> [set-to-value]\n", argv[0]);
return 0;
}
uint32 reg = parse_expression(argv[1]);
uint32 value = 0;
bool set = argc == 3;
if (set)
value = parse_expression(argv[2]);
kprintf("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;
}
@@ -0,0 +1,18 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#ifndef DEVICE_H
#define DEVICE_H
#include <Drivers.h>
/* The published PCI bus interface device hooks */
extern device_hooks gDeviceHooks;
#endif /* DEVICE_H */
@@ -0,0 +1,228 @@
/*
Copyright (c) 2002, Thomas Kurschel
*/
#include "driver.h"
#include "device.h"
#include "lock.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <AGP.h>
#include <KernelExport.h>
#include <OS.h>
#include <PCI.h>
#include <SupportDefs.h>
#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;
}
@@ -0,0 +1,54 @@
/*
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#ifndef DRIVER_H
#define DRIVER_H
#include <KernelExport.h>
#include <PCI.h>
#include <kernel/lock.h>
#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 */
@@ -0,0 +1,293 @@
/*
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#include "radeon_hd.h"
#include "AreaKeeper.h"
#include "driver.h"
#include "utility.h"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <driver_settings.h>
#include <util/kernel_cpp.h>
#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);
}
@@ -0,0 +1,50 @@
/*
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
#ifndef RADEON_RD_PRIVATE_H
#define RADEON_RD_PRIVATE_H
#include <AGP.h>
#include <KernelExport.h>
#include <PCI.h>
#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 */