Imported Gerald Zajac's ATI Mach64 / Rage driver and removed the old GPL-only mach64 driver that wasn't even part of the image anyways. Thanks!
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30962 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
cb8948154c
commit
80829ec813
|
@ -100,6 +100,7 @@ SYSTEM_ADD_ONS_ACCELERANTS = $(X86_ONLY)radeon.accelerant
|
|||
$(X86_ONLY)nvidia.accelerant $(X86_ONLY)matrox.accelerant
|
||||
$(X86_ONLY)neomagic.accelerant $(X86_ONLY)intel_extreme.accelerant
|
||||
$(X86_ONLY)s3.accelerant $(X86_ONLY)vesa.accelerant
|
||||
$(X86_ONLY)ati.accelerant
|
||||
#$(X86_ONLY)via.accelerant
|
||||
#$(X86_ONLY)vmware.accelerant
|
||||
;
|
||||
|
@ -142,6 +143,7 @@ SYSTEM_ADD_ONS_DRIVERS_AUDIO_OLD = ; #cmedia sis7018 usb_audio ;
|
|||
SYSTEM_ADD_ONS_DRIVERS_GRAPHICS = $(X86_ONLY)radeon $(X86_ONLY)nvidia
|
||||
$(X86_ONLY)neomagic $(X86_ONLY)matrox $(X86_ONLY)intel_extreme
|
||||
$(X86_ONLY)s3 $(X86_ONLY)vesa #$(X86_ONLY)via #$(X86_ONLY)vmware
|
||||
$(X86_ONLY)ati
|
||||
;
|
||||
SYSTEM_ADD_ONS_DRIVERS_MIDI = emuxki ;
|
||||
SYSTEM_ADD_ONS_DRIVERS_NET = $(X86_ONLY)3com $(X86_ONLY)broadcom440x
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
SubDir HAIKU_TOP src add-ons accelerants ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons accelerants ati ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants common ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants et6x00 ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants intel_extreme ;
|
||||
|
@ -13,5 +14,3 @@ SubInclude HAIKU_TOP src add-ons accelerants tdfx ;
|
|||
SubInclude HAIKU_TOP src add-ons accelerants vesa ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants via ;
|
||||
SubInclude HAIKU_TOP src add-ons accelerants vmware ;
|
||||
|
||||
SubIncludeGPL HAIKU_TOP src add-ons accelerants atimach64 ;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
SubDir HAIKU_TOP src add-ons accelerants ati ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics ati ] ;
|
||||
UsePrivateHeaders [ FDirName graphics common ] ;
|
||||
|
||||
Addon ati.accelerant :
|
||||
accelerant.cpp
|
||||
cursor.cpp
|
||||
engine.cpp
|
||||
hooks.cpp
|
||||
mode.cpp
|
||||
|
||||
mach64_cursor.cpp
|
||||
mach64_dpms.cpp
|
||||
mach64_draw.cpp
|
||||
mach64_init.cpp
|
||||
mach64_mode.cpp
|
||||
mach64_util.cpp
|
||||
|
||||
rage128_cursor.cpp
|
||||
rage128_dpms.cpp
|
||||
rage128_draw.cpp
|
||||
rage128_init.cpp
|
||||
rage128_mode.cpp
|
||||
|
||||
: be libaccelerantscommon.a
|
||||
;
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
Copyright 2007-2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2007-2009
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
AccelerantInfo gInfo; // global data used by various source files of accelerant.
|
||||
|
||||
|
||||
|
||||
static status_t
|
||||
InitCommon(int fileDesc)
|
||||
{
|
||||
// Initialization function used by primary and cloned accelerants.
|
||||
|
||||
gInfo.deviceFileDesc = fileDesc;
|
||||
|
||||
// Get area ID of shared data from driver.
|
||||
|
||||
area_id sharedArea;
|
||||
status_t result = ioctl(gInfo.deviceFileDesc, ATI_GET_SHARED_DATA,
|
||||
&sharedArea, sizeof(sharedArea));
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
gInfo.sharedInfoArea = clone_area("ATI shared info", (void**)&(gInfo.sharedInfo),
|
||||
B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, sharedArea);
|
||||
if (gInfo.sharedInfoArea < 0)
|
||||
return gInfo.sharedInfoArea; // sharedInfoArea has error code
|
||||
|
||||
gInfo.regsArea = clone_area("ATI regs area", (void**)&(gInfo.regs),
|
||||
B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, gInfo.sharedInfo->regsArea);
|
||||
if (gInfo.regsArea < 0) {
|
||||
delete_area(gInfo.sharedInfoArea);
|
||||
return gInfo.regsArea; // regsArea has error code
|
||||
}
|
||||
|
||||
// Set pointers to various device specific functions.
|
||||
|
||||
if (RAGE128_FAMILY(gInfo.sharedInfo->chipType))
|
||||
Rage128_SetFunctionPointers();
|
||||
else if (MACH64_FAMILY(gInfo.sharedInfo->chipType))
|
||||
Mach64_SetFunctionPointers();
|
||||
else
|
||||
return B_ERROR; // undefined chip type code
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
UninitCommon(void)
|
||||
{
|
||||
// This function is used by both primary and cloned accelerants.
|
||||
|
||||
delete_area(gInfo.regsArea);
|
||||
gInfo.regs = 0;
|
||||
|
||||
delete_area(gInfo.sharedInfoArea);
|
||||
gInfo.sharedInfo = 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InitAccelerant(int fileDesc)
|
||||
{
|
||||
// Initialize the accelerant. fileDesc is the file handle of the device
|
||||
// (in /dev/graphics) that has been opened by the app_server.
|
||||
|
||||
TRACE("Enter InitAccelerant()\n");
|
||||
|
||||
gInfo.bAccelerantIsClone = false; // indicate this is primary accelerant
|
||||
|
||||
status_t result = InitCommon(fileDesc);
|
||||
if (result == B_OK) {
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("Vendor ID: 0x%X, Device ID: 0x%X\n", si.vendorID, si.deviceID);
|
||||
|
||||
// Ensure that InitAccelerant is executed just once (copies should be clones)
|
||||
|
||||
if (si.bAccelerantInUse) {
|
||||
result = B_NOT_ALLOWED;
|
||||
} else {
|
||||
result = gInfo.ChipInit(); // perform init related to current chip
|
||||
if (result == B_OK) {
|
||||
result = si.engineLock.Init("ATI engine lock");
|
||||
if (result == B_OK) {
|
||||
if (gInfo.ShowCursor != NULL)
|
||||
gInfo.ShowCursor(false);
|
||||
|
||||
// ensure that this function won't be executed again
|
||||
// (copies should be clones)
|
||||
si.bAccelerantInUse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result != B_OK)
|
||||
UninitCommon();
|
||||
}
|
||||
|
||||
TRACE("Leave InitAccelerant(), result: 0x%X\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
AccelerantCloneInfoSize(void)
|
||||
{
|
||||
// Return the number of bytes required to hold the information required
|
||||
// to clone the device. The information is merely the name of the device;
|
||||
// thus, return the size of the name buffer.
|
||||
|
||||
return B_OS_NAME_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GetAccelerantCloneInfo(void* data)
|
||||
{
|
||||
// Return the info required to clone the device. Argument data points to
|
||||
// a buffer which is the size returned by AccelerantCloneInfoSize().
|
||||
|
||||
ioctl(gInfo.deviceFileDesc, ATI_DEVICE_NAME, data, B_OS_NAME_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CloneAccelerant(void* data)
|
||||
{
|
||||
// Initialize a copy of the accelerant as a clone. Argument data points to
|
||||
// a copy of the data which was returned by GetAccelerantCloneInfo().
|
||||
|
||||
TRACE("Enter CloneAccelerant()\n");
|
||||
|
||||
char path[MAXPATHLEN] = "/dev/";
|
||||
strcat(path, (const char*)data);
|
||||
|
||||
gInfo.deviceFileDesc = open(path, B_READ_WRITE); // open the device
|
||||
if (gInfo.deviceFileDesc < 0)
|
||||
return errno;
|
||||
|
||||
gInfo.bAccelerantIsClone = true;
|
||||
|
||||
status_t result = InitCommon(gInfo.deviceFileDesc);
|
||||
if (result != B_OK) {
|
||||
close(gInfo.deviceFileDesc);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = gInfo.modeListArea = clone_area("ATI cloned display_modes",
|
||||
(void**) &gInfo.modeList, B_ANY_ADDRESS, B_READ_AREA,
|
||||
gInfo.sharedInfo->modeArea);
|
||||
if (result < 0) {
|
||||
UninitCommon();
|
||||
close(gInfo.deviceFileDesc);
|
||||
return result;
|
||||
}
|
||||
|
||||
TRACE("Leave CloneAccelerant()\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UninitAccelerant(void)
|
||||
{
|
||||
delete_area(gInfo.modeListArea);
|
||||
gInfo.modeList = NULL;
|
||||
|
||||
UninitCommon();
|
||||
|
||||
if (gInfo.bAccelerantIsClone)
|
||||
close(gInfo.deviceFileDesc);
|
||||
}
|
||||
|
||||
|
||||
sem_id
|
||||
AccelerantRetraceSemaphore(void)
|
||||
{
|
||||
// Return the semaphore id that will be used to signal that a vertical
|
||||
// retrace occured.
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetAccelerantDeviceInfo(accelerant_device_info* adi)
|
||||
{
|
||||
// Get info about the device.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
adi->version = 1;
|
||||
strcpy(adi->name, "ATI chipset");
|
||||
strcpy(adi->serial_no, "unknown");
|
||||
adi->memory = si.maxFrameBufferSize;
|
||||
adi->dac_speed = 270;
|
||||
|
||||
// If laptop LCD display or flat panel display (ie, DVI interface), set chip
|
||||
// set name to "VESA" so that Screen Preferences will not show a refresh rate
|
||||
// since we will be using VESA code to set the video mode.
|
||||
|
||||
if (si.displayType == MT_VGA)
|
||||
strcpy(adi->chipset, si.chipName);
|
||||
else
|
||||
strcpy(adi->chipset, "VESA");
|
||||
|
||||
return B_OK;
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
Copyright 2007-2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2007-2009
|
||||
*/
|
||||
|
||||
#ifndef _ACCELERANT_H
|
||||
#define _ACCELERANT_H
|
||||
|
||||
#include "DriverInterface.h"
|
||||
|
||||
|
||||
|
||||
#undef TRACE
|
||||
|
||||
#ifdef ENABLE_DEBUG_TRACE
|
||||
extern "C" void _sPrintf(const char* format, ...);
|
||||
# define TRACE(x...) _sPrintf("ati: " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
// Global data used by various source files of the accelerant.
|
||||
|
||||
struct AccelerantInfo {
|
||||
int deviceFileDesc; // file descriptor of kernel driver
|
||||
|
||||
SharedInfo* sharedInfo; // address of info shared between accelerants & driver
|
||||
area_id sharedInfoArea; // shared info area ID
|
||||
|
||||
uint8* regs; // base address of MMIO register area
|
||||
area_id regsArea; // MMIO register area ID
|
||||
|
||||
display_mode* modeList; // list of standard display modes
|
||||
area_id modeListArea; // mode list area ID
|
||||
|
||||
bool bAccelerantIsClone; // true if this is a cloned accelerant
|
||||
|
||||
// Pointers to various global accelerant functions.
|
||||
//-------------------------------------------------
|
||||
|
||||
// Pointers to wait handlers.
|
||||
void (*WaitForFifo)(uint32);
|
||||
void (*WaitForIdle)();
|
||||
|
||||
// Pointers to DPMS functions.
|
||||
uint32 (*DPMSCapabilities)(void);
|
||||
uint32 (*GetDPMSMode)(void);
|
||||
status_t (*SetDPMSMode)(uint32 dpms_flags);
|
||||
|
||||
// Pointers to cursor functions.
|
||||
bool (*LoadCursorImage)(int width, int height, uint8* and_mask, uint8* xor_mask);
|
||||
void (*SetCursorPosition)(int x, int y);
|
||||
void (*ShowCursor)(bool bShow);
|
||||
|
||||
// Pointers to 2D acceleration functions.
|
||||
void (*FillRectangle)(engine_token*, uint32 color, fill_rect_params*, uint32 count);
|
||||
void (*FillSpan)(engine_token*, uint32 color, uint16* list, uint32 count);
|
||||
void (*InvertRectangle)(engine_token*, fill_rect_params*, uint32 count);
|
||||
void (*ScreenToScreenBlit)(engine_token*, blit_params*, uint32 count);
|
||||
|
||||
// Pointers to other functions.
|
||||
void (*AdjustFrame)(const DisplayModeEx& mode);
|
||||
status_t (*ChipInit)(void);
|
||||
bool (*GetColorSpaceParams)(int colorSpace, uint8& bpp, uint32& maxPixelClk);
|
||||
status_t (*SetDisplayMode)(const DisplayModeEx& mode);
|
||||
void (*SetIndexedColors)(uint count, uint8 first, uint8* color_data, uint32 flags);
|
||||
};
|
||||
|
||||
extern AccelerantInfo gInfo;
|
||||
|
||||
|
||||
// Prototypes of the interface functions called by the app_server. Note that
|
||||
// the functions that are unique to a particular chip family, will be prefixed
|
||||
// with the name of the family, and the functions that are applicable to all
|
||||
// chips will have no prefix.
|
||||
//================================================================
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// General
|
||||
status_t InitAccelerant(int fd);
|
||||
ssize_t AccelerantCloneInfoSize(void);
|
||||
void GetAccelerantCloneInfo(void* data);
|
||||
status_t CloneAccelerant(void* data);
|
||||
void UninitAccelerant(void);
|
||||
status_t GetAccelerantDeviceInfo(accelerant_device_info* adi);
|
||||
sem_id AccelerantRetraceSemaphore(void);
|
||||
|
||||
// Mode Configuration
|
||||
uint32 AccelerantModeCount(void);
|
||||
status_t GetModeList(display_mode* dm);
|
||||
status_t ProposeDisplayMode(display_mode* target, const display_mode* low, const display_mode* high);
|
||||
status_t SetDisplayMode(display_mode* mode_to_set);
|
||||
status_t GetDisplayMode(display_mode* current_mode);
|
||||
status_t GetFrameBufferConfig(frame_buffer_config* a_frame_buffer);
|
||||
status_t GetPixelClockLimits(display_mode* dm, uint32* low, uint32* high);
|
||||
status_t MoveDisplay(uint16 h_display_start, uint16 v_display_start);
|
||||
status_t GetTimingConstraints(display_timing_constraints* dtc);
|
||||
void Mach64_SetIndexedColors(uint count, uint8 first, uint8* color_data, uint32 flags);
|
||||
void Rage128_SetIndexedColors(uint count, uint8 first, uint8* color_data, uint32 flags);
|
||||
status_t GetPreferredDisplayMode(display_mode* preferredMode);
|
||||
status_t GetEdidInfo(void* info, size_t size, uint32* _version);
|
||||
|
||||
// DPMS
|
||||
uint32 Mach64_DPMSCapabilities(void);
|
||||
uint32 Mach64_GetDPMSMode(void);
|
||||
status_t Mach64_SetDPMSMode(uint32 dpms_flags);
|
||||
|
||||
uint32 Rage128_DPMSCapabilities(void);
|
||||
uint32 Rage128_GetDPMSMode(void);
|
||||
status_t Rage128_SetDPMSMode(uint32 dpms_flags);
|
||||
|
||||
// Cursor
|
||||
status_t SetCursorShape(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y,
|
||||
uint8* andMask, uint8* xorMask);
|
||||
void MoveCursor(uint16 x, uint16 y);
|
||||
|
||||
// Engine Management
|
||||
uint32 AccelerantEngineCount(void);
|
||||
status_t AcquireEngine(uint32 capabilities, uint32 max_wait, sync_token* st, engine_token** et);
|
||||
status_t ReleaseEngine(engine_token* et, sync_token* st);
|
||||
void WaitEngineIdle(void);
|
||||
status_t GetSyncToken(engine_token* et, sync_token* st);
|
||||
status_t SyncToToken(sync_token* st);
|
||||
|
||||
// 2D acceleration
|
||||
void Mach64_FillRectangle(engine_token* et, uint32 color, fill_rect_params* list, uint32 count);
|
||||
void Mach64_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count);
|
||||
void Mach64_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count);
|
||||
void Mach64_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count);
|
||||
|
||||
void Rage128_FillRectangle(engine_token* et, uint32 color, fill_rect_params* list, uint32 count);
|
||||
void Rage128_FillSpan(engine_token* et, uint32 color, uint16* list, uint32 count);
|
||||
void Rage128_InvertRectangle(engine_token* et, fill_rect_params* list, uint32 count);
|
||||
void Rage128_ScreenToScreenBlit(engine_token* et, blit_params* list, uint32 count);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Prototypes for other functions that are called from source files other than
|
||||
// where they are defined.
|
||||
//============================================================================
|
||||
|
||||
status_t CreateModeList(bool (*checkMode)(const display_mode* mode));
|
||||
uint16 GetVesaModeNumber(const display_mode& mode, uint8 bitsPerPixel);
|
||||
bool IsModeUsable(const display_mode* mode);
|
||||
|
||||
// Mach64 functions.
|
||||
|
||||
void Mach64_EngineReset(void);
|
||||
void Mach64_EngineInit(const DisplayModeEx& mode);
|
||||
|
||||
bool Mach64_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask);
|
||||
void Mach64_SetCursorPosition(int x, int y);
|
||||
void Mach64_ShowCursor(bool bShow);
|
||||
|
||||
void Mach64_AdjustFrame(const DisplayModeEx& mode);
|
||||
status_t Mach64_SetDisplayMode(const DisplayModeEx& mode);
|
||||
void Mach64_SetFunctionPointers(void);
|
||||
|
||||
int Mach64_Divide(int numerator, int denom, int shift, const int roundingKind);
|
||||
void Mach64_ReduceRatio(int *numerator, int *denominator);
|
||||
|
||||
|
||||
// Rage128 functions.
|
||||
|
||||
void Rage128_EngineFlush(void);
|
||||
void Rage128_EngineReset(void);
|
||||
void Rage128_EngineInit(const DisplayModeEx& mode);
|
||||
|
||||
bool Rage128_GetEdidInfo(void);
|
||||
|
||||
bool Rage128_LoadCursorImage(int width, int height, uint8* and_mask, uint8* xor_mask);
|
||||
void Rage128_SetCursorPosition(int x, int y);
|
||||
void Rage128_ShowCursor(bool bShow);
|
||||
|
||||
void Rage128_AdjustFrame(const DisplayModeEx& mode);
|
||||
status_t Rage128_SetDisplayMode(const DisplayModeEx& mode);
|
||||
void Rage128_SetFunctionPointers(void);
|
||||
|
||||
|
||||
// Macros for memory mapped I/O for both Mach64 and Rage128 chips.
|
||||
//================================================================
|
||||
|
||||
#define INREG8(addr) *((vuint8*)(gInfo.regs + addr))
|
||||
#define INREG16(addr) *((vuint16*)(gInfo.regs + addr))
|
||||
#define INREG(addr) *((vuint32*)(gInfo.regs + addr))
|
||||
|
||||
#define OUTREG8(addr, val) *((vuint8*)(gInfo.regs + addr)) = val
|
||||
#define OUTREG16(addr, val) *((vuint16*)(gInfo.regs + addr)) = val
|
||||
#define OUTREG(addr, val) *((vuint32*)(gInfo.regs + addr)) = val
|
||||
|
||||
// Write a value to an 32-bit reg using a mask. The mask selects the
|
||||
// bits to be modified.
|
||||
#define OUTREGM(addr, value, mask) \
|
||||
(OUTREG(addr, (INREG(addr) & ~mask) | (value & mask)))
|
||||
|
||||
|
||||
#endif // _ACCELERANT_H
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
Other authors:
|
||||
Gerald Zajac 2007-2008
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
|
||||
status_t
|
||||
SetCursorShape(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y,
|
||||
uint8* andMask, uint8* xorMask)
|
||||
{
|
||||
// NOTE: Currently, for BeOS, cursor width and height must be equal to 16.
|
||||
|
||||
if ((width != 16) || (height != 16)) {
|
||||
return B_ERROR;
|
||||
} else if ((hot_x >= width) || (hot_y >= height)) {
|
||||
return B_ERROR;
|
||||
} else {
|
||||
// Update cursor variables appropriately.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
si.cursorHotX = hot_x;
|
||||
si.cursorHotY = hot_y;
|
||||
|
||||
if ( ! gInfo.LoadCursorImage(width, height, andMask, xorMask))
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MoveCursor(uint16 xPos, uint16 yPos)
|
||||
{
|
||||
// Move the cursor to the specified position on the desktop. If we're
|
||||
// using some kind of virtual desktop, adjust the display start position
|
||||
// accordingly and position the cursor in the proper "virtual" location.
|
||||
|
||||
int x = xPos; // use signed int's since chip specific functions
|
||||
int y = yPos; // need signed int to determine if cursor off screen
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
DisplayModeEx& dm = si.displayMode;
|
||||
|
||||
uint16 hds = dm.h_display_start; // current horizontal starting pixel
|
||||
uint16 vds = dm.v_display_start; // current vertical starting line
|
||||
|
||||
// Clamp cursor to virtual display.
|
||||
if (x >= dm.virtual_width)
|
||||
x = dm.virtual_width - 1;
|
||||
if (y >= dm.virtual_height)
|
||||
y = dm.virtual_height - 1;
|
||||
|
||||
// Adjust h/v display start to move cursor onto screen.
|
||||
if (x >= (dm.timing.h_display + hds))
|
||||
hds = x - dm.timing.h_display + 1;
|
||||
else if (x < hds)
|
||||
hds = x;
|
||||
|
||||
if (y >= (dm.timing.v_display + vds))
|
||||
vds = y - dm.timing.v_display + 1;
|
||||
else if (y < vds)
|
||||
vds = y;
|
||||
|
||||
// Reposition the desktop on the display if required.
|
||||
if (hds != dm.h_display_start || vds != dm.v_display_start)
|
||||
MoveDisplay(hds, vds);
|
||||
|
||||
// Put cursor in correct physical position.
|
||||
x -= (hds + si.cursorHotX);
|
||||
y -= (vds + si.cursorHotY);
|
||||
|
||||
// Position the cursor on the display.
|
||||
gInfo.SetCursorPosition(x, y);
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
|
||||
Other authors:
|
||||
Gerald Zajac 2007-2008
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
|
||||
static engine_token engineToken = { 1, B_2D_ACCELERATION, NULL };
|
||||
|
||||
|
||||
uint32
|
||||
AccelerantEngineCount(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AcquireEngine(uint32 capabilities, uint32 max_wait,
|
||||
sync_token* st, engine_token** et)
|
||||
{
|
||||
(void)capabilities; // avoid compiler warning for unused arg
|
||||
(void)max_wait; // avoid compiler warning for unused arg
|
||||
|
||||
if (gInfo.sharedInfo->engineLock.Acquire() != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// Sync if required.
|
||||
if (st)
|
||||
SyncToToken(st);
|
||||
|
||||
// Return an engine token.
|
||||
*et = &engineToken;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReleaseEngine(engine_token* et, sync_token* st)
|
||||
{
|
||||
// Update the sync token, if any.
|
||||
if (st)
|
||||
GetSyncToken(et, st);
|
||||
|
||||
gInfo.sharedInfo->engineLock.Release();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WaitEngineIdle(void)
|
||||
{
|
||||
gInfo.WaitForIdle(); // wait until engine is completely idle
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetSyncToken(engine_token* et, sync_token* st)
|
||||
{
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SyncToToken(sync_token* st)
|
||||
{
|
||||
(void)st; // avoid compiler warning for unused arg
|
||||
|
||||
WaitEngineIdle();
|
||||
return B_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
Copyright 2008 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2008
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
|
||||
extern "C" void*
|
||||
get_accelerant_hook(uint32 feature, void* data)
|
||||
{
|
||||
(void)data; // avoid compiler warning for unused arg
|
||||
|
||||
switch (feature) {
|
||||
// General
|
||||
case B_INIT_ACCELERANT: return (void*)InitAccelerant;
|
||||
case B_UNINIT_ACCELERANT: return (void*)UninitAccelerant;
|
||||
case B_CLONE_ACCELERANT: return (void*)CloneAccelerant;
|
||||
case B_ACCELERANT_CLONE_INFO_SIZE: return (void*)AccelerantCloneInfoSize;
|
||||
case B_GET_ACCELERANT_CLONE_INFO: return (void*)GetAccelerantCloneInfo;
|
||||
case B_GET_ACCELERANT_DEVICE_INFO: return (void*)GetAccelerantDeviceInfo;
|
||||
case B_ACCELERANT_RETRACE_SEMAPHORE: return (void*)AccelerantRetraceSemaphore;
|
||||
|
||||
// Mode Configuration
|
||||
case B_ACCELERANT_MODE_COUNT: return (void*)AccelerantModeCount;
|
||||
case B_GET_MODE_LIST: return (void*)GetModeList;
|
||||
case B_PROPOSE_DISPLAY_MODE: return (void*)ProposeDisplayMode;
|
||||
case B_SET_DISPLAY_MODE: return (void*)SetDisplayMode;
|
||||
case B_GET_DISPLAY_MODE: return (void*)GetDisplayMode;
|
||||
case B_GET_PREFERRED_DISPLAY_MODE: return (void*)GetPreferredDisplayMode;
|
||||
case B_GET_EDID_INFO: return (void*)GetEdidInfo;
|
||||
case B_GET_FRAME_BUFFER_CONFIG: return (void*)GetFrameBufferConfig;
|
||||
case B_GET_PIXEL_CLOCK_LIMITS: return (void*)GetPixelClockLimits;
|
||||
case B_MOVE_DISPLAY: return (void*)MoveDisplay;
|
||||
case B_SET_INDEXED_COLORS: return (void*)(gInfo.SetIndexedColors);
|
||||
case B_GET_TIMING_CONSTRAINTS: return (void*)GetTimingConstraints;
|
||||
|
||||
// DPMS
|
||||
case B_DPMS_CAPABILITIES: return (void*)(gInfo.DPMSCapabilities);
|
||||
case B_DPMS_MODE: return (void*)(gInfo.GetDPMSMode);
|
||||
case B_SET_DPMS_MODE: return (void*)(gInfo.SetDPMSMode);
|
||||
|
||||
// Cursor
|
||||
case B_SET_CURSOR_SHAPE: return (void*)SetCursorShape;
|
||||
case B_MOVE_CURSOR: return (void*)MoveCursor;
|
||||
case B_SHOW_CURSOR: return (void*)(gInfo.ShowCursor);
|
||||
|
||||
// Engine Management
|
||||
case B_ACCELERANT_ENGINE_COUNT: return (void*)AccelerantEngineCount;
|
||||
case B_ACQUIRE_ENGINE: return (void*)AcquireEngine;
|
||||
case B_RELEASE_ENGINE: return (void*)ReleaseEngine;
|
||||
case B_WAIT_ENGINE_IDLE: return (void*)WaitEngineIdle;
|
||||
case B_GET_SYNC_TOKEN: return (void*)GetSyncToken;
|
||||
case B_SYNC_TO_TOKEN: return (void*)SyncToToken;
|
||||
|
||||
// 2D acceleration
|
||||
case B_SCREEN_TO_SCREEN_BLIT: return (void*)(gInfo.ScreenToScreenBlit);
|
||||
case B_FILL_RECTANGLE: return (void*)(gInfo.FillRectangle);
|
||||
case B_INVERT_RECTANGLE: return (void*)(gInfo.InvertRectangle);
|
||||
case B_FILL_SPAN: return (void*)(gInfo.FillSpan);
|
||||
}
|
||||
|
||||
return NULL; // Return null pointer for any feature not handled above
|
||||
}
|
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina.
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
#ifndef __MACH64_H__
|
||||
#define __MACH64_H__
|
||||
|
||||
|
||||
#define CURSOR_BYTES 1024 // bytes used for cursor image in video memory
|
||||
|
||||
// Memory types for Mach64 chips.
|
||||
|
||||
enum Mach64_MemoryType
|
||||
{
|
||||
MEM_NONE,
|
||||
MEM_DRAM,
|
||||
MEM_EDO,
|
||||
MEM_PSEUDO_EDO,
|
||||
MEM_SDRAM,
|
||||
MEM_SGRAM,
|
||||
MEM_SGRAM32,
|
||||
MEM_TYPE_7
|
||||
};
|
||||
|
||||
|
||||
// Macros to get/set a contiguous bit field. Arguments should not be
|
||||
// self-modifying.
|
||||
|
||||
#define UnitOf(___Value) (((((___Value) ^ ((___Value) - 1)) + 1) >> 1) \
|
||||
| ((((___Value) ^ ((___Value) - 1)) >> 1) + 1))
|
||||
|
||||
#define GetBits(__Value, _Mask) (((__Value) & (_Mask)) / UnitOf(_Mask))
|
||||
#define SetBits(__Value, _Mask) (((__Value) * UnitOf(_Mask)) & (_Mask))
|
||||
|
||||
|
||||
// Register MMIO addresses - expressed in BYTE offsets.
|
||||
//-----------------------------------------------------
|
||||
|
||||
#define CRTC_H_TOTAL_DISP (0x0c00 + 0x0000) // Dword offset 00
|
||||
#define CRTC_H_SYNC_STRT_WID (0x0c00 + 0x0004) // Dword offset 01
|
||||
#define CRTC_V_TOTAL_DISP (0x0c00 + 0x0008) // Dword offset 02
|
||||
#define CRTC_V_SYNC_STRT_WID (0x0c00 + 0x000C) // Dword offset 03
|
||||
#define CRTC_VLINE_CRNT_VLINE (0x0c00 + 0x0010) // Dword offset 04
|
||||
#define CRTC_OFF_PITCH (0x0c00 + 0x0014) // Dword offset 05
|
||||
#define CRTC_INT_CNTL (0x0c00 + 0x0018) // Dword offset 06
|
||||
#define CRTC_GEN_CNTL (0x0c00 + 0x001C) // Dword offset 07
|
||||
|
||||
#define DSP_CONFIG (0x0c00 + 0x0020) // Dword offset 08
|
||||
#define DSP_ON_OFF (0x0c00 + 0x0024) // Dword offset 09
|
||||
|
||||
#define SHARED_CNTL (0x0c00 + 0x0038) // Dword offset 0E
|
||||
|
||||
#define OVR_CLR (0x0c00 + 0x0040) // Dword offset 10
|
||||
#define OVR_WID_LEFT_RIGHT (0x0c00 + 0x0044) // Dword offset 11
|
||||
#define OVR_WID_TOP_BOTTOM (0x0c00 + 0x0048) // Dword offset 12
|
||||
|
||||
#define CUR_CLR0 (0x0c00 + 0x0060) // Dword offset 18
|
||||
#define CUR_CLR1 (0x0c00 + 0x0064) // Dword offset 19
|
||||
#define CUR_OFFSET (0x0c00 + 0x0068) // Dword offset 1A
|
||||
#define CUR_HORZ_VERT_POSN (0x0c00 + 0x006C) // Dword offset 1B
|
||||
#define CUR_HORZ_VERT_OFF (0x0c00 + 0x0070) // Dword offset 1C
|
||||
|
||||
#define HW_DEBUG (0x0c00 + 0x007C) // Dword offset 1F
|
||||
|
||||
#define SCRATCH_REG0 (0x0c00 + 0x0080) // Dword offset 20
|
||||
#define SCRATCH_REG1 (0x0c00 + 0x0084) // Dword offset 21
|
||||
|
||||
#define CLOCK_CNTL (0x0c00 + 0x0090) // Dword offset 24
|
||||
|
||||
#define BUS_CNTL (0x0c00 + 0x00A0) // Dword offset 28
|
||||
|
||||
#define LCD_INDEX (0x0c00 + 0x00A4) // Dword offset 29
|
||||
#define LCD_DATA (0x0c00 + 0x00A8) // Dword offset 2A
|
||||
|
||||
#define MEM_CNTL (0x0c00 + 0x00B0) // Dword offset 2C
|
||||
|
||||
#define MEM_VGA_WP_SEL (0x0c00 + 0x00B4) // Dword offset 2D
|
||||
#define MEM_VGA_RP_SEL (0x0c00 + 0x00B8) // Dword offset 2E
|
||||
|
||||
#define DAC_REGS (0x0c00 + 0x00C0) // Dword offset 30
|
||||
#define DAC_W_INDEX (DAC_REGS + 0)
|
||||
#define DAC_DATA (DAC_REGS + 1)
|
||||
#define DAC_MASK (DAC_REGS + 2)
|
||||
#define DAC_R_INDEX (DAC_REGS + 3)
|
||||
#define DAC_CNTL (0x0c00 + 0x00C4) // Dword offset 31
|
||||
|
||||
#define GEN_TEST_CNTL (0x0c00 + 0x00D0) // Dword offset 34
|
||||
|
||||
#define CONFIG_CNTL (0x0c00 + 0x00DC // Dword offset 37 (CT, ET, VT)
|
||||
#define CONFIG_CHIP_ID (0x0c00 + 0x00E0) // Dword offset 38
|
||||
#define CONFIG_STAT0 (0x0c00 + 0x00E4) // Dword offset 39
|
||||
#define CONFIG_STAT1 (0x0c00 + 0x00E8) // Dword offset 3A
|
||||
|
||||
#define DST_OFF_PITCH (0x0c00 + 0x0100) // Dword offset 40
|
||||
#define DST_X (0x0c00 + 0x0104) // Dword offset 41
|
||||
#define DST_Y (0x0c00 + 0x0108) // Dword offset 42
|
||||
#define DST_Y_X (0x0c00 + 0x010C) // Dword offset 43
|
||||
#define DST_WIDTH (0x0c00 + 0x0110) // Dword offset 44
|
||||
#define DST_HEIGHT (0x0c00 + 0x0114) // Dword offset 45
|
||||
#define DST_HEIGHT_WIDTH (0x0c00 + 0x0118) // Dword offset 46
|
||||
#define DST_X_WIDTH (0x0c00 + 0x011C) // Dword offset 47
|
||||
#define DST_BRES_LNTH (0x0c00 + 0x0120) // Dword offset 48
|
||||
#define DST_BRES_ERR (0x0c00 + 0x0124) // Dword offset 49
|
||||
#define DST_BRES_INC (0x0c00 + 0x0128) // Dword offset 4A
|
||||
#define DST_BRES_DEC (0x0c00 + 0x012C) // Dword offset 4B
|
||||
#define DST_CNTL (0x0c00 + 0x0130) // Dword offset 4C
|
||||
|
||||
#define SRC_OFF_PITCH (0x0c00 + 0x0180) // Dword offset 60
|
||||
#define SRC_X (0x0c00 + 0x0184) // Dword offset 61
|
||||
#define SRC_Y (0x0c00 + 0x0188) // Dword offset 62
|
||||
#define SRC_Y_X (0x0c00 + 0x018C) // Dword offset 63
|
||||
#define SRC_WIDTH1 (0x0c00 + 0x0190) // Dword offset 64
|
||||
#define SRC_HEIGHT1 (0x0c00 + 0x0194) // Dword offset 65
|
||||
#define SRC_HEIGHT1_WIDTH1 (0x0c00 + 0x0198) // Dword offset 66
|
||||
#define SRC_X_START (0x0c00 + 0x019C) // Dword offset 67
|
||||
#define SRC_Y_START (0x0c00 + 0x01A0) // Dword offset 68
|
||||
#define SRC_Y_X_START (0x0c00 + 0x01A4) // Dword offset 69
|
||||
#define SRC_WIDTH2 (0x0c00 + 0x01A8) // Dword offset 6A
|
||||
#define SRC_HEIGHT2 (0x0c00 + 0x01AC) // Dword offset 6B
|
||||
#define SRC_HEIGHT2_WIDTH2 (0x0c00 + 0x01B0) // Dword offset 6C
|
||||
#define SRC_CNTL (0x0c00 + 0x01B4) // Dword offset 6D
|
||||
|
||||
#define HOST_DATA0 (0x0c00 + 0x0200) // Dword offset 80
|
||||
#define HOST_DATA1 (0x0c00 + 0x0204) // Dword offset 81
|
||||
#define HOST_DATA2 (0x0c00 + 0x0208) // Dword offset 82
|
||||
#define HOST_DATA3 (0x0c00 + 0x020C) // Dword offset 83
|
||||
#define HOST_DATA4 (0x0c00 + 0x0210) // Dword offset 84
|
||||
#define HOST_DATA5 (0x0c00 + 0x0214) // Dword offset 85
|
||||
#define HOST_DATA6 (0x0c00 + 0x0218) // Dword offset 86
|
||||
#define HOST_DATA7 (0x0c00 + 0x021C) // Dword offset 87
|
||||
#define HOST_DATA8 (0x0c00 + 0x0220) // Dword offset 88
|
||||
#define HOST_DATA9 (0x0c00 + 0x0224) // Dword offset 89
|
||||
#define HOST_DATAA (0x0c00 + 0x0228) // Dword offset 8A
|
||||
#define HOST_DATAB (0x0c00 + 0x022C) // Dword offset 8B
|
||||
#define HOST_DATAC (0x0c00 + 0x0230) // Dword offset 8C
|
||||
#define HOST_DATAD (0x0c00 + 0x0234) // Dword offset 8D
|
||||
#define HOST_DATAE (0x0c00 + 0x0238) // Dword offset 8E
|
||||
#define HOST_DATAF (0x0c00 + 0x023C) // Dword offset 8F
|
||||
#define HOST_CNTL (0x0c00 + 0x0240) // Dword offset 90
|
||||
|
||||
#define PAT_REG0 (0x0c00 + 0x0280) // Dword offset A0
|
||||
#define PAT_REG1 (0x0c00 + 0x0284) // Dword offset A1
|
||||
#define PAT_CNTL (0x0c00 + 0x0288) // Dword offset A2
|
||||
|
||||
#define SC_LEFT (0x0c00 + 0x02A0) // Dword offset A8
|
||||
#define SC_RIGHT (0x0c00 + 0x02A4) // Dword offset A9
|
||||
#define SC_LEFT_RIGHT (0x0c00 + 0x02A8) // Dword offset AA
|
||||
#define SC_TOP (0x0c00 + 0x02AC) // Dword offset AB
|
||||
#define SC_BOTTOM (0x0c00 + 0x02B0) // Dword offset AC
|
||||
#define SC_TOP_BOTTOM (0x0c00 + 0x02B4) // Dword offset AD
|
||||
|
||||
#define DP_BKGD_CLR (0x0c00 + 0x02C0) // Dword offset B0
|
||||
#define DP_FRGD_CLR (0x0c00 + 0x02C4) // Dword offset B1
|
||||
#define DP_WRITE_MASK (0x0c00 + 0x02C8) // Dword offset B2
|
||||
#define DP_CHAIN_MASK (0x0c00 + 0x02CC) // Dword offset B3
|
||||
#define DP_PIX_WIDTH (0x0c00 + 0x02D0) // Dword offset B4
|
||||
#define DP_MIX (0x0c00 + 0x02D4) // Dword offset B5
|
||||
#define DP_SRC (0x0c00 + 0x02D8) // Dword offset B6
|
||||
|
||||
#define CLR_CMP_CLR (0x0c00 + 0x0300) // Dword offset C0
|
||||
#define CLR_CMP_MASK (0x0c00 + 0x0304) // Dword offset C1
|
||||
#define CLR_CMP_CNTL (0x0c00 + 0x0308) // Dword offset C2
|
||||
|
||||
#define FIFO_STAT (0x0c00 + 0x0310) // Dword offset C4
|
||||
|
||||
#define CONTEXT_MASK (0x0c00 + 0x0320) // Dword offset C8
|
||||
#define CONTEXT_LOAD_CNTL (0x0c00 + 0x032C) // Dword offset CB
|
||||
|
||||
#define GUI_TRAJ_CNTL (0x0c00 + 0x0330) // Dword offset CC
|
||||
#define GUI_STAT (0x0c00 + 0x0338) // Dword offset CE
|
||||
|
||||
|
||||
// CRTC control values.
|
||||
|
||||
#define CRTC_H_SYNC_NEG 0x00200000
|
||||
#define CRTC_V_SYNC_NEG 0x00200000
|
||||
|
||||
#define CRTC_DBL_SCAN_EN 0x00000001
|
||||
#define CRTC_INTERLACE_EN 0x00000002
|
||||
#define CRTC_HSYNC_DIS 0x00000004
|
||||
#define CRTC_VSYNC_DIS 0x00000008
|
||||
#define CRTC_CSYNC_EN 0x00000010
|
||||
#define CRTC_PIX_BY_2_EN 0x00000020
|
||||
#define CRTC_DISPLAY_DIS 0x00000040
|
||||
#define CRTC_VGA_XOVERSCAN 0x00000080
|
||||
|
||||
#define CRTC_PIX_WIDTH 0x00000700
|
||||
#define CRTC_PIX_WIDTH_4BPP 0x00000100
|
||||
#define CRTC_PIX_WIDTH_8BPP 0x00000200
|
||||
#define CRTC_PIX_WIDTH_15BPP 0x00000300
|
||||
#define CRTC_PIX_WIDTH_16BPP 0x00000400
|
||||
#define CRTC_PIX_WIDTH_24BPP 0x00000500
|
||||
#define CRTC_PIX_WIDTH_32BPP 0x00000600
|
||||
|
||||
#define CRTC_BYTE_PIX_ORDER 0x00000800
|
||||
#define CRTC_PIX_ORDER_MSN_LSN 0x00000000
|
||||
#define CRTC_PIX_ORDER_LSN_MSN 0x00000800
|
||||
|
||||
#define CRTC_FIFO_LWM 0x000f0000
|
||||
#define CRTC2_PIX_WIDTH 0x000e0000
|
||||
#define CRTC_VGA_128KAP_PAGING 0x00100000
|
||||
#define CRTC_VFC_SYNC_TRISTATE 0x00200000
|
||||
#define CRTC2_EN 0x00200000
|
||||
#define CRTC_LOCK_REGS 0x00400000
|
||||
#define CRTC_SYNC_TRISTATE 0x00800000
|
||||
#define CRTC_EXT_DISP_EN 0x01000000
|
||||
#define CRTC_EN 0x02000000
|
||||
#define CRTC_DISP_REQ_EN 0x04000000
|
||||
#define CRTC_VGA_LINEAR 0x08000000
|
||||
#define CRTC_VGA_TEXT_132 0x20000000
|
||||
#define CRTC_CNT_EN 0x40000000
|
||||
#define CRTC_CUR_B_TEST 0x80000000
|
||||
|
||||
#define CRTC_CRNT_VLINE 0x07f00000
|
||||
#define CRTC_VBLANK 0x00000001
|
||||
|
||||
#define CRTC_PITCH 0xffc00000
|
||||
|
||||
// DAC control values.
|
||||
|
||||
#define DAC_8BIT_EN 0x00000100
|
||||
|
||||
// Mix control values.
|
||||
|
||||
#define MIX_NOT_DST 0x0000
|
||||
#define MIX_0 0x0001
|
||||
#define MIX_1 0x0002
|
||||
#define MIX_DST 0x0003
|
||||
#define MIX_NOT_SRC 0x0004
|
||||
#define MIX_XOR 0x0005
|
||||
#define MIX_XNOR 0x0006
|
||||
#define MIX_SRC 0x0007
|
||||
#define MIX_NAND 0x0008
|
||||
#define MIX_NOT_SRC_OR_DST 0x0009
|
||||
#define MIX_SRC_OR_NOT_DST 0x000a
|
||||
#define MIX_OR 0x000b
|
||||
#define MIX_AND 0x000c
|
||||
#define MIX_SRC_AND_NOT_DST 0x000d
|
||||
#define MIX_NOT_SRC_AND_DST 0x000e
|
||||
#define MIX_NOR 0x000f
|
||||
|
||||
// BUS_CNTL register constants.
|
||||
#define BUS_FIFO_ERR_ACK 0x00200000
|
||||
#define BUS_HOST_ERR_ACK 0x00800000
|
||||
#define BUS_APER_REG_DIS 0x00000010
|
||||
|
||||
// GEN_TEST_CNTL register constants.
|
||||
#define GEN_OVR_OUTPUT_EN 0x20
|
||||
#define HWCURSOR_ENABLE 0x80
|
||||
#define GUI_ENGINE_ENABLE 0x100
|
||||
|
||||
// DSP_CONFIG register constants.
|
||||
#define DSP_XCLKS_PER_QW 0x00003fff
|
||||
#define DSP_LOOP_LATENCY 0x000f0000
|
||||
#define DSP_PRECISION 0x00700000
|
||||
|
||||
// DSP_ON_OFF register constants.
|
||||
#define DSP_OFF 0x000007ff
|
||||
#define DSP_ON 0x07ff0000
|
||||
|
||||
// CLOCK_CNTL register constants.
|
||||
#define CLOCK_SEL 0x0f
|
||||
#define CLOCK_DIV 0x30
|
||||
#define CLOCK_DIV1 0x00
|
||||
#define CLOCK_DIV2 0x10
|
||||
#define CLOCK_DIV4 0x20
|
||||
#define CLOCK_STROBE 0x40
|
||||
#define PLL_WR_EN 0x02
|
||||
#define PLL_ADDR 0xfc
|
||||
|
||||
// PLL registers.
|
||||
#define PLL_MACRO_CNTL 0x01
|
||||
#define PLL_REF_DIV 0x02
|
||||
#define PLL_GEN_CNTL 0x03
|
||||
#define PLL_MCLK_FB_DIV 0x04
|
||||
#define PLL_VCLK_CNTL 0x05
|
||||
#define PLL_VCLK_POST_DIV 0x06
|
||||
#define PLL_VCLK0_FB_DIV 0x07
|
||||
#define PLL_VCLK1_FB_DIV 0x08
|
||||
#define PLL_VCLK2_FB_DIV 0x09
|
||||
#define PLL_VCLK3_FB_DIV 0x0A
|
||||
#define PLL_XCLK_CNTL 0x0B
|
||||
#define PLL_TEST_CTRL 0x0E
|
||||
#define PLL_TEST_COUNT 0x0F
|
||||
|
||||
// Fields in PLL registers.
|
||||
#define PLL_PC_GAIN 0x07
|
||||
#define PLL_VC_GAIN 0x18
|
||||
#define PLL_DUTY_CYC 0xE0
|
||||
#define PLL_MFB_TIMES_4_2B 0x08
|
||||
#define PLL_VCLK0_XDIV 0x10
|
||||
#define PLL_OVERRIDE 0x01
|
||||
#define PLL_MCLK_RST 0x02
|
||||
#define OSC_EN 0x04
|
||||
#define EXT_CLK_EN 0x08
|
||||
#define MCLK_SRC_SEL 0x70
|
||||
#define EXT_CLK_CNTL 0x80
|
||||
#define PLL_VCLK_SRC_SEL 0x03
|
||||
#define PLL_VCLK_RESET 0x04
|
||||
#define VCLK_INVERT 0x08
|
||||
#define VCLK0_POST 0x03
|
||||
#define VCLK1_POST 0x0C
|
||||
#define VCLK2_POST 0x30
|
||||
#define VCLK3_POST 0xC0
|
||||
|
||||
// MEM_CNTL register constants.
|
||||
#define CTL_MEM_TRP 0x00000300
|
||||
#define CTL_MEM_TRCD 0x00000C00
|
||||
#define CTL_MEM_TCRD 0x00001000
|
||||
#define CTL_MEM_TRAS 0x00070000
|
||||
|
||||
// DST_CNTL register constants.
|
||||
#define DST_X_LEFT_TO_RIGHT 1
|
||||
#define DST_Y_TOP_TO_BOTTOM 2
|
||||
#define DST_LAST_PEL 0x20
|
||||
|
||||
// SRC_CNTL register constants.
|
||||
#define SRC_LINE_X_LEFT_TO_RIGHT 0x10
|
||||
|
||||
// HOST_CNTL register constants.
|
||||
#define HOST_BYTE_ALIGN 1
|
||||
|
||||
// DP_CHAIN_MASK register constants.
|
||||
#define DP_CHAIN_4BPP 0x8888
|
||||
#define DP_CHAIN_7BPP 0xD2D2
|
||||
#define DP_CHAIN_8BPP 0x8080
|
||||
#define DP_CHAIN_8BPP_RGB 0x9292
|
||||
#define DP_CHAIN_15BPP 0x4210
|
||||
#define DP_CHAIN_16BPP 0x8410
|
||||
#define DP_CHAIN_24BPP 0x8080
|
||||
#define DP_CHAIN_32BPP 0x8080
|
||||
|
||||
// DP_PIX_WIDTH register constants.
|
||||
#define DST_1BPP 0
|
||||
#define DST_4BPP 1
|
||||
#define DST_8BPP 2
|
||||
#define DST_15BPP 3
|
||||
#define DST_16BPP 4
|
||||
#define DST_32BPP 6
|
||||
#define SRC_1BPP 0
|
||||
#define SRC_4BPP 0x100
|
||||
#define SRC_8BPP 0x200
|
||||
#define SRC_15BPP 0x300
|
||||
#define SRC_16BPP 0x400
|
||||
#define SRC_32BPP 0x600
|
||||
#define HOST_1BPP 0
|
||||
#define HOST_4BPP 0x10000
|
||||
#define HOST_8BPP 0x20000
|
||||
#define HOST_15BPP 0x30000
|
||||
#define HOST_16BPP 0x40000
|
||||
#define HOST_32BPP 0x60000
|
||||
#define BYTE_ORDER_MSB_TO_LSB 0
|
||||
#define BYTE_ORDER_LSB_TO_MSB 0x1000000
|
||||
|
||||
// DP_SRC register constants.
|
||||
#define BKGD_SRC_BKGD_CLR 0
|
||||
#define FRGD_SRC_FRGD_CLR 0x100
|
||||
#define FRGD_SRC_BLIT 0x300
|
||||
#define MONO_SRC_ONE 0
|
||||
|
||||
// GUI_STAT register constants.
|
||||
#define ENGINE_BUSY 1
|
||||
|
||||
// LCD Index register constants.
|
||||
#define LCD_REG_INDEX 0x0000003F
|
||||
#define LCD_DISPLAY_DIS 0x00000100
|
||||
#define LCD_SRC_SEL 0x00000200
|
||||
#define CRTC2_DISPLAY_DIS 0x00000400
|
||||
|
||||
// LCD register indices.
|
||||
#define LCD_CONFIG_PANEL 0x00
|
||||
#define LCD_GEN_CNTL 0x01
|
||||
#define LCD_DSTN_CONTROL 0x02
|
||||
#define LCD_HFB_PITCH_ADDR 0x03
|
||||
#define LCD_HORZ_STRETCHING 0x04
|
||||
#define LCD_VERT_STRETCHING 0x05
|
||||
#define LCD_EXT_VERT_STRETCH 0x06
|
||||
#define LCD_LT_GIO 0x07
|
||||
#define LCD_POWER_MANAGEMENT 0x08
|
||||
|
||||
// LCD_CONFIG_PANEL register constants.
|
||||
#define DONT_SHADOW_HEND 0x00004000
|
||||
|
||||
// LCD_GEN_CNTL register constants.
|
||||
#define CRT_ON 0x00000001
|
||||
#define LCD_ON 0x00000002
|
||||
#define HORZ_DIVBY2_EN 0x00000004
|
||||
#define LOCK_8DOT 0x00000010
|
||||
#define DONT_SHADOW_VPAR 0x00000040
|
||||
#define DIS_HOR_CRT_DIVBY2 0x00000400
|
||||
#define MCLK_PM_EN 0x00010000
|
||||
#define VCLK_DAC_PM_EN 0x00020000
|
||||
#define CRTC_RW_SELECT 0x08000000
|
||||
#define USE_SHADOWED_VEND 0x10000000
|
||||
#define USE_SHADOWED_ROWCUR 0x20000000
|
||||
#define SHADOW_EN 0x40000000
|
||||
#define SHADOW_RW_EN 0x80000000
|
||||
|
||||
// LCD_HORZ_STRETCHING register constants.
|
||||
#define HORZ_STRETCH_BLEND 0x00000fff
|
||||
#define HORZ_STRETCH_RATIO 0x0000ffff
|
||||
#define HORZ_STRETCH_LOOP 0x00070000
|
||||
#define HORZ_PANEL_SIZE 0x0ff00000
|
||||
#define AUTO_HORZ_RATIO 0x20000000
|
||||
#define HORZ_STRETCH_MODE 0x40000000
|
||||
#define HORZ_STRETCH_EN 0x80000000
|
||||
|
||||
// LCD_VERT_STRETCHING register constants.
|
||||
#define VERT_STRETCH_RATIO0 0x000003ff
|
||||
#define VERT_STRETCH_RATIO1 0x000ffc00
|
||||
#define VERT_STRETCH_RATIO2 0x3ff00000
|
||||
#define VERT_STRETCH_USE0 0x40000000
|
||||
#define VERT_STRETCH_EN 0x80000000
|
||||
|
||||
// LCD_EXT_VERT_STRETCH register constants.
|
||||
#define VERT_STRETCH_RATIO3 0x000003ff
|
||||
#define FORCE_DAC_DATA 0x000000ff
|
||||
#define FORCE_DAC_DATA_SEL 0x00000300
|
||||
#define VERT_STRETCH_MODE 0x00000400
|
||||
#define VERT_PANEL_SIZE 0x003ff800
|
||||
#define AUTO_VERT_RATIO 0x00400000
|
||||
#define USE_AUTO_FP_POS 0x00800000
|
||||
#define USE_AUTO_LCD_VSYNC 0x01000000
|
||||
|
||||
// LCD_POWER_MANAGEMENT register constants.
|
||||
#define AUTO_POWER_UP 0x00000008
|
||||
#define POWER_BLON 0x02000000
|
||||
#define STANDBY_NOW 0x10000000
|
||||
#define SUSPEND_NOW 0x20000000
|
||||
|
||||
|
||||
|
||||
// Functions to get/set PLL registers.
|
||||
//=======================================
|
||||
|
||||
static inline uint8
|
||||
Mach64_GetPLLReg(uint8 index)
|
||||
{
|
||||
OUTREG8(CLOCK_CNTL + 1, (index << 2) & PLL_ADDR);
|
||||
return INREG8(CLOCK_CNTL + 2);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
Mach64_SetPLLReg(uint8 index, uint8 value)
|
||||
{
|
||||
OUTREG8(CLOCK_CNTL + 1, ((index << 2) & PLL_ADDR) | PLL_WR_EN);
|
||||
OUTREG8(CLOCK_CNTL + 2, value);
|
||||
}
|
||||
|
||||
|
||||
static inline uint32
|
||||
Mach64_GetLCDReg(int index)
|
||||
{
|
||||
OUTREG8(LCD_INDEX, index & LCD_REG_INDEX);
|
||||
return INREG(LCD_DATA);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
Mach64_PutLCDReg(int index, uint32 value)
|
||||
{
|
||||
OUTREG8(LCD_INDEX, index & LCD_REG_INDEX);
|
||||
OUTREG(LCD_DATA, value);
|
||||
}
|
||||
|
||||
|
||||
#endif // __MACH64_H__
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "mach64.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
void
|
||||
Mach64_ShowCursor(bool bShow)
|
||||
{
|
||||
// Turn cursor on/off.
|
||||
|
||||
OUTREGM(GEN_TEST_CNTL, bShow ? HWCURSOR_ENABLE : 0, HWCURSOR_ENABLE);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Mach64_SetCursorPosition(int x, int y)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
// xOffset & yOffset are used for displaying partial cursors on screen edges.
|
||||
|
||||
uint8 xOffset = 0;
|
||||
uint8 yOffset = 0;
|
||||
|
||||
if (x < 0) {
|
||||
xOffset = -x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
yOffset = -y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
OUTREG(CUR_OFFSET, (si.cursorOffset >> 3) + (yOffset << 1));
|
||||
OUTREG(CUR_HORZ_VERT_OFF, (yOffset << 16) | xOffset);
|
||||
OUTREG(CUR_HORZ_VERT_POSN, (y << 16) | x);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Mach64_LoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if (andMask == NULL || xorMask == NULL)
|
||||
return false;
|
||||
|
||||
uint16* fbCursor = (uint16*)((addr_t)si.videoMemAddr + si.cursorOffset);
|
||||
|
||||
// Initialize the hardware cursor as completely transparent.
|
||||
|
||||
memset(fbCursor, 0xaa, CURSOR_BYTES);
|
||||
|
||||
// Now load the AND & XOR masks for the cursor image into the cursor
|
||||
// buffer. Note that a particular bit in these masks will have the
|
||||
// following effect upon the corresponding cursor pixel:
|
||||
// AND XOR Result
|
||||
// 0 0 White pixel
|
||||
// 0 1 Black pixel
|
||||
// 1 0 Screen color (for transparency)
|
||||
// 1 1 Reverse screen color to black or white
|
||||
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int colByte = 0; colByte < width / 8; colByte++) {
|
||||
// Convert the 8 bit AND and XOR masks into a 16 bit mask containing
|
||||
// pairs of the bits from the AND and XOR maks.
|
||||
|
||||
uint8 andBits = *andMask++;
|
||||
uint8 xorBits = *xorMask++;
|
||||
uint16 cursorBits = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
cursorBits <<= 2;
|
||||
cursorBits |= ((andBits & 0x01) << 1);
|
||||
cursorBits |= (xorBits & 0x01);
|
||||
andBits >>= 1;
|
||||
xorBits >>= 1;
|
||||
}
|
||||
|
||||
fbCursor[row * 8 + colByte] = cursorBits;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the cursor colors which are white background and black foreground.
|
||||
|
||||
OUTREG(CUR_CLR0, ~0);
|
||||
OUTREG(CUR_CLR1, 0);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina.
|
||||
Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "mach64.h"
|
||||
|
||||
|
||||
|
||||
uint32
|
||||
Mach64_DPMSCapabilities(void)
|
||||
{
|
||||
// Return DPMS modes supported by this device.
|
||||
|
||||
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
Mach64_GetDPMSMode(void)
|
||||
{
|
||||
// Return the current DPMS mode.
|
||||
|
||||
uint32 tmp = INREG(CRTC_GEN_CNTL);
|
||||
uint32 mode;
|
||||
|
||||
if( (tmp & CRTC_DISPLAY_DIS) == 0 )
|
||||
mode = B_DPMS_ON;
|
||||
else if( (tmp & CRTC_VSYNC_DIS) == 0 )
|
||||
mode = B_DPMS_STAND_BY;
|
||||
else if( (tmp & CRTC_HSYNC_DIS) == 0 )
|
||||
mode = B_DPMS_SUSPEND;
|
||||
else
|
||||
mode = B_DPMS_OFF;
|
||||
|
||||
TRACE("Mach64_DPMSMode() mode: %d\n", mode);
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Mach64_SetDPMSMode(uint32 dpmsMode)
|
||||
{
|
||||
// Set the display into one of the Display Power Management modes,
|
||||
// and return B_OK if successful, else return B_ERROR.
|
||||
|
||||
TRACE("Mach64_SetDPMSMode() mode: %d, display type: %d\n", dpmsMode, gInfo.sharedInfo->displayType);
|
||||
|
||||
int mask = (CRTC_HSYNC_DIS | CRTC_VSYNC_DIS);
|
||||
|
||||
switch (dpmsMode) {
|
||||
case B_DPMS_ON:
|
||||
// Screen: On; HSync: On, VSync: On.
|
||||
OUTREGM(CRTC_GEN_CNTL, 0, mask);
|
||||
break;
|
||||
|
||||
case B_DPMS_STAND_BY:
|
||||
// Screen: Off; HSync: Off, VSync: On.
|
||||
OUTREGM(CRTC_GEN_CNTL, CRTC_HSYNC_DIS, mask);
|
||||
break;
|
||||
|
||||
case B_DPMS_SUSPEND:
|
||||
// Screen: Off; HSync: On, VSync: Off.
|
||||
OUTREGM(CRTC_GEN_CNTL, CRTC_VSYNC_DIS, mask);
|
||||
break;
|
||||
|
||||
case B_DPMS_OFF:
|
||||
// Screen: Off; HSync: Off, VSync: Off.
|
||||
OUTREGM(CRTC_GEN_CNTL, mask, mask);
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("Invalid DPMS mode %d\n", dpmsMode);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (gInfo.sharedInfo->displayType == MT_LAPTOP) {
|
||||
uint32 powerMgmt = (Mach64_GetLCDReg(LCD_POWER_MANAGEMENT)
|
||||
& ~(STANDBY_NOW | SUSPEND_NOW | POWER_BLON | AUTO_POWER_UP));
|
||||
|
||||
switch (dpmsMode) {
|
||||
case B_DPMS_ON:
|
||||
powerMgmt |= (POWER_BLON | AUTO_POWER_UP);
|
||||
break;
|
||||
|
||||
case B_DPMS_STAND_BY:
|
||||
powerMgmt |= STANDBY_NOW;
|
||||
break;
|
||||
|
||||
case B_DPMS_SUSPEND:
|
||||
powerMgmt |= SUSPEND_NOW;
|
||||
break;
|
||||
|
||||
case B_DPMS_OFF:
|
||||
powerMgmt |= STANDBY_NOW | SUSPEND_NOW;
|
||||
break;
|
||||
}
|
||||
|
||||
Mach64_PutLCDReg(LCD_POWER_MANAGEMENT, powerMgmt);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina.
|
||||
Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "mach64.h"
|
||||
|
||||
|
||||
|
||||
void
|
||||
Mach64_EngineReset()
|
||||
{
|
||||
// Reset engine and then enable it.
|
||||
|
||||
uint32 genTestCntl = INREG(GEN_TEST_CNTL) & ~GUI_ENGINE_ENABLE;
|
||||
OUTREG(GEN_TEST_CNTL, genTestCntl);
|
||||
OUTREG(GEN_TEST_CNTL, genTestCntl | GUI_ENGINE_ENABLE);
|
||||
|
||||
// Ensure engine is not locked up by clearing any FIFO errors.
|
||||
|
||||
OUTREG(BUS_CNTL, INREG(BUS_CNTL) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Mach64_EngineInit(const DisplayModeEx& mode)
|
||||
{
|
||||
// Initialize the drawing environment and clear the display.
|
||||
|
||||
Mach64_EngineReset();
|
||||
|
||||
gInfo.WaitForIdle();
|
||||
|
||||
OUTREG(MEM_VGA_WP_SEL, 0x00010000);
|
||||
OUTREG(MEM_VGA_RP_SEL, 0x00010000);
|
||||
|
||||
uint32 dpPixWidth = 0;
|
||||
uint32 dpChainMask = 0;
|
||||
|
||||
switch (mode.bitsPerPixel) {
|
||||
case 8:
|
||||
dpPixWidth = HOST_8BPP | SRC_8BPP | DST_8BPP;
|
||||
dpChainMask = DP_CHAIN_8BPP;
|
||||
break;
|
||||
case 15:
|
||||
dpPixWidth = HOST_15BPP | SRC_15BPP | DST_15BPP;
|
||||
dpChainMask = DP_CHAIN_15BPP;
|
||||
break;
|
||||
case 16:
|
||||
dpPixWidth = HOST_16BPP | SRC_16BPP | DST_16BPP;
|
||||
dpChainMask = DP_CHAIN_16BPP;
|
||||
break;
|
||||
case 32:
|
||||
dpPixWidth = HOST_32BPP | SRC_32BPP | DST_32BPP;
|
||||
dpChainMask = DP_CHAIN_32BPP;
|
||||
break;
|
||||
}
|
||||
|
||||
dpPixWidth |= BYTE_ORDER_LSB_TO_MSB; // set for little-endian byte order
|
||||
|
||||
gInfo.WaitForFifo(3);
|
||||
OUTREG(DP_PIX_WIDTH, dpPixWidth);
|
||||
OUTREG(DP_CHAIN_MASK, dpChainMask);
|
||||
|
||||
OUTREG(CONTEXT_MASK, 0xffffffff);
|
||||
|
||||
gInfo.WaitForFifo(7);
|
||||
OUTREG(DST_OFF_PITCH, (mode.timing.h_display / 8) << 22);
|
||||
OUTREG(DST_Y_X, 0);
|
||||
OUTREG(DST_HEIGHT, 0);
|
||||
OUTREG(DST_BRES_ERR, 0);
|
||||
OUTREG(DST_BRES_INC, 0);
|
||||
OUTREG(DST_BRES_DEC, 0);
|
||||
OUTREG(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM | DST_LAST_PEL);
|
||||
|
||||
gInfo.WaitForFifo(6);
|
||||
OUTREG(SRC_OFF_PITCH, (mode.timing.h_display / 8) << 22);
|
||||
OUTREG(SRC_Y_X, 0);
|
||||
OUTREG(SRC_HEIGHT1_WIDTH1, 0x10001);
|
||||
OUTREG(SRC_Y_X_START, 0);
|
||||
OUTREG(SRC_HEIGHT2_WIDTH2, 0x10001);
|
||||
OUTREG(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT);
|
||||
|
||||
gInfo.WaitForFifo(7);
|
||||
OUTREGM(HOST_CNTL, 0, HOST_BYTE_ALIGN);
|
||||
OUTREG(PAT_REG0, 0);
|
||||
OUTREG(PAT_REG1, 0);
|
||||
OUTREG(PAT_CNTL, 0);
|
||||
|
||||
OUTREG(SC_LEFT_RIGHT, ((mode.timing.h_display << 16) | 0 ));
|
||||
OUTREG(SC_TOP_BOTTOM, ((mode.timing.v_display << 16) | 0 ));
|
||||
|
||||
gInfo.WaitForFifo(9);
|
||||
OUTREG(DP_BKGD_CLR, 0);
|
||||
OUTREG(DP_FRGD_CLR, 0xffffffff);
|
||||
OUTREG(DP_WRITE_MASK, 0xffffffff);
|
||||
OUTREG(DP_MIX, (MIX_SRC << 16) | MIX_DST);
|
||||
OUTREG(DP_SRC, FRGD_SRC_FRGD_CLR);
|
||||
|
||||
OUTREG(CLR_CMP_CLR, 0);
|
||||
OUTREG(CLR_CMP_MASK, 0xffffffff);
|
||||
OUTREG(CLR_CMP_CNTL, 0);
|
||||
|
||||
gInfo.WaitForIdle();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Mach64_FillRectangle(engine_token *et, uint32 color, fill_rect_params *pList, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
gInfo.WaitForFifo(4);
|
||||
OUTREG(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
|
||||
OUTREG(DP_FRGD_CLR, color);
|
||||
OUTREG(DP_MIX, (MIX_SRC << 16) | MIX_DST);
|
||||
OUTREG(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM | DST_LAST_PEL);
|
||||
|
||||
while (count--) {
|
||||
int x = pList->left;
|
||||
int y = pList->top;
|
||||
int w = pList->right - x + 1;
|
||||
int h = pList->bottom - y + 1;
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(DST_Y_X, (x << 16) | y);
|
||||
OUTREG(DST_HEIGHT_WIDTH, (w << 16) | h);
|
||||
|
||||
pList++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Mach64_FillSpan(engine_token *et, uint32 color, uint16 *pList, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
gInfo.WaitForFifo(4);
|
||||
OUTREG(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
|
||||
OUTREG(DP_FRGD_CLR, color);
|
||||
OUTREG(DP_MIX, (MIX_SRC << 16) | MIX_DST);
|
||||
OUTREG(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM | DST_LAST_PEL);
|
||||
|
||||
while (count--) {
|
||||
int y = *pList++;
|
||||
int x = *pList++;
|
||||
int w = *pList++ - x + 1;
|
||||
|
||||
if (w <= 0)
|
||||
continue; // discard span with zero or negative width
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(DST_Y_X, (x << 16) | y);
|
||||
OUTREG(DST_HEIGHT_WIDTH, (w << 16) | 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Mach64_InvertRectangle(engine_token *et, fill_rect_params *pList, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
gInfo.WaitForFifo(3);
|
||||
OUTREG(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE);
|
||||
OUTREG(DP_MIX, MIX_NOT_DST << 16);
|
||||
OUTREG(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM | DST_LAST_PEL);
|
||||
|
||||
while (count--) {
|
||||
int x = pList->left;
|
||||
int y = pList->top;
|
||||
int w = pList->right - x + 1;
|
||||
int h = pList->bottom - y + 1;
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(DST_Y_X, (x << 16) | y);
|
||||
OUTREG(DST_HEIGHT_WIDTH, (w << 16) | h);
|
||||
|
||||
pList++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Mach64_ScreenToScreenBlit(engine_token *et, blit_params *pList, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(DP_SRC, FRGD_SRC_BLIT);
|
||||
OUTREG(DP_MIX, MIX_SRC << 16);
|
||||
|
||||
while (count--) {
|
||||
int cmd = DST_LAST_PEL;
|
||||
int src_x = pList->src_left;
|
||||
int src_y = pList->src_top;
|
||||
int dest_x = pList->dest_left;
|
||||
int dest_y = pList->dest_top;
|
||||
int width = pList->width;
|
||||
int height = pList->height;
|
||||
|
||||
if (dest_x <= src_x) {
|
||||
cmd |= DST_X_LEFT_TO_RIGHT;
|
||||
} else {
|
||||
src_x += width;
|
||||
dest_x += width;
|
||||
}
|
||||
|
||||
if (dest_y <= src_y) {
|
||||
cmd |= DST_Y_TOP_TO_BOTTOM;
|
||||
} else {
|
||||
src_y += height;
|
||||
dest_y += height;
|
||||
}
|
||||
|
||||
gInfo.WaitForFifo(5);
|
||||
OUTREG(DST_CNTL, cmd);
|
||||
OUTREG(SRC_Y_X, (src_x << 16) | src_y);
|
||||
OUTREG(SRC_HEIGHT1_WIDTH1, ((width + 1) << 16) | (height + 1));
|
||||
OUTREG(DST_Y_X, (dest_x << 16) | dest_y);
|
||||
OUTREG(DST_HEIGHT_WIDTH, ((width + 1) << 16) | (height + 1));
|
||||
|
||||
pList ++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina.
|
||||
Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "mach64.h"
|
||||
|
||||
|
||||
|
||||
static bool
|
||||
Mach64_InitDSPParams()
|
||||
{
|
||||
// Initialize global variables used to set DSP registers on a VT-B or later.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
M64_Params& params = si.m64Params;
|
||||
|
||||
// Retrieve XCLK settings.
|
||||
|
||||
uint8 ioValue = Mach64_GetPLLReg(PLL_XCLK_CNTL);
|
||||
params.xClkPostDivider = ioValue & 0x7;
|
||||
|
||||
switch (params.xClkPostDivider) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
params.xClkRefDivider = 1;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
params.xClkRefDivider = 3;
|
||||
params.xClkPostDivider = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("Unsupported XCLK source: %d.\n", params.xClkPostDivider);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioValue & PLL_MFB_TIMES_4_2B)
|
||||
params.xClkPostDivider--;
|
||||
|
||||
// Compute maximum RAS delay and related params.
|
||||
|
||||
uint32 memCntl = INREG(MEM_CNTL);
|
||||
int trp = GetBits(memCntl, CTL_MEM_TRP);
|
||||
params.xClkPageFaultDelay = GetBits(memCntl, CTL_MEM_TRCD) +
|
||||
GetBits(memCntl, CTL_MEM_TCRD) + trp + 2;
|
||||
params.xClkMaxRASDelay = GetBits(memCntl, CTL_MEM_TRAS) + trp + 2;
|
||||
|
||||
params.displayFIFODepth = 32;
|
||||
|
||||
if (si.chipType < MACH64_264VT4) {
|
||||
params.xClkPageFaultDelay += 2;
|
||||
params.xClkMaxRASDelay += 3;
|
||||
params.displayFIFODepth = 24;
|
||||
}
|
||||
|
||||
// Determine type of memory used with the chip.
|
||||
|
||||
int memType = INREG(CONFIG_STAT0) & 0x7;
|
||||
TRACE("Memory type: %d\n", memType);
|
||||
|
||||
switch (memType) {
|
||||
case MEM_DRAM:
|
||||
if (si.videoMemSize <= 1024 * 1024) {
|
||||
params.displayLoopLatency = 10;
|
||||
} else {
|
||||
params.displayLoopLatency = 8;
|
||||
params.xClkPageFaultDelay += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case MEM_EDO:
|
||||
case MEM_PSEUDO_EDO:
|
||||
if (si.videoMemSize <= 1024 * 1024) {
|
||||
params.displayLoopLatency = 9;
|
||||
} else {
|
||||
params.displayLoopLatency = 8;
|
||||
params.xClkPageFaultDelay++;
|
||||
}
|
||||
break;
|
||||
|
||||
case MEM_SDRAM:
|
||||
if (si.videoMemSize <= 1024 * 1024) {
|
||||
params.displayLoopLatency = 11;
|
||||
} else {
|
||||
params.displayLoopLatency = 10;
|
||||
params.xClkPageFaultDelay++;
|
||||
}
|
||||
break;
|
||||
|
||||
case MEM_SGRAM:
|
||||
params.displayLoopLatency = 8;
|
||||
params.xClkPageFaultDelay += 3;
|
||||
break;
|
||||
|
||||
default: /* Set maximums */
|
||||
params.displayLoopLatency = 11;
|
||||
params.xClkPageFaultDelay += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (params.xClkMaxRASDelay <= params.xClkPageFaultDelay)
|
||||
params.xClkMaxRASDelay = params.xClkPageFaultDelay + 1;
|
||||
|
||||
uint32 dspConfig = INREG(DSP_CONFIG);
|
||||
if (dspConfig)
|
||||
params.displayLoopLatency = GetBits(dspConfig, DSP_LOOP_LATENCY);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
Mach64_GetColorSpaceParams(int colorSpace, uint8& bitsPerPixel, uint32& maxPixelClock)
|
||||
{
|
||||
// Get parameters for a color space which is supported by the Mach64 chips.
|
||||
// Argument maxPixelClock is in KHz.
|
||||
// Return true if the color space is supported; else return false.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
switch (colorSpace) {
|
||||
case B_RGB32:
|
||||
bitsPerPixel = 32;
|
||||
break;
|
||||
case B_RGB16:
|
||||
bitsPerPixel = 16;
|
||||
break;
|
||||
case B_RGB15:
|
||||
bitsPerPixel = 15;
|
||||
break;
|
||||
case B_CMAP8:
|
||||
bitsPerPixel = 8;
|
||||
break;
|
||||
default:
|
||||
TRACE("Unsupported color space: 0x%X\n", colorSpace);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (si.chipType >= MACH64_264VTB) {
|
||||
if ((si.chipType >= MACH64_264VT4) && (si.chipType != MACH64_264LTPRO))
|
||||
maxPixelClock = 230000;
|
||||
else if (si.chipType >= MACH64_264VT3)
|
||||
maxPixelClock = 200000;
|
||||
else
|
||||
maxPixelClock = 170000;
|
||||
} else {
|
||||
if (bitsPerPixel == 8)
|
||||
maxPixelClock = 135000;
|
||||
else
|
||||
maxPixelClock = 80000;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
Mach64_Init(void)
|
||||
{
|
||||
TRACE("Mach64_Init()\n");
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
static const int videoRamSizes[] =
|
||||
{ 512, 1024, 2*1024, 4*1024, 6*1024, 8*1024, 12*1024, 16*1024 };
|
||||
|
||||
uint32 memCntl = INREG(MEM_CNTL);
|
||||
if (si.chipType < MACH64_264VTB) {
|
||||
si.videoMemSize = videoRamSizes[memCntl & 0x7] * 1024;
|
||||
} else {
|
||||
uint32 ioValue = (memCntl & 0xf);
|
||||
if (ioValue < 8)
|
||||
si.videoMemSize = (ioValue + 1) * 512 * 1024;
|
||||
else if (ioValue < 12)
|
||||
si.videoMemSize = (ioValue - 3) * 1024 * 1024;
|
||||
else
|
||||
si.videoMemSize = (ioValue - 7) * 2048 * 1024;
|
||||
}
|
||||
|
||||
si.cursorOffset = (si.videoMemSize - CURSOR_BYTES) & ~0xfff; // align to 4k boundary
|
||||
si.frameBufferOffset = 0;
|
||||
si.maxFrameBufferSize = si.cursorOffset - si.frameBufferOffset;
|
||||
|
||||
TRACE("Video Memory size: %d MB frameBufferOffset: 0x%x cursorOffset: 0x%x\n",
|
||||
si.videoMemSize / 1024 / 1024, si.frameBufferOffset, si.cursorOffset);
|
||||
|
||||
// 264VT-B's and later have DSP registers.
|
||||
|
||||
if ((si.chipType >= MACH64_264VTB) && !Mach64_InitDSPParams())
|
||||
return B_ERROR;
|
||||
|
||||
// Determine if the LCD display of a laptop computer is active.
|
||||
|
||||
si.displayType = MT_VGA;
|
||||
|
||||
if (si.chipType == MACH64_MOBILITY && si.panelX > 0 && si.panelY > 0) {
|
||||
if (Mach64_GetLCDReg(LCD_GEN_CNTL) & LCD_ON)
|
||||
si.displayType = MT_LAPTOP;
|
||||
}
|
||||
|
||||
// Set up the array of color spaces supported by the Mach64 chips.
|
||||
|
||||
si.colorSpaces[0] = B_CMAP8;
|
||||
si.colorSpaces[1] = B_RGB15;
|
||||
si.colorSpaces[2] = B_RGB16;
|
||||
si.colorSpaces[3] = B_RGB32;
|
||||
si.colorSpaceCount = 4;
|
||||
|
||||
// Setup the mode list.
|
||||
|
||||
return CreateModeList(IsModeUsable);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Mach64_WaitForFifo(uint32 entries)
|
||||
{
|
||||
// The FIFO has 16 slots. This routines waits until at least `entries'
|
||||
// of these slots are empty.
|
||||
|
||||
while ((INREG(FIFO_STAT) & 0xffff) > (0x8000ul >> entries)) ;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Mach64_WaitForIdle()
|
||||
{
|
||||
// Wait for the graphics engine to be completely idle. That is, the FIFO
|
||||
// has drained, the Pixel Cache is flushed, and the engine is idle. This
|
||||
// is a standard "sync" function that will make the hardware "quiescent".
|
||||
|
||||
Mach64_WaitForFifo(16);
|
||||
|
||||
while (INREG(GUI_STAT) & ENGINE_BUSY) ;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Mach64_SetFunctionPointers(void)
|
||||
{
|
||||
// Setting the function pointers must be done prior to first ModeInit call
|
||||
// or any accel activity.
|
||||
|
||||
gInfo.WaitForFifo = Mach64_WaitForFifo;
|
||||
gInfo.WaitForIdle = Mach64_WaitForIdle;
|
||||
|
||||
gInfo.DPMSCapabilities = Mach64_DPMSCapabilities;
|
||||
gInfo.GetDPMSMode = Mach64_GetDPMSMode;
|
||||
gInfo.SetDPMSMode = Mach64_SetDPMSMode;
|
||||
|
||||
gInfo.LoadCursorImage = Mach64_LoadCursorImage;
|
||||
gInfo.SetCursorPosition = Mach64_SetCursorPosition;
|
||||
gInfo.ShowCursor = Mach64_ShowCursor;
|
||||
|
||||
gInfo.FillRectangle = Mach64_FillRectangle;
|
||||
gInfo.FillSpan = Mach64_FillSpan;
|
||||
gInfo.InvertRectangle = Mach64_InvertRectangle;
|
||||
gInfo.ScreenToScreenBlit = Mach64_ScreenToScreenBlit;
|
||||
|
||||
gInfo.AdjustFrame = Mach64_AdjustFrame;
|
||||
gInfo.ChipInit = Mach64_Init;
|
||||
gInfo.GetColorSpaceParams = Mach64_GetColorSpaceParams;
|
||||
gInfo.SetDisplayMode = Mach64_SetDisplayMode;
|
||||
gInfo.SetIndexedColors = Mach64_SetIndexedColors;
|
||||
}
|
||||
|
|
@ -0,0 +1,410 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina.
|
||||
Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "mach64.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
|
||||
static void SetClockRegisters(const DisplayModeEx& mode)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
M64_Params& params = si.m64Params;
|
||||
|
||||
int p;
|
||||
int postDiv;
|
||||
bool extendedDiv = false;
|
||||
uint32 pixelClock = mode.timing.pixel_clock;
|
||||
|
||||
if (pixelClock > params.maxPixelClock)
|
||||
pixelClock = params.maxPixelClock;
|
||||
|
||||
double q = ((pixelClock / 10.0) * params.refDivider) / (2.0 * params.refFreq);
|
||||
|
||||
if (si.chipType >= MACH64_264VTB) {
|
||||
if (q > 255) {
|
||||
TRACE("SetClockRegisters(): Warning: q > 255\n");
|
||||
q = 255;
|
||||
p = 0;
|
||||
postDiv = 1;
|
||||
} else if (q > 127.5) {
|
||||
p = 0;
|
||||
postDiv = 1;
|
||||
} else if (q > 85) {
|
||||
p = 1;
|
||||
postDiv = 2;
|
||||
} else if (q > 63.75) {
|
||||
p = 0;
|
||||
postDiv = 3;
|
||||
extendedDiv = true;
|
||||
} else if (q > 42.5) {
|
||||
p = 2;
|
||||
postDiv = 4;
|
||||
} else if (q > 31.875) {
|
||||
p = 2;
|
||||
postDiv = 6;
|
||||
extendedDiv = true;
|
||||
} else if (q > 21.25) {
|
||||
p = 3;
|
||||
postDiv = 8;
|
||||
} else if (q >= 10.6666666667) {
|
||||
p = 3;
|
||||
postDiv = 12;
|
||||
extendedDiv = true;
|
||||
} else {
|
||||
TRACE("SetClockRegisters(): Warning: q < 10.66666667\n");
|
||||
p = 3;
|
||||
postDiv = 12;
|
||||
extendedDiv = true;
|
||||
}
|
||||
} else {
|
||||
if (q > 255) {
|
||||
TRACE("SetClockRegisters(): Warning: q > 255\n");
|
||||
q = 255;
|
||||
p = 0;
|
||||
} else if (q > 127.5)
|
||||
p = 0;
|
||||
else if (q > 63.75)
|
||||
p = 1;
|
||||
else if (q > 31.875)
|
||||
p = 2;
|
||||
else if (q >= 16)
|
||||
p = 3;
|
||||
else {
|
||||
TRACE("SetClockRegisters(): Warning: q < 16\n");
|
||||
p = 3;
|
||||
}
|
||||
postDiv = 1 << p;
|
||||
}
|
||||
|
||||
uint8 fbDiv = uint8(q * postDiv);
|
||||
|
||||
// With some chips such as those with ID's 4750 & 475A, the display has
|
||||
// ripples when using resolution 1440x900 at 60 Hz refresh rate.
|
||||
// Decrementing fbDiv by 1 seems to fix this problem.
|
||||
|
||||
if (mode.timing.h_display == 1440 && pixelClock < 108000)
|
||||
fbDiv--;
|
||||
|
||||
int clkNum = params.clockNumberToProgram;
|
||||
|
||||
OUTREG8(CLOCK_CNTL, clkNum | CLOCK_STROBE);
|
||||
|
||||
// Temporarily switch to accelerator mode.
|
||||
uint32 crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
|
||||
if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
|
||||
OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN);
|
||||
|
||||
// Reset VCLK generator.
|
||||
uint8 vclkCntl = Mach64_GetPLLReg(PLL_VCLK_CNTL);
|
||||
Mach64_SetPLLReg(PLL_VCLK_CNTL, vclkCntl | PLL_VCLK_RESET);
|
||||
|
||||
// Set post-divider.
|
||||
uint8 tmp = Mach64_GetPLLReg(PLL_VCLK_POST_DIV);
|
||||
Mach64_SetPLLReg(PLL_VCLK_POST_DIV,
|
||||
(tmp & ~(0x03 << (2 * clkNum))) | (p << (2 * clkNum)));
|
||||
|
||||
// Set feedback divider.
|
||||
Mach64_SetPLLReg(PLL_VCLK0_FB_DIV + clkNum, fbDiv);
|
||||
|
||||
// Set extended post-divider.
|
||||
if (si.chipType >= MACH64_264VTB) {
|
||||
tmp = Mach64_GetPLLReg(PLL_XCLK_CNTL);
|
||||
if (extendedDiv)
|
||||
Mach64_SetPLLReg(PLL_XCLK_CNTL, tmp | (0x10 << clkNum));
|
||||
else
|
||||
Mach64_SetPLLReg(PLL_XCLK_CNTL, tmp & ~(0x10 << clkNum));
|
||||
}
|
||||
|
||||
// End VCLK generator reset.
|
||||
Mach64_SetPLLReg(PLL_VCLK_CNTL, vclkCntl & ~PLL_VCLK_RESET);
|
||||
|
||||
snooze(5000);
|
||||
INREG8(DAC_W_INDEX); // Clear DAC counter
|
||||
|
||||
if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
|
||||
OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl); // Restore register
|
||||
|
||||
// Save parameters that will be used for computing the DSP parameters.
|
||||
|
||||
params.vClkPostDivider = postDiv;
|
||||
params.vClkFeedbackDivider = fbDiv;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
SetDSPRegisters(const DisplayModeEx& mode)
|
||||
{
|
||||
// Set up DSP register values for a VTB or later.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
M64_Params& params = si.m64Params;
|
||||
|
||||
#define Maximum_DSP_PRECISION 7
|
||||
|
||||
uint8 mClkFeedbackDivider = Mach64_GetPLLReg(PLL_MCLK_FB_DIV);
|
||||
|
||||
/* Compute a memory-to-screen bandwidth ratio */
|
||||
uint32 multiplier = uint32(mClkFeedbackDivider) * params.vClkPostDivider;
|
||||
uint32 divider = uint32(params.vClkFeedbackDivider) * params.xClkRefDivider;
|
||||
divider *= ((mode.bitsPerPixel + 1) / 4);
|
||||
|
||||
// Start by assuming a display FIFO width of 64 bits.
|
||||
|
||||
int vshift = (6 - 2) - params.xClkPostDivider;
|
||||
|
||||
int RASMultiplier = params.xClkMaxRASDelay;
|
||||
int RASDivider = 1;
|
||||
|
||||
// Determine dsp_precision first.
|
||||
|
||||
int tmp = Mach64_Divide(multiplier * params.displayFIFODepth, divider, vshift, -1);
|
||||
int dsp_precision;
|
||||
|
||||
for (dsp_precision = -5; tmp; dsp_precision++)
|
||||
tmp >>= 1;
|
||||
if (dsp_precision < 0)
|
||||
dsp_precision = 0;
|
||||
else if (dsp_precision > Maximum_DSP_PRECISION)
|
||||
dsp_precision = Maximum_DSP_PRECISION;
|
||||
|
||||
int xshift = 6 - dsp_precision;
|
||||
vshift += xshift;
|
||||
|
||||
int dsp_off = Mach64_Divide(multiplier * (params.displayFIFODepth - 1),
|
||||
divider, vshift, -1) - Mach64_Divide(1, 1, vshift - xshift, 1);
|
||||
|
||||
int dsp_on = Mach64_Divide(multiplier, divider, vshift, 1);
|
||||
tmp = Mach64_Divide(RASMultiplier, RASDivider, xshift, 1);
|
||||
if (dsp_on < tmp)
|
||||
dsp_on = tmp;
|
||||
dsp_on += (tmp * 2) +
|
||||
Mach64_Divide(params.xClkPageFaultDelay, 1, xshift, 1);
|
||||
|
||||
/* Calculate rounding factor and apply it to dsp_on */
|
||||
tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1;
|
||||
dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1);
|
||||
|
||||
if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1))) {
|
||||
dsp_on = dsp_off - Mach64_Divide(multiplier, divider, vshift, -1);
|
||||
dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1);
|
||||
}
|
||||
|
||||
int dsp_xclks = Mach64_Divide(multiplier, divider, vshift + 5, 1);
|
||||
|
||||
// Build DSP register contents.
|
||||
|
||||
uint32 dsp_on_off = SetBits(dsp_on, DSP_ON)
|
||||
| SetBits(dsp_off, DSP_OFF);
|
||||
uint32 dsp_config = SetBits(dsp_precision, DSP_PRECISION)
|
||||
| SetBits(dsp_xclks, DSP_XCLKS_PER_QW)
|
||||
| SetBits(params.displayLoopLatency, DSP_LOOP_LATENCY);
|
||||
|
||||
OUTREG(DSP_ON_OFF, dsp_on_off);
|
||||
OUTREG(DSP_CONFIG, dsp_config);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
SetCrtcRegisters(const DisplayModeEx& mode)
|
||||
{
|
||||
// Calculate the CRTC register values for requested video mode, and then set
|
||||
// set the registers to the calculated values.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
uint32 crtc_h_total_disp = ((mode.timing.h_total / 8) - 1)
|
||||
| (((mode.timing.h_display / 8) - 1) << 16);
|
||||
|
||||
int hSyncWidth = (mode.timing.h_sync_end - mode.timing.h_sync_start) / 8;
|
||||
if (hSyncWidth > 0x3f)
|
||||
hSyncWidth = 0x3f;
|
||||
|
||||
int hSyncStart = mode.timing.h_sync_start / 8 - 1;
|
||||
|
||||
uint32 crtc_h_sync_strt_wid = (hSyncWidth << 16)
|
||||
| (hSyncStart & 0xff) | ((hSyncStart & 0x100) << 4)
|
||||
| ((mode.timing.flags & B_POSITIVE_HSYNC) ? 0 : CRTC_H_SYNC_NEG);
|
||||
|
||||
uint32 crtc_v_total_disp = ((mode.timing.v_total - 1)
|
||||
| ((mode.timing.v_display - 1) << 16));
|
||||
|
||||
int vSyncWidth = mode.timing.v_sync_end - mode.timing.v_sync_start;
|
||||
if (vSyncWidth > 0x1f)
|
||||
vSyncWidth = 0x1f;
|
||||
|
||||
uint32 crtc_v_sync_strt_wid = (mode.timing.v_sync_start - 1)
|
||||
| (vSyncWidth << 16)
|
||||
| ((mode.timing.flags & B_POSITIVE_VSYNC) ? 0 : CRTC_V_SYNC_NEG);
|
||||
|
||||
uint32 crtc_off_pitch = SetBits(mode.timing.h_display >> 3, CRTC_PITCH);
|
||||
|
||||
uint32 crtc_gen_cntl = INREG(CRTC_GEN_CNTL) &
|
||||
~(CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN |
|
||||
CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_CSYNC_EN |
|
||||
CRTC_PIX_BY_2_EN | CRTC_VGA_XOVERSCAN |
|
||||
CRTC_PIX_WIDTH | CRTC_BYTE_PIX_ORDER |
|
||||
CRTC_VGA_128KAP_PAGING | CRTC_VFC_SYNC_TRISTATE |
|
||||
CRTC_LOCK_REGS | // already off, but ...
|
||||
CRTC_SYNC_TRISTATE | CRTC_DISP_REQ_EN |
|
||||
CRTC_VGA_TEXT_132 | CRTC_CUR_B_TEST);
|
||||
|
||||
crtc_gen_cntl |= CRTC_EXT_DISP_EN | CRTC_EN | CRTC_VGA_LINEAR | CRTC_CNT_EN;
|
||||
|
||||
switch (mode.bitsPerPixel) {
|
||||
case 8:
|
||||
crtc_gen_cntl |= CRTC_PIX_WIDTH_8BPP;
|
||||
break;
|
||||
case 15:
|
||||
crtc_gen_cntl |= CRTC_PIX_WIDTH_15BPP;
|
||||
break;
|
||||
case 16:
|
||||
crtc_gen_cntl |= CRTC_PIX_WIDTH_16BPP;
|
||||
break;
|
||||
case 32:
|
||||
crtc_gen_cntl |= CRTC_PIX_WIDTH_32BPP;
|
||||
break;
|
||||
default:
|
||||
TRACE("Undefined color depth, bitsPerPixel: %d\n", mode.bitsPerPixel);
|
||||
break;
|
||||
}
|
||||
|
||||
// For now, set display FIFO low water mark as high as possible.
|
||||
if (si.chipType < MACH64_264VTB)
|
||||
crtc_gen_cntl |= CRTC_FIFO_LWM;
|
||||
|
||||
|
||||
// Write the CRTC registers.
|
||||
//--------------------------
|
||||
|
||||
// Stop CRTC.
|
||||
OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN));
|
||||
|
||||
OUTREG(CRTC_H_TOTAL_DISP, crtc_h_total_disp);
|
||||
OUTREG(CRTC_H_SYNC_STRT_WID, crtc_h_sync_strt_wid);
|
||||
OUTREG(CRTC_V_TOTAL_DISP, crtc_v_total_disp);
|
||||
OUTREG(CRTC_V_SYNC_STRT_WID, crtc_v_sync_strt_wid);
|
||||
|
||||
OUTREG(CRTC_OFF_PITCH, crtc_off_pitch);
|
||||
|
||||
// Clear overscan registers.
|
||||
OUTREG(OVR_CLR, 0);
|
||||
OUTREG(OVR_WID_LEFT_RIGHT, 0);
|
||||
OUTREG(OVR_WID_TOP_BOTTOM, 0);
|
||||
|
||||
// Finalise CRTC setup and turn on the screen.
|
||||
OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
Mach64_SetDisplayMode(const DisplayModeEx& mode)
|
||||
{
|
||||
// The code to actually configure the display.
|
||||
// All the error checking must be done in ProposeDisplayMode(),
|
||||
// and assume that the mode values we get here are acceptable.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if (si.displayType == MT_VGA) {
|
||||
// Chip is connected to a monitor via a VGA connector.
|
||||
|
||||
SetCrtcRegisters(mode);
|
||||
SetClockRegisters(mode);
|
||||
|
||||
if (si.chipType >= MACH64_264VTB)
|
||||
SetDSPRegisters(mode);
|
||||
|
||||
} else {
|
||||
// Chip is connected to a laptop LCD monitor; or via a DVI interface.
|
||||
|
||||
uint16 vesaMode = GetVesaModeNumber(display_mode(mode), mode.bitsPerPixel);
|
||||
if (vesaMode == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
status_t status = ioctl(gInfo.deviceFileDesc, ATI_SET_VESA_DISPLAY_MODE,
|
||||
&vesaMode, sizeof(vesaMode));
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
Mach64_AdjustFrame(mode);
|
||||
|
||||
// Initialize the palette so that the various color depths will display
|
||||
// the correct colors.
|
||||
|
||||
OUTREGM(DAC_CNTL, DAC_8BIT_EN, DAC_8BIT_EN);
|
||||
OUTREG8(DAC_MASK, 0xff);
|
||||
OUTREG8(DAC_W_INDEX, 0); // initial color index
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
OUTREG8(DAC_DATA, i);
|
||||
OUTREG8(DAC_DATA, i);
|
||||
OUTREG8(DAC_DATA, i);
|
||||
}
|
||||
|
||||
Mach64_EngineInit(mode);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Mach64_AdjustFrame(const DisplayModeEx& mode)
|
||||
{
|
||||
// Adjust start address in frame buffer.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
int address = (mode.v_display_start * mode.virtual_width
|
||||
+ mode.h_display_start) * ((mode.bitsPerPixel + 1) / 8);
|
||||
|
||||
address &= ~0x07;
|
||||
address += si.frameBufferOffset;
|
||||
|
||||
OUTREGM(CRTC_OFF_PITCH, address, 0xfffff);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Mach64_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
|
||||
{
|
||||
// Set the indexed color palette for 8-bit color depth mode.
|
||||
|
||||
(void)flags; // avoid compiler warning for unused arg
|
||||
|
||||
if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
|
||||
return ;
|
||||
|
||||
OUTREG8(DAC_MASK, 0xff);
|
||||
OUTREG8(DAC_W_INDEX, first); // initial color index
|
||||
|
||||
while (count--) {
|
||||
OUTREG8(DAC_DATA, colorData[0]); // red
|
||||
OUTREG8(DAC_DATA, colorData[1]); // green
|
||||
OUTREG8(DAC_DATA, colorData[2]); // blue
|
||||
|
||||
colorData += 3;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "mach64.h"
|
||||
|
||||
|
||||
#define MAX_INT ((int)((unsigned int)(-1) >> 2))
|
||||
|
||||
|
||||
|
||||
void
|
||||
Mach64_ReduceRatio(int *numerator, int *denominator)
|
||||
{
|
||||
// Reduce a fraction by factoring out the largest common divider of the
|
||||
// fraction's numerator and denominator.
|
||||
|
||||
int multiplier = *numerator;
|
||||
int divider = *denominator;
|
||||
int remainder;
|
||||
|
||||
while ((remainder = multiplier % divider)) {
|
||||
multiplier = divider;
|
||||
divider = remainder;
|
||||
}
|
||||
|
||||
*numerator /= divider;
|
||||
*denominator /= divider;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
Mach64_Divide(int numerator, int denominator, int shift, const int roundingKind)
|
||||
{
|
||||
// Using integer arithmetic and avoiding overflows, this function finds the
|
||||
// rounded integer that best approximates
|
||||
//
|
||||
// numerator shift
|
||||
// ----------- * 2
|
||||
// denominator
|
||||
//
|
||||
// using the specified rounding (floor (<0), nearest (=0) or ceiling (>0)).
|
||||
|
||||
Mach64_ReduceRatio(&numerator, &denominator);
|
||||
|
||||
// Deal with left shifts but try to keep the denominator even.
|
||||
if (denominator & 1) {
|
||||
if (denominator <= MAX_INT) {
|
||||
denominator <<= 1;
|
||||
shift++;
|
||||
}
|
||||
} else {
|
||||
while ((shift > 0) && !(denominator & 3)) {
|
||||
denominator >>= 1;
|
||||
shift--;
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with right shifts.
|
||||
while (shift < 0) {
|
||||
if ((numerator & 1) && (denominator <= MAX_INT))
|
||||
denominator <<= 1;
|
||||
else
|
||||
numerator >>= 1;
|
||||
|
||||
shift++;
|
||||
}
|
||||
|
||||
int rounding = 0; // Default to floor
|
||||
|
||||
if (!roundingKind) // nearest
|
||||
rounding = denominator >> 1;
|
||||
else if (roundingKind > 0) // ceiling
|
||||
rounding = denominator - 1;
|
||||
|
||||
return ((numerator / denominator) << shift) +
|
||||
((((numerator % denominator) << shift) + rounding) / denominator);
|
||||
}
|
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
Copyright 2007-2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2007-2009
|
||||
*/
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
#include <create_display_modes.h> // common accelerant header file
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
static display_mode*
|
||||
FindDisplayMode(int width, int height, int refreshRate, uint32 colorDepth)
|
||||
{
|
||||
// Search the mode list for the mode with specified width, height,
|
||||
// refresh rate, and color depth. If argument colorDepth is zero, this
|
||||
// function will search for a mode satisfying the other 3 arguments, and
|
||||
// if more than one matching mode is found, the one with the greatest color
|
||||
// depth will be selected.
|
||||
//
|
||||
// If successful, return a pointer to the selected display_mode object;
|
||||
// else return NULL.
|
||||
|
||||
display_mode* selectedMode = NULL;
|
||||
uint32 modeCount = gInfo.sharedInfo->modeCount;
|
||||
|
||||
for (uint32 j = 0; j < modeCount; j++) {
|
||||
display_mode& mode = gInfo.modeList[j];
|
||||
|
||||
if (mode.timing.h_display == width && mode.timing.v_display == height) {
|
||||
int modeRefreshRate = int(((mode.timing.pixel_clock * 1000.0 /
|
||||
mode.timing.h_total) / mode.timing.v_total) + 0.5);
|
||||
if (modeRefreshRate == refreshRate) {
|
||||
if (colorDepth == 0) {
|
||||
if (selectedMode == NULL || mode.space > selectedMode->space)
|
||||
selectedMode = &mode;
|
||||
} else {
|
||||
if (mode.space == colorDepth)
|
||||
return &mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedMode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool
|
||||
IsThereEnoughFBMemory(const display_mode* mode, uint32 bitsPerPixel)
|
||||
{
|
||||
// Test if there is enough Frame Buffer memory for the mode and color depth
|
||||
// specified by the caller, and return true if there is sufficient memory.
|
||||
|
||||
uint32 maxWidth = mode->virtual_width;
|
||||
if (mode->timing.h_display > maxWidth)
|
||||
maxWidth = mode->timing.h_display;
|
||||
|
||||
uint32 maxHeight = mode->virtual_height;
|
||||
if (mode->timing.v_display > maxHeight)
|
||||
maxHeight = mode->timing.v_display;
|
||||
|
||||
uint32 bytesPerPixel = (bitsPerPixel + 7) / 8;
|
||||
|
||||
return (maxWidth * maxHeight * bytesPerPixel < gInfo.sharedInfo->maxFrameBufferSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint16
|
||||
GetVesaModeNumber(const display_mode& mode, uint8 bitsPerPixel)
|
||||
{
|
||||
// Search VESA mode table for a matching mode, and return the VESA mode
|
||||
// number if a match is found; else return 0 if no match is found.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
VesaMode* vesaModeTable = (VesaMode*)((uint8*)&si + si.vesaModeTableOffset);
|
||||
|
||||
for (uint32 j = 0; j < si.vesaModeCount; j++) {
|
||||
VesaMode& vesaMode = vesaModeTable[j];
|
||||
|
||||
if (vesaMode.width == mode.timing.h_display
|
||||
&& vesaMode.height == mode.timing.v_display
|
||||
&& vesaMode.bitsPerPixel == bitsPerPixel)
|
||||
return vesaMode.mode;
|
||||
}
|
||||
|
||||
return 0; // matching VESA mode not found
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
IsModeUsable(const display_mode* mode)
|
||||
{
|
||||
// Test if the display mode is usable by the current video chip. That is,
|
||||
// does the chip have enough memory for the mode and is the pixel clock
|
||||
// within the chips allowable range, etc.
|
||||
//
|
||||
// Return true if the mode is usable.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
uint8 bitsPerPixel;
|
||||
uint32 maxPixelClock;
|
||||
|
||||
if (!gInfo.GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock))
|
||||
return false;
|
||||
|
||||
// Is there enough frame buffer memory to handle the mode?
|
||||
|
||||
if (!IsThereEnoughFBMemory(mode, bitsPerPixel))
|
||||
return false;
|
||||
|
||||
if (si.displayType == MT_VGA) {
|
||||
// Test if mode is usable for a chip that is connected to a monitor
|
||||
// via an analog VGA connector.
|
||||
|
||||
if (mode->timing.pixel_clock > maxPixelClock)
|
||||
return false;
|
||||
|
||||
// Is the color space supported?
|
||||
|
||||
bool colorSpaceSupported = false;
|
||||
for (uint32 j = 0; j < si.colorSpaceCount; j++) {
|
||||
if (mode->space == uint32(si.colorSpaces[j])) {
|
||||
colorSpaceSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colorSpaceSupported)
|
||||
return false;
|
||||
|
||||
// Reject modes with a width of 640 and a height < 480 since they do not
|
||||
// work properly with the ATI chipsets.
|
||||
|
||||
if (mode->timing.h_display == 640 && mode->timing.v_display < 480)
|
||||
return false;
|
||||
} else {
|
||||
// Test if mode is usable for a chip that is connected to a laptop LCD
|
||||
// display or a monitor via a DVI interface.
|
||||
|
||||
// If chip is a Mach64 Mobility chip exclude 640x350 resolution since
|
||||
// that resolution can not be set without a failure in the VESA set mode
|
||||
// function.
|
||||
|
||||
if (si.chipType == MACH64_MOBILITY && mode->timing.h_display == 640
|
||||
&& mode->timing.v_display == 350)
|
||||
return false;
|
||||
|
||||
// Search VESA mode table for matching mode.
|
||||
|
||||
if (GetVesaModeNumber(*mode, bitsPerPixel) == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CreateModeList(bool (*checkMode)(const display_mode* mode))
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
// Obtain EDID info which is needed for for building the mode list.
|
||||
// However, if a laptop's LCD display is active, bypass getting the EDID
|
||||
// info since it is not needed, and if the external display supports only
|
||||
// resolutions smaller than the size of the laptop LCD display, it would
|
||||
// unnecessarily restrict size of the resolutions that could be set for
|
||||
// laptop LCD display.
|
||||
|
||||
si.bHaveEDID = false;
|
||||
|
||||
if (si.displayType == MT_VGA && !si.bHaveEDID) {
|
||||
edid1_raw rawEdid; // raw EDID info to obtain
|
||||
|
||||
if (ioctl(gInfo.deviceFileDesc, ATI_GET_EDID, &rawEdid,
|
||||
sizeof(rawEdid)) == B_OK) {
|
||||
if (rawEdid.version.version != 1 || rawEdid.version.revision > 4) {
|
||||
TRACE("CreateModeList(); EDID version %d.%d out of range\n",
|
||||
rawEdid.version.version, rawEdid.version.revision);
|
||||
} else {
|
||||
edid_decode(&si.edidInfo, &rawEdid); // decode & save EDID info
|
||||
si.bHaveEDID = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (si.bHaveEDID) {
|
||||
#ifdef ENABLE_DEBUG_TRACE
|
||||
edid_dump(&(si.edidInfo));
|
||||
#endif
|
||||
} else {
|
||||
TRACE("CreateModeList(); Unable to get EDID info\n");
|
||||
}
|
||||
}
|
||||
|
||||
display_mode* list;
|
||||
uint32 count = 0;
|
||||
area_id listArea;
|
||||
|
||||
listArea = create_display_modes("ATI modes",
|
||||
si.bHaveEDID ? &si.edidInfo : NULL,
|
||||
NULL, 0, si.colorSpaces, si.colorSpaceCount,
|
||||
(check_display_mode_hook)checkMode, &list, &count);
|
||||
|
||||
if (listArea < 0)
|
||||
return listArea; // listArea has error code
|
||||
|
||||
si.modeArea = gInfo.modeListArea = listArea;
|
||||
si.modeCount = count;
|
||||
gInfo.modeList = list;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
ProposeDisplayMode(display_mode *target, const display_mode *low,
|
||||
const display_mode *high)
|
||||
{
|
||||
(void)low; // avoid compiler warning for unused arg
|
||||
(void)high; // avoid compiler warning for unused arg
|
||||
|
||||
TRACE("ProposeDisplayMode() %dx%d, pixel clock: %d kHz, space: 0x%X\n",
|
||||
target->timing.h_display, target->timing.v_display,
|
||||
target->timing.pixel_clock, target->space);
|
||||
|
||||
// Search the mode list for the specified mode.
|
||||
|
||||
uint32 modeCount = gInfo.sharedInfo->modeCount;
|
||||
|
||||
for (uint32 j = 0; j < modeCount; j++) {
|
||||
display_mode& mode = gInfo.modeList[j];
|
||||
|
||||
if (target->timing.h_display == mode.timing.h_display
|
||||
&& target->timing.v_display == mode.timing.v_display
|
||||
&& target->space == mode.space)
|
||||
return B_OK; // mode found in list
|
||||
}
|
||||
|
||||
return B_BAD_VALUE; // mode not found in list
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SetDisplayMode(display_mode* pMode)
|
||||
{
|
||||
// First validate the mode, then call a function to set the registers.
|
||||
|
||||
TRACE("SetDisplayMode() begin\n");
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
DisplayModeEx mode;
|
||||
(display_mode&)mode = *pMode;
|
||||
|
||||
uint32 maxPixelClock;
|
||||
if ( ! gInfo.GetColorSpaceParams(mode.space, mode.bitsPerPixel, maxPixelClock))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (ProposeDisplayMode(&mode, pMode, pMode) != B_OK)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
int bytesPerPixel = (mode.bitsPerPixel + 7) / 8;
|
||||
mode.bytesPerRow = mode.timing.h_display * bytesPerPixel;
|
||||
|
||||
// Is there enough frame buffer memory for this mode?
|
||||
|
||||
if ( ! IsThereEnoughFBMemory(&mode, mode.bitsPerPixel))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
TRACE("Set display mode: %dx%d virtual size: %dx%d color depth: %d bits/pixel\n",
|
||||
mode.timing.h_display, mode.timing.v_display,
|
||||
mode.virtual_width, mode.virtual_height, mode.bitsPerPixel);
|
||||
|
||||
if (si.displayType == MT_VGA) {
|
||||
TRACE(" mode timing: %d %d %d %d %d %d %d %d %d\n",
|
||||
mode.timing.pixel_clock,
|
||||
mode.timing.h_display,
|
||||
mode.timing.h_sync_start, mode.timing.h_sync_end,
|
||||
mode.timing.h_total,
|
||||
mode.timing.v_display,
|
||||
mode.timing.v_sync_start, mode.timing.v_sync_end,
|
||||
mode.timing.v_total);
|
||||
|
||||
TRACE(" mode hFreq: %.1f kHz vFreq: %.1f Hz %chSync %cvSync\n",
|
||||
double(mode.timing.pixel_clock) / mode.timing.h_total,
|
||||
((double(mode.timing.pixel_clock) / mode.timing.h_total) * 1000.0)
|
||||
/ mode.timing.v_total,
|
||||
(mode.timing.flags & B_POSITIVE_HSYNC) ? '+' : '-',
|
||||
(mode.timing.flags & B_POSITIVE_VSYNC) ? '+' : '-');
|
||||
}
|
||||
|
||||
status_t status = gInfo.SetDisplayMode(mode);
|
||||
if (status != B_OK) {
|
||||
TRACE("SetDisplayMode() failed; status 0x%x\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
si.displayMode = mode;
|
||||
|
||||
TRACE("SetDisplayMode() done\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
MoveDisplay(uint16 horizontalStart, uint16 verticalStart)
|
||||
{
|
||||
// Set which pixel of the virtual frame buffer will show up in the
|
||||
// top left corner of the display device. Used for page-flipping
|
||||
// games and virtual desktops.
|
||||
|
||||
DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
|
||||
|
||||
if (mode.timing.h_display + horizontalStart > mode.virtual_width
|
||||
|| mode.timing.v_display + verticalStart > mode.virtual_height)
|
||||
return B_ERROR;
|
||||
|
||||
mode.h_display_start = horizontalStart;
|
||||
mode.v_display_start = verticalStart;
|
||||
|
||||
gInfo.AdjustFrame(mode);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
AccelerantModeCount(void)
|
||||
{
|
||||
// Return the number of display modes in the mode list.
|
||||
|
||||
return gInfo.sharedInfo->modeCount;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetModeList(display_mode* dmList)
|
||||
{
|
||||
// Copy the list of supported video modes to the location pointed at
|
||||
// by dmList.
|
||||
|
||||
memcpy(dmList, gInfo.modeList, gInfo.sharedInfo->modeCount * sizeof(display_mode));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetDisplayMode(display_mode* current_mode)
|
||||
{
|
||||
*current_mode = gInfo.sharedInfo->displayMode; // return current display mode
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetFrameBufferConfig(frame_buffer_config* pFBC)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
pFBC->frame_buffer = (void*)((addr_t)si.videoMemAddr + si.frameBufferOffset);
|
||||
pFBC->frame_buffer_dma = (void*)((addr_t)si.videoMemPCI + si.frameBufferOffset);
|
||||
uint32 bytesPerPixel = (si.displayMode.bitsPerPixel + 7) / 8;
|
||||
pFBC->bytes_per_row = si.displayMode.virtual_width * bytesPerPixel;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetPixelClockLimits(display_mode* mode, uint32* low, uint32* high)
|
||||
{
|
||||
// Return the maximum and minium pixel clock limits for the specified mode.
|
||||
|
||||
uint8 bitsPerPixel;
|
||||
uint32 maxPixelClock;
|
||||
|
||||
if ( ! gInfo.GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock))
|
||||
return B_ERROR;
|
||||
|
||||
if (low != NULL) {
|
||||
// lower limit of about 48Hz vertical refresh
|
||||
uint32 totalClocks = (uint32)mode->timing.h_total * (uint32)mode->timing.v_total;
|
||||
uint32 lowClock = (totalClocks * 48L) / 1000L;
|
||||
if (lowClock > maxPixelClock)
|
||||
return B_ERROR;
|
||||
|
||||
*low = lowClock;
|
||||
}
|
||||
|
||||
if (high != NULL)
|
||||
*high = maxPixelClock;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetTimingConstraints(display_timing_constraints *constraints)
|
||||
{
|
||||
(void)constraints; // avoid compiler warning for unused arg
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetPreferredDisplayMode(display_mode* preferredMode)
|
||||
{
|
||||
// If the chip is connected to a laptop LCD panel, find the mode with
|
||||
// matching width and height, 60 Hz refresh rate, and greatest color depth.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if (si.displayType == MT_LAPTOP) {
|
||||
display_mode* mode = FindDisplayMode(si.panelX, si.panelY, 60, 0);
|
||||
|
||||
if (mode != NULL) {
|
||||
*preferredMode = *mode;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GetEdidInfo(void* info, size_t size, uint32* _version)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if ( ! si.bHaveEDID)
|
||||
return B_ERROR;
|
||||
|
||||
if (size < sizeof(struct edid1_info))
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
memcpy(info, &si.edidInfo, sizeof(struct edid1_info));
|
||||
*_version = EDID_VERSION_1;
|
||||
return B_OK;
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
|
||||
Precision Insight, Inc., Cedar Park, Texas, and
|
||||
VA Linux Systems Inc., Fremont, California.
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __RAGE128_H__
|
||||
#define __RAGE128_H__
|
||||
|
||||
|
||||
#define CURSOR_BYTES 1024 // bytes used for cursor image in video memory
|
||||
|
||||
#define R128_TIMEOUT 2000000 // Fall out of wait loops after this count
|
||||
|
||||
|
||||
// Register MMIO addresses.
|
||||
//-------------------------
|
||||
|
||||
#define R128_AUX_SC_CNTL 0x1660
|
||||
|
||||
#define R128_BUS_CNTL 0x0030
|
||||
# define R128_BUS_MASTER_DIS (1 << 6)
|
||||
# define R128_BUS_RD_DISCARD_EN (1 << 24)
|
||||
# define R128_BUS_RD_ABORT_EN (1 << 25)
|
||||
# define R128_BUS_MSTR_DISCONNECT_EN (1 << 28)
|
||||
# define R128_BUS_WRT_BURST (1 << 29)
|
||||
# define R128_BUS_READ_BURST (1 << 30)
|
||||
|
||||
#define R128_CAP0_TRIG_CNTL 0x0950 // ?
|
||||
#define R128_CAP1_TRIG_CNTL 0x09c0 // ?
|
||||
#define R128_CLOCK_CNTL_DATA 0x000c
|
||||
#define R128_CLOCK_CNTL_INDEX 0x0008
|
||||
# define R128_PLL_WR_EN (1 << 7)
|
||||
# define R128_PLL_DIV_SEL (3 << 8)
|
||||
#define R128_CONFIG_MEMSIZE 0x00f8
|
||||
#define R128_CRTC_EXT_CNTL 0x0054
|
||||
# define R128_CRTC_VGA_XOVERSCAN (1 << 0)
|
||||
# define R128_VGA_ATI_LINEAR (1 << 3)
|
||||
# define R128_XCRT_CNT_EN (1 << 6)
|
||||
# define R128_CRTC_HSYNC_DIS (1 << 8)
|
||||
# define R128_CRTC_VSYNC_DIS (1 << 9)
|
||||
# define R128_CRTC_DISPLAY_DIS (1 << 10)
|
||||
# define R128_CRTC_CRT_ON (1 << 15)
|
||||
# define R128_FP_OUT_EN (1 << 22)
|
||||
# define R128_FP_ACTIVE (1 << 23)
|
||||
#define R128_CRTC_GEN_CNTL 0x0050
|
||||
# define R128_CRTC_CUR_EN (1 << 16)
|
||||
# define R128_CRTC_EXT_DISP_EN (1 << 24)
|
||||
# define R128_CRTC_EN (1 << 25)
|
||||
#define R128_CRTC_H_SYNC_STRT_WID 0x0204
|
||||
# define R128_CRTC_H_SYNC_POL (1 << 23)
|
||||
#define R128_CRTC_H_TOTAL_DISP 0x0200
|
||||
#define R128_CRTC_OFFSET 0x0224
|
||||
#define R128_CRTC_OFFSET_CNTL 0x0228
|
||||
#define R128_CRTC_PITCH 0x022c
|
||||
#define R128_CRTC_V_SYNC_STRT_WID 0x020c
|
||||
# define R128_CRTC_V_SYNC_POL (1 << 23)
|
||||
#define R128_CRTC_V_TOTAL_DISP 0x0208
|
||||
#define R128_CUR_CLR0 0x026c
|
||||
#define R128_CUR_CLR1 0x0270
|
||||
#define R128_CUR_HORZ_VERT_OFF 0x0268
|
||||
#define R128_CUR_HORZ_VERT_POSN 0x0264
|
||||
#define R128_CUR_OFFSET 0x0260
|
||||
# define R128_CUR_LOCK (1 << 31)
|
||||
|
||||
#define R128_DAC_CNTL 0x0058
|
||||
# define R128_DAC_RANGE_CNTL (3 << 0)
|
||||
# define R128_DAC_BLANKING (1 << 2)
|
||||
# define R128_DAC_CRT_SEL_CRTC2 (1 << 4)
|
||||
# define R128_DAC_PALETTE_ACC_CTL (1 << 5)
|
||||
# define R128_DAC_8BIT_EN (1 << 8)
|
||||
# define R128_DAC_VGA_ADR_EN (1 << 13)
|
||||
# define R128_DAC_MASK_ALL (0xff << 24)
|
||||
#define R128_DDA_CONFIG 0x02e0
|
||||
#define R128_DDA_ON_OFF 0x02e4
|
||||
#define R128_DEFAULT_OFFSET 0x16e0
|
||||
#define R128_DEFAULT_PITCH 0x16e4
|
||||
#define R128_DEFAULT_SC_BOTTOM_RIGHT 0x16e8
|
||||
# define R128_DEFAULT_SC_RIGHT_MAX (0x1fff << 0)
|
||||
# define R128_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16)
|
||||
#define R128_DP_BRUSH_BKGD_CLR 0x1478
|
||||
#define R128_DP_BRUSH_FRGD_CLR 0x147c
|
||||
#define R128_DP_CNTL 0x16c0
|
||||
# define R128_DST_X_LEFT_TO_RIGHT (1 << 0)
|
||||
# define R128_DST_Y_TOP_TO_BOTTOM (1 << 1)
|
||||
#define R128_DP_DATATYPE 0x16c4
|
||||
# define R128_HOST_BIG_ENDIAN_EN (1 << 29)
|
||||
#define R128_DP_GUI_MASTER_CNTL 0x146c
|
||||
# define R128_DP_SRC_SOURCE_MEMORY (2 << 24)
|
||||
# define R128_GMC_AUX_CLIP_DIS (1 << 29)
|
||||
# define R128_GMC_BRUSH_NONE (15 << 4)
|
||||
# define R128_GMC_BRUSH_SOLID_COLOR (13 << 4)
|
||||
# define R128_GMC_CLR_CMP_CNTL_DIS (1 << 28)
|
||||
# define R128_GMC_DST_DATATYPE_SHIFT 8
|
||||
# define R128_GMC_SRC_DATATYPE_COLOR (3 << 12)
|
||||
# define R128_ROP3_Dn 0x00550000
|
||||
# define R128_ROP3_P 0x00f00000
|
||||
# define R128_ROP3_S 0x00cc0000
|
||||
#define R128_DP_SRC_BKGD_CLR 0x15dc
|
||||
#define R128_DP_SRC_FRGD_CLR 0x15d8
|
||||
#define R128_DP_WRITE_MASK 0x16cc
|
||||
#define R128_DST_BRES_DEC 0x1630
|
||||
#define R128_DST_BRES_ERR 0x1628
|
||||
#define R128_DST_BRES_INC 0x162c
|
||||
#define R128_DST_HEIGHT_WIDTH 0x143c
|
||||
#define R128_DST_WIDTH_HEIGHT 0x1598
|
||||
#define R128_DST_Y_X 0x1438
|
||||
|
||||
#define R128_FP_CRTC_H_TOTAL_DISP 0x0250
|
||||
#define R128_FP_CRTC_V_TOTAL_DISP 0x0254
|
||||
#define R128_FP_GEN_CNTL 0x0284
|
||||
# define R128_FP_FPON (1 << 0)
|
||||
# define R128_FP_BLANK_DIS (1 << 1)
|
||||
# define R128_FP_TDMS_EN (1 << 2)
|
||||
# define R128_FP_DETECT_SENSE (1 << 8)
|
||||
# define R128_FP_SEL_CRTC2 (1 << 13)
|
||||
# define R128_FP_CRTC_DONT_SHADOW_VPAR (1 << 16)
|
||||
# define R128_FP_CRTC_DONT_SHADOW_HEND (1 << 17)
|
||||
# define R128_FP_CRTC_USE_SHADOW_VEND (1 << 18)
|
||||
# define R128_FP_CRTC_USE_SHADOW_ROWCUR (1 << 19)
|
||||
# define R128_FP_CRTC_HORZ_DIV2_EN (1 << 20)
|
||||
# define R128_FP_CRTC_HOR_CRT_DIV2_DIS (1 << 21)
|
||||
# define R128_FP_CRT_SYNC_SEL (1 << 23)
|
||||
# define R128_FP_USE_SHADOW_EN (1 << 24)
|
||||
#define R128_FP_H_SYNC_STRT_WID 0x02c4
|
||||
#define R128_FP_HORZ_STRETCH 0x028c
|
||||
# define R128_HORZ_STRETCH_RATIO_MASK 0xfff
|
||||
# define R128_HORZ_STRETCH_RATIO_SHIFT 0
|
||||
# define R128_HORZ_STRETCH_RATIO_MAX 4096
|
||||
# define R128_HORZ_PANEL_SIZE (0xff << 16)
|
||||
# define R128_HORZ_PANEL_SHIFT 16
|
||||
# define R128_AUTO_HORZ_RATIO (0 << 24)
|
||||
# define R128_HORZ_STRETCH_PIXREP (0 << 25)
|
||||
# define R128_HORZ_STRETCH_BLEND (1 << 25)
|
||||
# define R128_HORZ_STRETCH_ENABLE (1 << 26)
|
||||
# define R128_HORZ_FP_LOOP_STRETCH (0x7 << 27)
|
||||
# define R128_HORZ_STRETCH_RESERVED (1 << 30)
|
||||
# define R128_HORZ_AUTO_RATIO_FIX_EN (1 << 31)
|
||||
|
||||
#define R128_FP_PANEL_CNTL 0x0288
|
||||
# define R128_FP_DIGON (1 << 0)
|
||||
# define R128_FP_BLON (1 << 1)
|
||||
#define R128_FP_V_SYNC_STRT_WID 0x02c8
|
||||
#define R128_FP_VERT_STRETCH 0x0290
|
||||
# define R128_VERT_PANEL_SIZE (0x7ff << 0)
|
||||
# define R128_VERT_PANEL_SHIFT 0
|
||||
# define R128_VERT_STRETCH_RATIO_MASK 0x3ff
|
||||
# define R128_VERT_STRETCH_RATIO_SHIFT 11
|
||||
# define R128_VERT_STRETCH_RATIO_MAX 1024
|
||||
# define R128_VERT_STRETCH_ENABLE (1 << 24)
|
||||
# define R128_VERT_STRETCH_LINEREP (0 << 25)
|
||||
# define R128_VERT_STRETCH_BLEND (1 << 25)
|
||||
# define R128_VERT_AUTO_RATIO_EN (1 << 26)
|
||||
# define R128_VERT_STRETCH_RESERVED 0xf8e00000
|
||||
|
||||
#define R128_GEN_INT_CNTL 0x0040
|
||||
#define R128_GEN_RESET_CNTL 0x00f0
|
||||
# define R128_SOFT_RESET_GUI (1 << 0)
|
||||
#define R128_GPIO_MONID 0x0068
|
||||
# define R128_GPIO_MONID_A_0 (1 << 0)
|
||||
# define R128_GPIO_MONID_A_3 (1 << 3)
|
||||
# define R128_GPIO_MONID_Y_0 (1 << 8)
|
||||
# define R128_GPIO_MONID_Y_3 (1 << 11)
|
||||
# define R128_GPIO_MONID_EN_0 (1 << 16)
|
||||
# define R128_GPIO_MONID_EN_3 (1 << 19)
|
||||
# define R128_GPIO_MONID_MASK_0 (1 << 24)
|
||||
# define R128_GPIO_MONID_MASK_3 (1 << 27)
|
||||
#define R128_GUI_PROBE 0x16bc
|
||||
#define R128_GUI_STAT 0x1740
|
||||
# define R128_GUI_FIFOCNT_MASK 0x0fff
|
||||
# define R128_GUI_ACTIVE (1 << 31)
|
||||
|
||||
#define R128_HTOTAL_CNTL 0x0009 // PLL
|
||||
|
||||
#define R128_I2C_CNTL_1 0x0094 // ?
|
||||
|
||||
#define R128_LVDS_GEN_CNTL 0x02d0
|
||||
# define R128_LVDS_ON (1 << 0)
|
||||
# define R128_LVDS_DISPLAY_DIS (1 << 1)
|
||||
# define R128_LVDS_EN (1 << 7)
|
||||
# define R128_LVDS_DIGON (1 << 18)
|
||||
# define R128_LVDS_BLON (1 << 19)
|
||||
# define R128_LVDS_SEL_CRTC2 (1 << 23)
|
||||
# define R128_HSYNC_DELAY_SHIFT 28
|
||||
# define R128_HSYNC_DELAY_MASK (0xf << 28)
|
||||
|
||||
#define R128_MCLK_CNTL 0x000f /* PLL */
|
||||
# define R128_FORCE_GCP (1 << 16)
|
||||
# define R128_FORCE_PIPE3D_CP (1 << 17)
|
||||
#define R128_MEM_CNTL 0x0140
|
||||
#define R128_MPP_TB_CONFIG 0x01c0 // ?
|
||||
#define R128_MPP_GP_CONFIG 0x01c8 // ?
|
||||
|
||||
#define R128_OVR_CLR 0x0230
|
||||
#define R128_OVR_WID_LEFT_RIGHT 0x0234
|
||||
#define R128_OVR_WID_TOP_BOTTOM 0x0238
|
||||
#define R128_OV0_SCALE_CNTL 0x0420
|
||||
|
||||
#define R128_PALETTE_DATA 0x00b4
|
||||
#define R128_PALETTE_INDEX 0x00b0
|
||||
#define R128_PC_NGUI_CTLSTAT 0x0184
|
||||
# define R128_PC_FLUSH_ALL 0x00ff
|
||||
# define R128_PC_BUSY (1 << 31)
|
||||
#define R128_PPLL_CNTL 0x0002 // PLL
|
||||
# define R128_PPLL_RESET (1 << 0)
|
||||
# define R128_PPLL_SLEEP (1 << 1)
|
||||
# define R128_PPLL_ATOMIC_UPDATE_EN (1 << 16)
|
||||
# define R128_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17)
|
||||
#define R128_PPLL_DIV_3 0x0007 // PLL
|
||||
# define R128_PPLL_FB3_DIV_MASK 0x07ff
|
||||
# define R128_PPLL_POST3_DIV_MASK 0x00070000
|
||||
#define R128_PPLL_REF_DIV 0x0003 // PLL
|
||||
# define R128_PPLL_REF_DIV_MASK 0x03ff
|
||||
# define R128_PPLL_ATOMIC_UPDATE_R (1 << 15) // same as _W
|
||||
# define R128_PPLL_ATOMIC_UPDATE_W (1 << 15) // same as _R
|
||||
|
||||
#define R128_SC_BOTTOM_RIGHT 0x16f0
|
||||
#define R128_SC_TOP_LEFT 0x16ec
|
||||
#define R128_SCALE_3D_CNTL 0x1a00
|
||||
#define R128_SRC_Y_X 0x1434
|
||||
#define R128_SUBPIC_CNTL 0x0540 // ?
|
||||
|
||||
#define R128_TMDS_CRC 0x02a0
|
||||
|
||||
#define R128_VCLK_ECP_CNTL 0x0008 // PLL
|
||||
# define R128_VCLK_SRC_SEL_MASK 0x03
|
||||
# define R128_VCLK_SRC_SEL_CPUCLK 0x00
|
||||
# define R128_VCLK_SRC_SEL_PPLLCLK 0x03
|
||||
#define R128_VIPH_CONTROL 0x01D0 // ?
|
||||
|
||||
|
||||
|
||||
// Functions to get/set PLL registers.
|
||||
//=======================================
|
||||
|
||||
static inline uint32
|
||||
GetPLLReg(uint8 index)
|
||||
{
|
||||
OUTREG8(R128_CLOCK_CNTL_INDEX, index & 0x3f);
|
||||
return INREG(R128_CLOCK_CNTL_DATA);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
SetPLLReg(uint8 index, uint32 value)
|
||||
{
|
||||
OUTREG8(R128_CLOCK_CNTL_INDEX, ((index) & 0x3f) | R128_PLL_WR_EN);
|
||||
OUTREG(R128_CLOCK_CNTL_DATA, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
SetPLLReg(uint8 index, uint32 value, uint32 mask)
|
||||
{
|
||||
// Write a value to a PLL reg using a mask. The mask selects the
|
||||
// bits to be modified.
|
||||
|
||||
SetPLLReg(index, (GetPLLReg(index) & ~mask) | (value & mask));
|
||||
}
|
||||
|
||||
|
||||
#endif // __RAGE128_H__
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
|
||||
Precision Insight, Inc., Cedar Park, Texas, and
|
||||
VA Linux Systems Inc., Fremont, California.
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "rage128.h"
|
||||
|
||||
|
||||
|
||||
void
|
||||
Rage128_ShowCursor(bool bShow)
|
||||
{
|
||||
// Turn cursor on/off.
|
||||
|
||||
OUTREGM(R128_CRTC_GEN_CNTL, bShow ? R128_CRTC_CUR_EN : 0, R128_CRTC_CUR_EN);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rage128_SetCursorPosition(int x, int y)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
// xOffset & yOffset are used for displaying partial cursors on screen edges.
|
||||
|
||||
uint8 xOffset = 0;
|
||||
uint8 yOffset = 0;
|
||||
|
||||
if (x < 0) {
|
||||
xOffset = (( -x) & 0xFE);
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
yOffset = (( -y) & 0xFE);
|
||||
y = 0;
|
||||
}
|
||||
|
||||
OUTREG(R128_CUR_HORZ_VERT_OFF, R128_CUR_LOCK | (xOffset << 16) | yOffset);
|
||||
OUTREG(R128_CUR_HORZ_VERT_POSN, R128_CUR_LOCK | (x << 16) | y);
|
||||
OUTREG(R128_CUR_OFFSET, si.cursorOffset + yOffset * 16);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Rage128_LoadCursorImage(int width, int height, uint8* andMask, uint8* xorMask)
|
||||
{
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
if (andMask == NULL || xorMask == NULL)
|
||||
return false;
|
||||
|
||||
// Initialize the hardware cursor as completely transparent.
|
||||
|
||||
uint32* fbCursor32 = (uint32*)((addr_t)si.videoMemAddr + si.cursorOffset);
|
||||
|
||||
for (int i = 0; i < CURSOR_BYTES; i += 16) {
|
||||
*fbCursor32++ = ~0; // and bits
|
||||
*fbCursor32++ = ~0;
|
||||
*fbCursor32++ = 0; // xor bits
|
||||
*fbCursor32++ = 0;
|
||||
}
|
||||
|
||||
// Now load the AND & XOR masks for the cursor image into the cursor
|
||||
// buffer. Note that a particular bit in these masks will have the
|
||||
// following effect upon the corresponding cursor pixel:
|
||||
// AND XOR Result
|
||||
// 0 0 White pixel
|
||||
// 0 1 Black pixel
|
||||
// 1 0 Screen color (for transparency)
|
||||
// 1 1 Reverse screen color to black or white
|
||||
|
||||
uint8* fbCursor = (uint8*)((addr_t)si.videoMemAddr + si.cursorOffset);
|
||||
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int colByte = 0; colByte < width / 8; colByte++) {
|
||||
fbCursor[row * 16 + colByte] = *andMask++;
|
||||
fbCursor[row * 16 + colByte + 8] = *xorMask++;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the cursor colors which are white background and black foreground.
|
||||
|
||||
OUTREG(R128_CUR_CLR0, ~0);
|
||||
OUTREG(R128_CUR_CLR1, 0);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
|
||||
Precision Insight, Inc., Cedar Park, Texas, and
|
||||
VA Linux Systems Inc., Fremont, California.
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "rage128.h"
|
||||
|
||||
|
||||
|
||||
uint32
|
||||
Rage128_DPMSCapabilities(void)
|
||||
{
|
||||
// Return DPMS modes supported by this device.
|
||||
|
||||
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
Rage128_GetDPMSMode(void)
|
||||
{
|
||||
// Return the current DPMS mode.
|
||||
|
||||
uint32 tmp = INREG(R128_CRTC_EXT_CNTL);
|
||||
uint32 mode;
|
||||
|
||||
if( (tmp & R128_CRTC_DISPLAY_DIS) == 0 )
|
||||
mode = B_DPMS_ON;
|
||||
else if( (tmp & R128_CRTC_VSYNC_DIS) == 0 )
|
||||
mode = B_DPMS_STAND_BY;
|
||||
else if( (tmp & R128_CRTC_HSYNC_DIS) == 0 )
|
||||
mode = B_DPMS_SUSPEND;
|
||||
else
|
||||
mode = B_DPMS_OFF;
|
||||
|
||||
TRACE("Rage128_DPMSMode() mode: %d\n", mode);
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Rage128_SetDPMSMode(uint32 dpmsMode)
|
||||
{
|
||||
// Set the display into one of the Display Power Management modes,
|
||||
// and return B_OK if successful, else return B_ERROR.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("Rage128_SetDPMSMode() mode: %d, display type: %d\n", dpmsMode, si.displayType);
|
||||
|
||||
int mask = (R128_CRTC_DISPLAY_DIS
|
||||
| R128_CRTC_HSYNC_DIS
|
||||
| R128_CRTC_VSYNC_DIS);
|
||||
|
||||
switch (dpmsMode) {
|
||||
case B_DPMS_ON:
|
||||
// Screen: On; HSync: On, VSync: On.
|
||||
OUTREGM(R128_CRTC_EXT_CNTL, 0, mask);
|
||||
break;
|
||||
|
||||
case B_DPMS_STAND_BY:
|
||||
// Screen: Off; HSync: Off, VSync: On.
|
||||
OUTREGM(R128_CRTC_EXT_CNTL,
|
||||
R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS, mask);
|
||||
break;
|
||||
|
||||
case B_DPMS_SUSPEND:
|
||||
// Screen: Off; HSync: On, VSync: Off.
|
||||
OUTREGM(R128_CRTC_EXT_CNTL,
|
||||
R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS, mask);
|
||||
break;
|
||||
|
||||
case B_DPMS_OFF:
|
||||
// Screen: Off; HSync: Off, VSync: Off.
|
||||
OUTREGM(R128_CRTC_EXT_CNTL, mask, mask);
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("Invalid DPMS mode %d\n", dpmsMode);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (si.displayType == MT_LAPTOP) {
|
||||
uint32 genCtrl;
|
||||
|
||||
switch (dpmsMode) {
|
||||
case B_DPMS_ON:
|
||||
genCtrl = INREG(R128_LVDS_GEN_CNTL);
|
||||
genCtrl |= R128_LVDS_ON | R128_LVDS_EN | R128_LVDS_BLON | R128_LVDS_DIGON;
|
||||
genCtrl &= ~R128_LVDS_DISPLAY_DIS;
|
||||
OUTREG(R128_LVDS_GEN_CNTL, genCtrl);
|
||||
break;
|
||||
|
||||
case B_DPMS_STAND_BY:
|
||||
case B_DPMS_SUSPEND:
|
||||
case B_DPMS_OFF:
|
||||
genCtrl = INREG(R128_LVDS_GEN_CNTL);
|
||||
genCtrl |= R128_LVDS_DISPLAY_DIS;
|
||||
OUTREG(R128_LVDS_GEN_CNTL, genCtrl);
|
||||
snooze(10);
|
||||
genCtrl &= ~(R128_LVDS_ON | R128_LVDS_EN | R128_LVDS_BLON | R128_LVDS_DIGON);
|
||||
OUTREG(R128_LVDS_GEN_CNTL, genCtrl);
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("Invalid DPMS mode %d\n", dpmsMode);
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (gInfo.sharedInfo->displayType == MT_DVI) {
|
||||
switch (dpmsMode) {
|
||||
case B_DPMS_ON:
|
||||
OUTREG(R128_FP_GEN_CNTL, INREG(R128_FP_GEN_CNTL)
|
||||
| (R128_FP_FPON | R128_FP_TDMS_EN));
|
||||
break;
|
||||
|
||||
case B_DPMS_STAND_BY:
|
||||
case B_DPMS_SUSPEND:
|
||||
case B_DPMS_OFF:
|
||||
OUTREG(R128_FP_GEN_CNTL, INREG(R128_FP_GEN_CNTL)
|
||||
& ~(R128_FP_FPON | R128_FP_TDMS_EN));
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("Invalid DPMS mode %d\n", dpmsMode);
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
|
||||
Precision Insight, Inc., Cedar Park, Texas, and
|
||||
VA Linux Systems Inc., Fremont, California.
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "rage128.h"
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
Rage128_EngineFlush()
|
||||
{
|
||||
// Flush all dirty data in the Pixel Cache to memory.
|
||||
|
||||
OUTREGM(R128_PC_NGUI_CTLSTAT, R128_PC_FLUSH_ALL, R128_PC_FLUSH_ALL);
|
||||
|
||||
for (int i = 0; i < R128_TIMEOUT; i++) {
|
||||
if ( ! (INREG(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rage128_EngineReset()
|
||||
{
|
||||
// Reset graphics card to known state.
|
||||
|
||||
Rage128_EngineFlush();
|
||||
|
||||
uint32 clockCntlIndex = INREG(R128_CLOCK_CNTL_INDEX);
|
||||
uint32 mclkCntl = GetPLLReg(R128_MCLK_CNTL);
|
||||
|
||||
SetPLLReg(R128_MCLK_CNTL, mclkCntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
|
||||
|
||||
uint32 genResetCntl = INREG(R128_GEN_RESET_CNTL);
|
||||
|
||||
OUTREG(R128_GEN_RESET_CNTL, genResetCntl | R128_SOFT_RESET_GUI);
|
||||
INREG(R128_GEN_RESET_CNTL);
|
||||
OUTREG(R128_GEN_RESET_CNTL, genResetCntl & ~R128_SOFT_RESET_GUI);
|
||||
INREG(R128_GEN_RESET_CNTL);
|
||||
|
||||
SetPLLReg(R128_MCLK_CNTL, mclkCntl);
|
||||
OUTREG(R128_CLOCK_CNTL_INDEX, clockCntlIndex);
|
||||
OUTREG(R128_GEN_RESET_CNTL, genResetCntl);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rage128_EngineInit(const DisplayModeEx& mode)
|
||||
{
|
||||
// Initialize the acceleration hardware.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
TRACE("Rage128_EngineInit() bits/pixel: %d\n", mode.bitsPerPixel);
|
||||
|
||||
OUTREG(R128_SCALE_3D_CNTL, 0);
|
||||
Rage128_EngineReset();
|
||||
|
||||
uint32 dataType = 0;
|
||||
|
||||
switch (mode.bitsPerPixel) {
|
||||
case 8:
|
||||
dataType = 2;
|
||||
break;
|
||||
case 15:
|
||||
dataType = 3;
|
||||
break;
|
||||
case 16:
|
||||
dataType = 4;
|
||||
break;
|
||||
case 32:
|
||||
dataType = 6;
|
||||
break;
|
||||
default:
|
||||
TRACE("Unsupported color depth: %d bits/pixel\n", mode.bitsPerPixel);
|
||||
}
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(R128_DEFAULT_OFFSET, gInfo.sharedInfo->frameBufferOffset);
|
||||
OUTREG(R128_DEFAULT_PITCH, mode.timing.h_display / 8);
|
||||
|
||||
gInfo.WaitForFifo(4);
|
||||
OUTREG(R128_AUX_SC_CNTL, 0);
|
||||
OUTREG(R128_DEFAULT_SC_BOTTOM_RIGHT, (R128_DEFAULT_SC_RIGHT_MAX
|
||||
| R128_DEFAULT_SC_BOTTOM_MAX));
|
||||
OUTREG(R128_SC_TOP_LEFT, 0);
|
||||
OUTREG(R128_SC_BOTTOM_RIGHT, (R128_DEFAULT_SC_RIGHT_MAX
|
||||
| R128_DEFAULT_SC_BOTTOM_MAX));
|
||||
|
||||
si.r128_dpGuiMasterCntl = ((dataType << R128_GMC_DST_DATATYPE_SHIFT)
|
||||
| R128_GMC_CLR_CMP_CNTL_DIS
|
||||
| R128_GMC_AUX_CLIP_DIS);
|
||||
gInfo.WaitForFifo(1);
|
||||
OUTREG(R128_DP_GUI_MASTER_CNTL, (si.r128_dpGuiMasterCntl
|
||||
| R128_GMC_BRUSH_SOLID_COLOR
|
||||
| R128_GMC_SRC_DATATYPE_COLOR));
|
||||
|
||||
gInfo.WaitForFifo(8);
|
||||
OUTREG(R128_DST_BRES_ERR, 0);
|
||||
OUTREG(R128_DST_BRES_INC, 0);
|
||||
OUTREG(R128_DST_BRES_DEC, 0);
|
||||
OUTREG(R128_DP_BRUSH_FRGD_CLR, 0xffffffff);
|
||||
OUTREG(R128_DP_BRUSH_BKGD_CLR, 0x00000000);
|
||||
OUTREG(R128_DP_SRC_FRGD_CLR, 0xffffffff);
|
||||
OUTREG(R128_DP_SRC_BKGD_CLR, 0x00000000);
|
||||
OUTREG(R128_DP_WRITE_MASK, 0xffffffff);
|
||||
|
||||
gInfo.WaitForFifo(1);
|
||||
OUTREGM(R128_DP_DATATYPE, 0, R128_HOST_BIG_ENDIAN_EN);
|
||||
|
||||
gInfo.WaitForIdle();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rage128_FillRectangle(engine_token *et, uint32 color, fill_rect_params *pList, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
gInfo.WaitForFifo(3);
|
||||
OUTREG(R128_DP_GUI_MASTER_CNTL, (gInfo.sharedInfo->r128_dpGuiMasterCntl
|
||||
| R128_GMC_BRUSH_SOLID_COLOR
|
||||
| R128_GMC_SRC_DATATYPE_COLOR
|
||||
| R128_ROP3_P)); // use GXcopy for rop
|
||||
|
||||
OUTREG(R128_DP_BRUSH_FRGD_CLR, color);
|
||||
OUTREG(R128_DP_CNTL, R128_DST_X_LEFT_TO_RIGHT | R128_DST_Y_TOP_TO_BOTTOM);
|
||||
|
||||
while (count--) {
|
||||
int x = pList->left;
|
||||
int y = pList->top;
|
||||
int w = pList->right - x + 1;
|
||||
int h = pList->bottom - y + 1;
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(R128_DST_Y_X, (y << 16) | x);
|
||||
OUTREG(R128_DST_WIDTH_HEIGHT, (w << 16) | h);
|
||||
|
||||
pList++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rage128_FillSpan(engine_token *et, uint32 color, uint16 *pList, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(R128_DP_GUI_MASTER_CNTL, (gInfo.sharedInfo->r128_dpGuiMasterCntl
|
||||
| R128_GMC_BRUSH_SOLID_COLOR
|
||||
| R128_GMC_SRC_DATATYPE_COLOR
|
||||
| R128_ROP3_P)); // use GXcopy for rop
|
||||
|
||||
OUTREG(R128_DP_BRUSH_FRGD_CLR, color);
|
||||
|
||||
while (count--) {
|
||||
int y = *pList++;
|
||||
int x = *pList++;
|
||||
int w = *pList++ - x + 1;
|
||||
|
||||
if (w <= 0)
|
||||
continue; // discard span with zero or negative width
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(R128_DST_Y_X, (y << 16) | x);
|
||||
OUTREG(R128_DST_WIDTH_HEIGHT, (w << 16) | 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rage128_InvertRectangle(engine_token *et, fill_rect_params *pList, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(R128_DP_GUI_MASTER_CNTL, (gInfo.sharedInfo->r128_dpGuiMasterCntl
|
||||
| R128_GMC_BRUSH_NONE
|
||||
| R128_GMC_SRC_DATATYPE_COLOR
|
||||
| R128_DP_SRC_SOURCE_MEMORY
|
||||
| R128_ROP3_Dn)); // use GXinvert for rop
|
||||
|
||||
OUTREG(R128_DP_CNTL, R128_DST_X_LEFT_TO_RIGHT | R128_DST_Y_TOP_TO_BOTTOM);
|
||||
|
||||
while (count--) {
|
||||
int x = pList->left;
|
||||
int y = pList->top;
|
||||
int w = pList->right - x + 1;
|
||||
int h = pList->bottom - y + 1;
|
||||
|
||||
gInfo.WaitForFifo(2);
|
||||
OUTREG(R128_DST_Y_X, (y << 16) | x);
|
||||
OUTREG(R128_DST_WIDTH_HEIGHT, (w << 16) | h);
|
||||
|
||||
pList++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rage128_ScreenToScreenBlit(engine_token *et, blit_params *pList, uint32 count)
|
||||
{
|
||||
(void)et; // avoid compiler warning for unused arg
|
||||
|
||||
gInfo.WaitForFifo(1);
|
||||
OUTREG(R128_DP_GUI_MASTER_CNTL, (gInfo.sharedInfo->r128_dpGuiMasterCntl
|
||||
| R128_GMC_BRUSH_NONE
|
||||
| R128_GMC_SRC_DATATYPE_COLOR
|
||||
| R128_DP_SRC_SOURCE_MEMORY
|
||||
| R128_ROP3_S)); // use GXcopy for rop
|
||||
|
||||
while (count--) {
|
||||
int cmd = 0;
|
||||
int src_x = pList->src_left;
|
||||
int src_y = pList->src_top;
|
||||
int dest_x = pList->dest_left;
|
||||
int dest_y = pList->dest_top;
|
||||
int width = pList->width;
|
||||
int height = pList->height;
|
||||
|
||||
if (dest_x <= src_x) {
|
||||
cmd |= R128_DST_X_LEFT_TO_RIGHT;
|
||||
} else {
|
||||
src_x += width;
|
||||
dest_x += width;
|
||||
}
|
||||
|
||||
if (dest_y <= src_y) {
|
||||
cmd |= R128_DST_Y_TOP_TO_BOTTOM;
|
||||
} else {
|
||||
src_y += height;
|
||||
dest_y += height;
|
||||
}
|
||||
|
||||
gInfo.WaitForFifo(4);
|
||||
OUTREG(R128_DP_CNTL, cmd);
|
||||
OUTREG(R128_SRC_Y_X, (src_y << 16) | src_x);
|
||||
OUTREG(R128_DST_Y_X, (dest_y << 16) | dest_x);
|
||||
OUTREG(R128_DST_HEIGHT_WIDTH, ((height + 1) << 16) | (width + 1));
|
||||
|
||||
pList ++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
|
||||
Precision Insight, Inc., Cedar Park, Texas, and
|
||||
VA Linux Systems Inc., Fremont, California.
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "rage128.h"
|
||||
|
||||
|
||||
|
||||
// Memory Specifications from RAGE 128 Software Development Manual
|
||||
// (Technical Reference Manual P/N SDK-G04000 Rev 0.01), page 3-21.
|
||||
static R128_RAMSpec sRAMSpecs[] = {
|
||||
{ 4, 4, 3, 3, 1, 3, 1, 16, 12, "128-bit SDR SGRAM 1:1" },
|
||||
{ 4, 8, 3, 3, 1, 3, 1, 17, 13, "64-bit SDR SGRAM 1:1" },
|
||||
{ 4, 4, 1, 2, 1, 2, 1, 16, 12, "64-bit SDR SGRAM 2:1" },
|
||||
{ 4, 4, 3, 3, 2, 3, 1, 16, 12, "64-bit DDR SGRAM" },
|
||||
};
|
||||
|
||||
|
||||
|
||||
static bool
|
||||
Rage128_GetColorSpaceParams(int colorSpace, uint8& bitsPerPixel, uint32& maxPixelClock)
|
||||
{
|
||||
// Get parameters for a color space which is supported by the Rage128 chips.
|
||||
// Argument maxPixelClock is in KHz.
|
||||
// Return true if the color space is supported; else return false.
|
||||
|
||||
switch (colorSpace) {
|
||||
case B_RGB32:
|
||||
bitsPerPixel = 32;
|
||||
break;
|
||||
case B_RGB16:
|
||||
bitsPerPixel = 16;
|
||||
break;
|
||||
case B_RGB15:
|
||||
bitsPerPixel = 15;
|
||||
break;
|
||||
case B_CMAP8:
|
||||
bitsPerPixel = 8;
|
||||
break;
|
||||
default:
|
||||
TRACE("Unsupported color space: 0x%X\n", colorSpace);
|
||||
return false;
|
||||
}
|
||||
|
||||
maxPixelClock = gInfo.sharedInfo->r128PLLParams.max_pll_freq * 10;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
WaitForFifo(uint32 entries)
|
||||
{
|
||||
// The FIFO has 64 slots. This routines waits until at least `entries'
|
||||
// of these slots are empty.
|
||||
|
||||
while (true) {
|
||||
for (int i = 0; i < R128_TIMEOUT; i++) {
|
||||
uint32 slots = INREG(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK;
|
||||
if (slots >= entries)
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE("FIFO timed out: %d entries, stat=0x%08x, probe=0x%08x\n",
|
||||
INREG(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK,
|
||||
INREG(R128_GUI_STAT),
|
||||
INREG(R128_GUI_PROBE));
|
||||
TRACE("FIFO timed out, resetting engine...\n");
|
||||
|
||||
Rage128_EngineReset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
WaitForIdle()
|
||||
{
|
||||
// Wait for the graphics engine to be completely idle. That is, the FIFO
|
||||
// has drained, the Pixel Cache is flushed, and the engine is idle. This
|
||||
// is a standard "sync" function that will make the hardware "quiescent".
|
||||
|
||||
WaitForFifo(64);
|
||||
|
||||
while (true) {
|
||||
for (uint32 i = 0; i < R128_TIMEOUT; i++) {
|
||||
if ( ! (INREG(R128_GUI_STAT) & R128_GUI_ACTIVE)) {
|
||||
Rage128_EngineFlush();
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("Idle timed out: %d entries, stat=0x%08x, probe=0x%08x\n",
|
||||
INREG(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK,
|
||||
INREG(R128_GUI_STAT),
|
||||
INREG(R128_GUI_PROBE));
|
||||
TRACE("Idle timed out, resetting engine...\n");
|
||||
|
||||
Rage128_EngineReset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Rage128_Init(void)
|
||||
{
|
||||
TRACE("Rage128_Init()\n");
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
si.videoMemSize = INREG(R128_CONFIG_MEMSIZE);
|
||||
|
||||
si.cursorOffset = (si.videoMemSize - CURSOR_BYTES) & ~0xfff; // align to 4k boundary
|
||||
si.frameBufferOffset = 0;
|
||||
si.maxFrameBufferSize = si.cursorOffset - si.frameBufferOffset;
|
||||
|
||||
TRACE("Video Memory size: %d MB frameBufferOffset: 0x%x cursorOffset: 0x%x\n",
|
||||
si.videoMemSize / 1024 / 1024, si.frameBufferOffset, si.cursorOffset);
|
||||
|
||||
// Get the specifications of the memory used by the chip.
|
||||
|
||||
uint32 offset;
|
||||
|
||||
switch (INREG(R128_MEM_CNTL) & 0x3) {
|
||||
case 0: // SDR SGRAM 1:1
|
||||
switch (si.deviceID) {
|
||||
case 0x4C45: // RAGE128 LE:
|
||||
case 0x4C46: // RAGE128 LF:
|
||||
case 0x4D46: // RAGE128 MF:
|
||||
case 0x4D4C: // RAGE128 ML:
|
||||
case 0x5245: // RAGE128 RE:
|
||||
case 0x5246: // RAGE128 RF:
|
||||
case 0x5247: // RAGE128 RG:
|
||||
case 0x5446: // RAGE128 TF:
|
||||
case 0x544C: // RAGE128 TL:
|
||||
case 0x5452: // RAGE128 TR:
|
||||
offset = 0; // 128-bit SDR SGRAM 1:1
|
||||
break;
|
||||
default:
|
||||
offset = 1; // 64-bit SDR SGRAM 1:1
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
offset = 2; // 64-bit SDR SGRAM 2:1
|
||||
break;
|
||||
case 2:
|
||||
offset = 3; // 64-bit DDR SGRAM
|
||||
break;
|
||||
default:
|
||||
offset = 1; // 64-bit SDR SGRAM 1:1
|
||||
break;
|
||||
}
|
||||
si.r128MemSpec = sRAMSpecs[offset];
|
||||
TRACE("RAM type: %s\n", si.r128MemSpec.name);
|
||||
|
||||
// Determine the type of display.
|
||||
|
||||
si.displayType = MT_VGA;
|
||||
|
||||
if (INREG(R128_FP_PANEL_CNTL) & R128_FP_DIGON) // don't know if this is correct
|
||||
si.displayType = MT_DVI;
|
||||
|
||||
if (si.chipType == RAGE128_MOBILITY && si.panelX > 0 && si.panelY > 0) {
|
||||
if (INREG(R128_LVDS_GEN_CNTL) & R128_LVDS_ON)
|
||||
si.displayType = MT_LAPTOP; // laptop LCD display is on
|
||||
}
|
||||
|
||||
// Set up the array of color spaces supported by the Rage128 chips.
|
||||
|
||||
si.colorSpaces[0] = B_CMAP8;
|
||||
si.colorSpaces[1] = B_RGB15;
|
||||
si.colorSpaces[2] = B_RGB16;
|
||||
si.colorSpaces[3] = B_RGB32;
|
||||
si.colorSpaceCount = 4;
|
||||
|
||||
// Setup the mode list.
|
||||
|
||||
return CreateModeList(IsModeUsable);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rage128_SetFunctionPointers(void)
|
||||
{
|
||||
// Setting the function pointers must be done prior to first ModeInit call
|
||||
// or any accel activity.
|
||||
|
||||
gInfo.WaitForFifo = WaitForFifo;
|
||||
gInfo.WaitForIdle = WaitForIdle;
|
||||
|
||||
gInfo.DPMSCapabilities = Rage128_DPMSCapabilities;
|
||||
gInfo.GetDPMSMode = Rage128_GetDPMSMode;
|
||||
gInfo.SetDPMSMode = Rage128_SetDPMSMode;
|
||||
|
||||
gInfo.LoadCursorImage = Rage128_LoadCursorImage;
|
||||
gInfo.SetCursorPosition = Rage128_SetCursorPosition;
|
||||
gInfo.ShowCursor = Rage128_ShowCursor;
|
||||
|
||||
gInfo.FillRectangle = Rage128_FillRectangle;
|
||||
gInfo.FillSpan = Rage128_FillSpan;
|
||||
gInfo.InvertRectangle = Rage128_InvertRectangle;
|
||||
gInfo.ScreenToScreenBlit = Rage128_ScreenToScreenBlit;
|
||||
|
||||
gInfo.AdjustFrame = Rage128_AdjustFrame;
|
||||
gInfo.ChipInit = Rage128_Init;
|
||||
gInfo.GetColorSpaceParams = Rage128_GetColorSpaceParams;
|
||||
gInfo.SetDisplayMode = Rage128_SetDisplayMode;
|
||||
gInfo.SetIndexedColors = Rage128_SetIndexedColors;
|
||||
}
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
/*
|
||||
Haiku ATI video driver adapted from the X.org ATI driver.
|
||||
|
||||
Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
|
||||
Precision Insight, Inc., Cedar Park, Texas, and
|
||||
VA Linux Systems Inc., Fremont, California.
|
||||
|
||||
Copyright 2009 Haiku, Inc. All rights reserved.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Authors:
|
||||
Gerald Zajac 2009
|
||||
*/
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
#include "rage128.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
|
||||
struct DisplayParams {
|
||||
// CRTC registers
|
||||
uint32 crtc_gen_cntl;
|
||||
uint32 crtc_h_total_disp;
|
||||
uint32 crtc_h_sync_strt_wid;
|
||||
uint32 crtc_v_total_disp;
|
||||
uint32 crtc_v_sync_strt_wid;
|
||||
uint32 crtc_pitch;
|
||||
|
||||
// DDA register
|
||||
uint32 dda_config;
|
||||
uint32 dda_on_off;
|
||||
|
||||
// Computed PLL values
|
||||
int feedback_div;
|
||||
int post_div;
|
||||
|
||||
// PLL registers
|
||||
uint32 ppll_ref_div;
|
||||
uint32 ppll_div_3;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline int
|
||||
DivideWithRounding(int n, int d)
|
||||
{
|
||||
return (n + (d / 2)) / d; // compute n/d with rounding
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
MinimumBits(uint32 value)
|
||||
{
|
||||
// Compute minimum number of bits required to contain a value (ie, log
|
||||
// base 2 of value).
|
||||
|
||||
if (value == 0)
|
||||
return 1;
|
||||
|
||||
int numBits = 0;
|
||||
|
||||
while (value != 0) {
|
||||
value >>= 1;
|
||||
numBits++;
|
||||
}
|
||||
|
||||
return numBits;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
CalculateCrtcRegisters(const DisplayModeEx& mode, DisplayParams& params)
|
||||
{
|
||||
// Define CRTC registers for requested video mode.
|
||||
// Return true if successful.
|
||||
|
||||
const uint8 hSyncFudge[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
|
||||
|
||||
uint32 format;
|
||||
|
||||
switch (mode.bitsPerPixel) {
|
||||
case 8:
|
||||
format = 2;
|
||||
break;
|
||||
case 15:
|
||||
format = 3; // 555
|
||||
break;
|
||||
case 16:
|
||||
format = 4; // 565
|
||||
break;
|
||||
case 32:
|
||||
format = 6; // xRGB
|
||||
break;
|
||||
default:
|
||||
TRACE("Unsupported color depth: %d bits/pixel\n", mode.bitsPerPixel);
|
||||
return false;
|
||||
}
|
||||
|
||||
params.crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN
|
||||
| R128_CRTC_EN
|
||||
| (format << 8));
|
||||
|
||||
params.crtc_h_total_disp = (((mode.timing.h_total / 8) - 1) & 0xffff)
|
||||
| (((mode.timing.h_display / 8) - 1) << 16);
|
||||
|
||||
int hSyncWidth = (mode.timing.h_sync_end - mode.timing.h_sync_start) / 8;
|
||||
if (hSyncWidth <= 0)
|
||||
hSyncWidth = 1;
|
||||
if (hSyncWidth > 0x3f)
|
||||
hSyncWidth = 0x3f;
|
||||
|
||||
int hSyncStart = mode.timing.h_sync_start - 8 + hSyncFudge[format - 1];
|
||||
|
||||
params.crtc_h_sync_strt_wid = (hSyncStart & 0xfff) | (hSyncWidth << 16)
|
||||
| ((mode.timing.flags & B_POSITIVE_HSYNC) ? 0 : R128_CRTC_H_SYNC_POL);
|
||||
|
||||
params.crtc_v_total_disp = (((mode.timing.v_total - 1) & 0xffff)
|
||||
| ((mode.timing.v_display - 1) << 16));
|
||||
|
||||
int vSyncWidth = mode.timing.v_sync_end - mode.timing.v_sync_start;
|
||||
if (vSyncWidth <= 0)
|
||||
vSyncWidth = 1;
|
||||
if (vSyncWidth > 0x1f)
|
||||
vSyncWidth = 0x1f;
|
||||
|
||||
params.crtc_v_sync_strt_wid = ((mode.timing.v_sync_start - 1) & 0xfff)
|
||||
| (vSyncWidth << 16)
|
||||
| ((mode.timing.flags & B_POSITIVE_VSYNC) ? 0 : R128_CRTC_V_SYNC_POL);
|
||||
|
||||
params.crtc_pitch = mode.timing.h_display / 8;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
CalculateDDARegisters(const DisplayModeEx& mode, DisplayParams& params)
|
||||
{
|
||||
// Compute and write DDA registers for requested video mode.
|
||||
// Return true if successful.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
R128_RAMSpec& memSpec = si.r128MemSpec;
|
||||
R128_PLLParams& pll = si.r128PLLParams;
|
||||
|
||||
int displayFifoWidth = 128;
|
||||
int displayFifoDepth = 32;
|
||||
int xClkFreq = pll.xclk;
|
||||
|
||||
int vClkFreq = DivideWithRounding(pll.reference_freq * params.feedback_div,
|
||||
pll.reference_div * params.post_div);
|
||||
|
||||
int bytesPerPixel = (mode.bitsPerPixel + 7) / 8;
|
||||
|
||||
int xClksPerTransfer = DivideWithRounding(xClkFreq * displayFifoWidth,
|
||||
vClkFreq * bytesPerPixel * 8);
|
||||
|
||||
int useablePrecision = MinimumBits(xClksPerTransfer) + 1;
|
||||
|
||||
int xClksPerTransferPrecise = DivideWithRounding(
|
||||
(xClkFreq * displayFifoWidth) << (11 - useablePrecision),
|
||||
vClkFreq * bytesPerPixel * 8);
|
||||
|
||||
int rOff = xClksPerTransferPrecise * (displayFifoDepth - 4);
|
||||
|
||||
int rOn = (4 * memSpec.memBurstLen
|
||||
+ 3 * MAX(memSpec.rasToCasDelay - 2, 0)
|
||||
+ 2 * memSpec.rasPercentage
|
||||
+ memSpec.writeRecovery
|
||||
+ memSpec.casLatency
|
||||
+ memSpec.readToWriteDelay
|
||||
+ xClksPerTransfer) << (11 - useablePrecision);
|
||||
|
||||
if (rOn + memSpec.loopLatency >= rOff) {
|
||||
TRACE("Error: (rOn = %d) + (loopLatency = %d) >= (rOff = %d)\n",
|
||||
rOn, memSpec.loopLatency, rOff);
|
||||
return false;
|
||||
}
|
||||
|
||||
params.dda_config = xClksPerTransferPrecise | (useablePrecision << 16)
|
||||
| (memSpec.loopLatency << 20);
|
||||
params.dda_on_off = (rOn << 16) | rOff;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
CalculatePLLRegisters(const DisplayModeEx& mode, DisplayParams& params)
|
||||
{
|
||||
// Define PLL registers for requested video mode.
|
||||
|
||||
struct Divider {
|
||||
int divider;
|
||||
int bitValue;
|
||||
};
|
||||
|
||||
// The following data is from RAGE 128 VR/RAGE 128 GL Register Reference
|
||||
// Manual (Technical Reference Manual P/N RRG-G04100-C Rev. 0.04), page
|
||||
// 3-17 (PLL_DIV_[3:0]).
|
||||
|
||||
const Divider postDividers[] = {
|
||||
{ 1, 0 }, // VCLK_SRC
|
||||
{ 2, 1 }, // VCLK_SRC/2
|
||||
{ 4, 2 }, // VCLK_SRC/4
|
||||
{ 8, 3 }, // VCLK_SRC/8
|
||||
{ 3, 4 }, // VCLK_SRC/3
|
||||
// bitValue = 5 is reserved
|
||||
{ 6, 6 }, // VCLK_SRC/6
|
||||
{ 12, 7 } // VCLK_SRC/12
|
||||
};
|
||||
|
||||
R128_PLLParams& pll = gInfo.sharedInfo->r128PLLParams;
|
||||
uint32 freq = mode.timing.pixel_clock / 10;
|
||||
|
||||
if (freq > pll.max_pll_freq)
|
||||
freq = pll.max_pll_freq;
|
||||
if (freq * 12 < pll.min_pll_freq)
|
||||
freq = pll.min_pll_freq / 12;
|
||||
|
||||
int bitValue = -1;
|
||||
uint32 output_freq;
|
||||
|
||||
for (int j = 0; j < ARRAY_SIZE(postDividers); j++) {
|
||||
output_freq = postDividers[j].divider * freq;
|
||||
if (output_freq >= pll.min_pll_freq && output_freq <= pll.max_pll_freq) {
|
||||
params.feedback_div = DivideWithRounding(pll.reference_div * output_freq,
|
||||
pll.reference_freq);
|
||||
params.post_div = postDividers[j].divider;
|
||||
bitValue = postDividers[j].bitValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bitValue < 0) {
|
||||
TRACE("CalculatePLLRegisters(), acceptable divider not found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
params.ppll_ref_div = pll.reference_div;
|
||||
params.ppll_div_3 = (params.feedback_div | (bitValue << 16));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
PLLWaitForReadUpdateComplete()
|
||||
{
|
||||
while (GetPLLReg(R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
PLLWriteUpdate()
|
||||
{
|
||||
PLLWaitForReadUpdateComplete();
|
||||
|
||||
SetPLLReg(R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W, R128_PPLL_ATOMIC_UPDATE_W);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
SetRegisters(DisplayParams& params)
|
||||
{
|
||||
// Write the common registers (most will be set to zero).
|
||||
//-------------------------------------------------------
|
||||
|
||||
OUTREGM(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, R128_FP_BLANK_DIS);
|
||||
|
||||
OUTREG(R128_OVR_CLR, 0);
|
||||
OUTREG(R128_OVR_WID_LEFT_RIGHT, 0);
|
||||
OUTREG(R128_OVR_WID_TOP_BOTTOM, 0);
|
||||
OUTREG(R128_OV0_SCALE_CNTL, 0);
|
||||
OUTREG(R128_MPP_TB_CONFIG, 0);
|
||||
OUTREG(R128_MPP_GP_CONFIG, 0);
|
||||
OUTREG(R128_SUBPIC_CNTL, 0);
|
||||
OUTREG(R128_VIPH_CONTROL, 0);
|
||||
OUTREG(R128_I2C_CNTL_1, 0);
|
||||
OUTREG(R128_GEN_INT_CNTL, 0);
|
||||
OUTREG(R128_CAP0_TRIG_CNTL, 0);
|
||||
OUTREG(R128_CAP1_TRIG_CNTL, 0);
|
||||
|
||||
// If bursts are enabled, turn on discards and aborts.
|
||||
|
||||
uint32 busCntl = INREG(R128_BUS_CNTL);
|
||||
if (busCntl & (R128_BUS_WRT_BURST | R128_BUS_READ_BURST)) {
|
||||
busCntl |= R128_BUS_RD_DISCARD_EN | R128_BUS_RD_ABORT_EN;
|
||||
OUTREG(R128_BUS_CNTL, busCntl);
|
||||
}
|
||||
|
||||
// Write the DDA registers.
|
||||
//-------------------------
|
||||
|
||||
OUTREG(R128_DDA_CONFIG, params.dda_config);
|
||||
OUTREG(R128_DDA_ON_OFF, params.dda_on_off);
|
||||
|
||||
// Write the CRTC registers.
|
||||
//--------------------------
|
||||
|
||||
OUTREG(R128_CRTC_GEN_CNTL, params.crtc_gen_cntl);
|
||||
|
||||
OUTREGM(R128_DAC_CNTL, R128_DAC_MASK_ALL | R128_DAC_8BIT_EN,
|
||||
~(R128_DAC_RANGE_CNTL | R128_DAC_BLANKING));
|
||||
|
||||
OUTREG(R128_CRTC_H_TOTAL_DISP, params.crtc_h_total_disp);
|
||||
OUTREG(R128_CRTC_H_SYNC_STRT_WID, params.crtc_h_sync_strt_wid);
|
||||
OUTREG(R128_CRTC_V_TOTAL_DISP, params.crtc_v_total_disp);
|
||||
OUTREG(R128_CRTC_V_SYNC_STRT_WID, params.crtc_v_sync_strt_wid);
|
||||
OUTREG(R128_CRTC_OFFSET, 0);
|
||||
OUTREG(R128_CRTC_OFFSET_CNTL, 0);
|
||||
OUTREG(R128_CRTC_PITCH, params.crtc_pitch);
|
||||
|
||||
// Write the PLL registers.
|
||||
//-------------------------
|
||||
|
||||
OUTREGM(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, R128_PLL_DIV_SEL);
|
||||
|
||||
SetPLLReg(R128_VCLK_ECP_CNTL, R128_VCLK_SRC_SEL_CPUCLK, R128_VCLK_SRC_SEL_MASK);
|
||||
|
||||
SetPLLReg(R128_PPLL_CNTL, 0xffffffff,
|
||||
R128_PPLL_RESET | R128_PPLL_ATOMIC_UPDATE_EN | R128_PPLL_VGA_ATOMIC_UPDATE_EN);
|
||||
|
||||
PLLWaitForReadUpdateComplete();
|
||||
SetPLLReg(R128_PPLL_REF_DIV, params.ppll_ref_div, R128_PPLL_REF_DIV_MASK);
|
||||
PLLWriteUpdate();
|
||||
|
||||
PLLWaitForReadUpdateComplete();
|
||||
SetPLLReg(R128_PPLL_DIV_3, params.ppll_div_3,
|
||||
R128_PPLL_FB3_DIV_MASK | R128_PPLL_POST3_DIV_MASK);
|
||||
PLLWriteUpdate();
|
||||
|
||||
PLLWaitForReadUpdateComplete();
|
||||
SetPLLReg(R128_HTOTAL_CNTL, 0);
|
||||
PLLWriteUpdate();
|
||||
|
||||
SetPLLReg(R128_PPLL_CNTL, 0, R128_PPLL_RESET
|
||||
| R128_PPLL_SLEEP
|
||||
| R128_PPLL_ATOMIC_UPDATE_EN
|
||||
| R128_PPLL_VGA_ATOMIC_UPDATE_EN);
|
||||
|
||||
snooze(5000);
|
||||
|
||||
SetPLLReg(R128_VCLK_ECP_CNTL, R128_VCLK_SRC_SEL_PPLLCLK,
|
||||
R128_VCLK_SRC_SEL_MASK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
status_t
|
||||
Rage128_SetDisplayMode(const DisplayModeEx& mode)
|
||||
{
|
||||
// The code to actually configure the display.
|
||||
// All the error checking must be done in ProposeDisplayMode(),
|
||||
// and assume that the mode values we get here are acceptable.
|
||||
|
||||
DisplayParams params; // where computed parameters are saved
|
||||
|
||||
if (gInfo.sharedInfo->displayType == MT_VGA) {
|
||||
// Chip is connected to a monitor via a VGA connector.
|
||||
|
||||
if ( ! CalculateCrtcRegisters(mode, params))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if ( ! CalculatePLLRegisters(mode, params))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if ( ! CalculateDDARegisters(mode, params))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
SetRegisters(params);
|
||||
|
||||
} else {
|
||||
// Chip is connected to a laptop LCD monitor; or via a DVI interface.
|
||||
|
||||
uint16 vesaMode = GetVesaModeNumber(display_mode(mode), mode.bitsPerPixel);
|
||||
if (vesaMode == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (ioctl(gInfo.deviceFileDesc, ATI_SET_VESA_DISPLAY_MODE,
|
||||
&vesaMode, sizeof(vesaMode)) != B_OK)
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
Rage128_AdjustFrame(mode);
|
||||
|
||||
// Initialize the palette so that color depths > 8 bits/pixel will display
|
||||
// the correct colors.
|
||||
|
||||
// Select primary monitor and enable 8-bit color.
|
||||
OUTREGM(R128_DAC_CNTL, R128_DAC_8BIT_EN,
|
||||
R128_DAC_PALETTE_ACC_CTL | R128_DAC_8BIT_EN);
|
||||
OUTREG8(R128_PALETTE_INDEX, 0); // set first color index
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
OUTREG(R128_PALETTE_DATA, (i << 16) | (i << 8) | i );
|
||||
|
||||
Rage128_EngineInit(mode);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Rage128_AdjustFrame(const DisplayModeEx& mode)
|
||||
{
|
||||
// Adjust start address in frame buffer.
|
||||
|
||||
SharedInfo& si = *gInfo.sharedInfo;
|
||||
|
||||
int address = (mode.v_display_start * mode.virtual_width
|
||||
+ mode.h_display_start) * ((mode.bitsPerPixel + 1) / 8);
|
||||
|
||||
address &= ~0x07;
|
||||
address += si.frameBufferOffset;
|
||||
|
||||
OUTREG(R128_CRTC_OFFSET, address);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Rage128_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
|
||||
{
|
||||
// Set the indexed color palette for 8-bit color depth mode.
|
||||
|
||||
(void)flags; // avoid compiler warning for unused arg
|
||||
|
||||
if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
|
||||
return ;
|
||||
|
||||
// Select primary monitor and enable 8-bit color.
|
||||
OUTREGM(R128_DAC_CNTL, R128_DAC_8BIT_EN,
|
||||
R128_DAC_PALETTE_ACC_CTL | R128_DAC_8BIT_EN);
|
||||
OUTREG8(R128_PALETTE_INDEX, first); // set first color index
|
||||
|
||||
while (count--) {
|
||||
OUTREG(R128_PALETTE_DATA, ((colorData[0] << 16) // red
|
||||
| (colorData[1] << 8) // green
|
||||
| colorData[2])); // blue
|
||||
colorData += 3;
|
||||
}
|
||||
}
|
|
@ -1,434 +0,0 @@
|
|||
#include <GraphicsDefs.h>
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
#define STICKY_REGS 1
|
||||
|
||||
#define WRITE_REG(x, y) outw(x, y)
|
||||
|
||||
#define wait_for_slots(num) WaitQueue(num)
|
||||
|
||||
/*#define wait_for_slots(numSlots) \
|
||||
{ \
|
||||
uint32 FifoReg; \
|
||||
\
|
||||
do \
|
||||
{ \
|
||||
READ_REG(FIFO_STAT, FifoReg); \
|
||||
} \
|
||||
while ((FifoReg & 0xFFFF) >> (16 - numSlots)); \
|
||||
}
|
||||
*/
|
||||
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count) {
|
||||
|
||||
uint32 Offset, Pitch;
|
||||
uint32 BppEncoding;
|
||||
uint32 XDir;
|
||||
uint32 YDir;
|
||||
|
||||
uint32 src_top, src_left;
|
||||
uint32 dest_top, dest_left;
|
||||
uint32 width, height;
|
||||
|
||||
uint32 scissor_x = (si->dm.virtual_width - 1) << 16;
|
||||
uint32 scissor_y = (si->dm.virtual_height - 1) << 16;
|
||||
|
||||
// Perform required calculations and do the blit.
|
||||
// start of frame buffer
|
||||
Offset = 1024;
|
||||
Offset = Offset >> 3; // qword offset of the frame buffer in card memory; had
|
||||
// better be qword-aligned.
|
||||
|
||||
Pitch = si->dm.virtual_width;
|
||||
Pitch = (Pitch + 7) >> 3; // frame buffer stride in pixels*8
|
||||
|
||||
// encode pixel format
|
||||
switch (si->dm.space & ~0x3000)
|
||||
{
|
||||
case B_CMAP8:
|
||||
BppEncoding = 0x2;
|
||||
break;
|
||||
case B_RGB15_BIG:
|
||||
case B_RGBA15_BIG:
|
||||
case B_RGB15_LITTLE:
|
||||
case B_RGBA15_LITTLE:
|
||||
BppEncoding = 0x3;
|
||||
break;
|
||||
case B_RGB16_BIG:
|
||||
case B_RGB16_LITTLE:
|
||||
BppEncoding = 0x4;
|
||||
break;
|
||||
case B_RGB32_BIG:
|
||||
case B_RGBA32_BIG:
|
||||
case B_RGB32_LITTLE:
|
||||
case B_RGBA32_LITTLE:
|
||||
default:
|
||||
BppEncoding = 0x6;
|
||||
}
|
||||
|
||||
BppEncoding = (BppEncoding << 28) | (BppEncoding << 16) | (BppEncoding << 8)
|
||||
| (BppEncoding << 4) | BppEncoding;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(10);
|
||||
|
||||
WRITE_REG(SC_LEFT_RIGHT, scissor_x);
|
||||
WRITE_REG(SC_TOP_BOTTOM, scissor_y);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, 0x00070007); // ROP = SRC
|
||||
WRITE_REG(DP_SRC, 0x00000300);
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(SRC_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
/* update fifo count */
|
||||
si->engine.count += 10;
|
||||
#endif
|
||||
|
||||
/* program the blit */
|
||||
while (count--) {
|
||||
src_left = list->src_left;
|
||||
src_top = list->src_top;
|
||||
dest_left = list->dest_left;
|
||||
dest_top = list->dest_top;
|
||||
width = list->width + 1; /* + 1 because it seems to be non-inclusive */
|
||||
height = list->height + 1;
|
||||
|
||||
// Adjust direction of blitting to allow for overlapping source and destination.
|
||||
if (src_left < dest_left)
|
||||
{
|
||||
XDir = 0; // right to left
|
||||
src_left += (width - 1);
|
||||
dest_left += (width - 1);
|
||||
}
|
||||
else
|
||||
XDir = 1; // left to right
|
||||
|
||||
if (src_top < dest_top)
|
||||
{
|
||||
YDir = 0; // bottom to top
|
||||
src_top += (height - 1);
|
||||
dest_top += (height - 1);
|
||||
}
|
||||
else
|
||||
YDir = 1; // top to bottom
|
||||
|
||||
|
||||
// Set up the rectangle blit
|
||||
|
||||
// Critital section - accessing card registers.
|
||||
//lock_card();
|
||||
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(5);
|
||||
#else
|
||||
wait_for_slots(15);
|
||||
|
||||
WRITE_REG(SC_LEFT_RIGHT, scissor_x);
|
||||
WRITE_REG(SC_TOP_BOTTOM, scissor_y);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, 0x00070007); // ROP = SRC
|
||||
WRITE_REG(DP_SRC, 0x00000300);
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(SRC_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
#endif
|
||||
|
||||
WRITE_REG(SRC_WIDTH1, width);
|
||||
WRITE_REG(SRC_Y_X, ((uint32)src_left << 16) | src_top);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_CNTL, (YDir << 1) | XDir);
|
||||
WRITE_REG(DST_Y_X, ((uint32)dest_left << 16) | dest_top);
|
||||
WRITE_REG(DST_HEIGHT_WIDTH, ((uint32)width << 16) | height); // This triggers drawing.
|
||||
|
||||
#if STICKY_REGS
|
||||
/* update fifo count */
|
||||
si->engine.count += 5;
|
||||
#else
|
||||
/* update fifo count */
|
||||
si->engine.count += 15;
|
||||
#endif
|
||||
/* next one */
|
||||
list++;
|
||||
}
|
||||
}
|
||||
|
||||
void hardware_rectangle(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count, uint32 ROP) {
|
||||
|
||||
uint32 Offset;
|
||||
uint32 Pitch;
|
||||
uint32 Y;
|
||||
uint32 X;
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
uint32 Colour;
|
||||
uint32 BppEncoding;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
uint32 scissor_x = (si->dm.virtual_width - 1) << 16;
|
||||
uint32 scissor_y = (si->dm.virtual_height - 1) << 16;
|
||||
#endif
|
||||
|
||||
// Perform required calculations and do the blit.
|
||||
// start of frame buffer
|
||||
Offset = 1024;
|
||||
Offset = Offset >> 3; // qword offset of the frame buffer in card memory; had
|
||||
// better be qword-aligned.
|
||||
|
||||
Pitch = si->dm.virtual_width;
|
||||
Pitch = (Pitch + 7) >> 3; // frame buffer stride in pixels*8
|
||||
|
||||
// Don't need this - rectangle is in frame buffer co-ordinates.
|
||||
// X += (uint32) (CardInfo.Display.DisplayXPos);
|
||||
// Y += (uint32) (CardInfo.Display.DisplayYPos);
|
||||
|
||||
// Fill colour dword with specified colour, though only ls should be necessary.
|
||||
switch (si->dm.space & ~0x3000)
|
||||
{
|
||||
case B_CMAP8:
|
||||
BppEncoding = 0x2;
|
||||
colorIndex &= 0xFF;
|
||||
Colour = colorIndex | (colorIndex << 8) | (colorIndex << 16) | (colorIndex << 24);
|
||||
break;
|
||||
case B_RGB15_BIG:
|
||||
case B_RGBA15_BIG:
|
||||
case B_RGB15_LITTLE:
|
||||
case B_RGBA15_LITTLE:
|
||||
BppEncoding = 0x3;
|
||||
colorIndex &= 0xFFFF;
|
||||
Colour = colorIndex | (colorIndex << 16);
|
||||
break;
|
||||
case B_RGB16_BIG:
|
||||
case B_RGB16_LITTLE:
|
||||
BppEncoding = 0x4;
|
||||
colorIndex &= 0xFFFF;
|
||||
Colour = colorIndex | (colorIndex << 16);
|
||||
break;
|
||||
case B_RGB32_BIG:
|
||||
case B_RGBA32_BIG:
|
||||
case B_RGB32_LITTLE:
|
||||
case B_RGBA32_LITTLE:
|
||||
default:
|
||||
BppEncoding = 0x6;
|
||||
Colour = colorIndex;
|
||||
}
|
||||
|
||||
BppEncoding = (BppEncoding << 28) | (BppEncoding << 16) | (BppEncoding << 8) | (BppEncoding << 4) | BppEncoding;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(11);
|
||||
// This seems to be needed even though we aren't using a source trajectory.
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
|
||||
WRITE_REG(DP_FRGD_CLR, Colour);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, ROP);
|
||||
WRITE_REG(DP_SRC, 0x00000100);
|
||||
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
WRITE_REG(GUI_TRAJ_CNTL, 0x3);
|
||||
WRITE_REG(SC_LEFT_RIGHT, scissor_x);
|
||||
WRITE_REG(SC_TOP_BOTTOM, scissor_y);
|
||||
/* update fifo count */
|
||||
si->engine.count += 11;
|
||||
#endif
|
||||
|
||||
while (count--) {
|
||||
|
||||
X = list->left;
|
||||
Y = list->top;
|
||||
Width = list->right;
|
||||
Width = Width - X + 1;
|
||||
Height = list->bottom;
|
||||
Height = Height - Y + 1;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(2);
|
||||
#else
|
||||
wait_for_slots(13);
|
||||
// This seems to be needed even though we aren't using a source trajectory.
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
|
||||
WRITE_REG(DP_FRGD_CLR, Colour);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, ROP);
|
||||
WRITE_REG(DP_SRC, 0x00000100);
|
||||
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
WRITE_REG(GUI_TRAJ_CNTL, 0x3);
|
||||
|
||||
WRITE_REG(SC_LEFT_RIGHT, ((X + Width - 1) << 16) | X);
|
||||
WRITE_REG(SC_TOP_BOTTOM, ((Y + Height - 1) << 16) | Y);
|
||||
#endif
|
||||
|
||||
// X and Y should have been clipped to frame buffer, and so should be in range.
|
||||
WRITE_REG(DST_Y_X, (X << 16) | Y);
|
||||
WRITE_REG(DST_HEIGHT_WIDTH, (Width << 16) | Height); // This triggers drawing.
|
||||
|
||||
#if STICKY_REGS
|
||||
/* update fifo count */
|
||||
si->engine.count += 2;
|
||||
#else
|
||||
/* update fifo count */
|
||||
si->engine.count += 13;
|
||||
#endif
|
||||
|
||||
/* next rect */
|
||||
list++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FILL_RECTANGLE(engine_token *et, uint32 colorIndex, fill_rect_params *list, uint32 count) {
|
||||
hardware_rectangle(et, colorIndex, list, count, 0x00070007); // ROP = SRC
|
||||
}
|
||||
|
||||
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count) {
|
||||
hardware_rectangle(et, 0xFFFFFFFF, list, count, 0x00000000); // ROP = !DST
|
||||
}
|
||||
|
||||
void FILL_SPAN(engine_token *et, uint32 colorIndex, uint16 *list, uint32 count) {
|
||||
uint32 Offset;
|
||||
uint32 Pitch;
|
||||
uint32 Y;
|
||||
uint32 X;
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
uint32 Colour;
|
||||
uint32 BppEncoding;
|
||||
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
uint32 scissor_x = (si->dm.virtual_width - 1) << 16;
|
||||
uint32 scissor_y = (si->dm.virtual_height - 1) << 16;
|
||||
#endif
|
||||
|
||||
// Perform required calculations and do the blit.
|
||||
// start of frame buffer
|
||||
Offset = 1024;
|
||||
Offset = Offset >> 3; // qword offset of the frame buffer in card memory; had
|
||||
// better be qword-aligned.
|
||||
|
||||
Pitch = si->dm.virtual_width;
|
||||
Pitch = (Pitch + 7) >> 3; // frame buffer stride in pixels*8
|
||||
|
||||
// Fill colour dword with specified colour, though only ls should be necessary.
|
||||
switch (si->dm.space & ~0x3000)
|
||||
{
|
||||
case B_CMAP8:
|
||||
BppEncoding = 0x2;
|
||||
colorIndex &= 0xFF;
|
||||
Colour = colorIndex | (colorIndex << 8) | (colorIndex << 16) | (colorIndex << 24);
|
||||
break;
|
||||
case B_RGB15_BIG:
|
||||
case B_RGBA15_BIG:
|
||||
case B_RGB15_LITTLE:
|
||||
case B_RGBA15_LITTLE:
|
||||
BppEncoding = 0x3;
|
||||
colorIndex &= 0xFFFF;
|
||||
Colour = colorIndex | (colorIndex << 16);
|
||||
break;
|
||||
case B_RGB16_BIG:
|
||||
case B_RGB16_LITTLE:
|
||||
BppEncoding = 0x4;
|
||||
colorIndex &= 0xFFFF;
|
||||
Colour = colorIndex | (colorIndex << 16);
|
||||
break;
|
||||
case B_RGB32_BIG:
|
||||
case B_RGBA32_BIG:
|
||||
case B_RGB32_LITTLE:
|
||||
case B_RGBA32_LITTLE:
|
||||
default:
|
||||
BppEncoding = 0x6;
|
||||
Colour = colorIndex;
|
||||
}
|
||||
|
||||
BppEncoding = (BppEncoding << 28) | (BppEncoding << 16) | (BppEncoding << 8) | (BppEncoding << 4) | BppEncoding;
|
||||
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(11);
|
||||
// This seems to be needed even though we aren't using a source trajectory.
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
|
||||
WRITE_REG(DP_FRGD_CLR, Colour);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, 0x00070007); // ROP = SRC
|
||||
WRITE_REG(DP_SRC, 0x00000100);
|
||||
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
WRITE_REG(GUI_TRAJ_CNTL, 0x3);
|
||||
WRITE_REG(SC_LEFT_RIGHT, scissor_x);
|
||||
WRITE_REG(SC_TOP_BOTTOM, scissor_y);
|
||||
/* update fifo count */
|
||||
si->engine.count += 11;
|
||||
#endif
|
||||
/* span lines are always one pixel tall */
|
||||
Height = 1;
|
||||
while (count--) {
|
||||
|
||||
Y = (uint32)*list++;
|
||||
X = (uint32)*list++;
|
||||
Width = (uint32)*list++;
|
||||
Width = Width - X + 1;
|
||||
|
||||
#if STICKY_REGS > 0
|
||||
wait_for_slots(2);
|
||||
#else
|
||||
wait_for_slots(13);
|
||||
// This seems to be needed even though we aren't using a source trajectory.
|
||||
WRITE_REG(SRC_CNTL, 0x0);
|
||||
|
||||
// Pitch and offset had better not be out of range.
|
||||
WRITE_REG(DST_OFF_PITCH, (Pitch << 22) | Offset);
|
||||
|
||||
WRITE_REG(DP_FRGD_CLR, Colour);
|
||||
WRITE_REG(DP_WRITE_MASK, 0xFFFFFFFF);
|
||||
WRITE_REG(DP_PIX_WIDTH, BppEncoding);
|
||||
WRITE_REG(DP_MIX, 0x00070007); // ROP = SRC
|
||||
WRITE_REG(DP_SRC, 0x00000100);
|
||||
|
||||
WRITE_REG(CLR_CMP_CNTL, 0x0);
|
||||
WRITE_REG(GUI_TRAJ_CNTL, 0x3);
|
||||
|
||||
WRITE_REG(SC_LEFT_RIGHT, ((X + Width - 1) << 16) | X);
|
||||
WRITE_REG(SC_TOP_BOTTOM, ((Y + Height - 1) << 16) | Y);
|
||||
#endif
|
||||
|
||||
// X and Y should have been clipped to frame buffer, and so should be in range.
|
||||
WRITE_REG(DST_Y_X, (X << 16) | Y);
|
||||
WRITE_REG(DST_HEIGHT_WIDTH, (Width << 16) | Height); // This triggers drawing.
|
||||
|
||||
#if STICKY_REGS
|
||||
/* update fifo count */
|
||||
si->engine.count += 2;
|
||||
#else
|
||||
/* update fifo count */
|
||||
si->engine.count += 13;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,210 +0,0 @@
|
|||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
void set_cursor_colors(void);
|
||||
uint8 bit_mirror(uint8 bits);
|
||||
uint16 bit_merger(uint8 andbits, uint8 xorbits);
|
||||
|
||||
void set_cursor_colors(void) {
|
||||
/* a place-holder for a routine to set the cursor colors */
|
||||
/* In our sample driver, it's only called by the INIT_ACCELERANT() */
|
||||
|
||||
/* Cursor color 0 is black */
|
||||
|
||||
outw(CUR_CLR0, 0x00000000);
|
||||
|
||||
/* Cursor color 1 is white */
|
||||
|
||||
outw(CUR_CLR1, 0xffffffff);
|
||||
|
||||
}
|
||||
|
||||
uint8
|
||||
bit_mirror(uint8 bits)
|
||||
{
|
||||
int i;
|
||||
uint8 res = 0;
|
||||
|
||||
for(i=0; i<8; i++) {
|
||||
res |= (1 & (bits>>i)) <<(7-i);
|
||||
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint16
|
||||
bit_merger(uint8 andbits, uint8 xorbits)
|
||||
{
|
||||
int i;
|
||||
uint16 res = 0;
|
||||
uint8 bits = 0;
|
||||
|
||||
for(i=0; i<8; i++) {
|
||||
bits = (((xorbits & (1<<i))>>i)<<1) | ((andbits & (1<<i))>>i);
|
||||
switch (bits){
|
||||
case 0: /* Transparent is 10 */
|
||||
res |= (2 << (i*2));
|
||||
break;
|
||||
case 2: /* Inversion is 11 */
|
||||
res |= (3 << (i*2));
|
||||
break;
|
||||
case 1: /* White is color 1 */
|
||||
res |= (1 << (i*2));
|
||||
break;
|
||||
case 3: /* Black is color 0 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask) {
|
||||
|
||||
int i, j, k;
|
||||
uint8 andM, xorM;
|
||||
uint16 *cdata = (uint16 *)si->cursor.data;
|
||||
|
||||
/* NOTE: Currently, for BeOS, cursor width and height must be equal to 16. */
|
||||
|
||||
if ((width != 16) || (height != 16))
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
else if ((hot_x >= width) || (hot_y >= height))
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Turn off cursor */
|
||||
SHOW_CURSOR(false);
|
||||
|
||||
|
||||
/* Fill up data */
|
||||
k = 0;
|
||||
for(i = 0; i < height; i++) {
|
||||
for(j = 0; j < (width / 8); j++) {
|
||||
andM = bit_mirror(~*(andMask++));
|
||||
xorM = bit_mirror(*(xorMask++));
|
||||
|
||||
/* convert 8 bits to 16 bits of mask */
|
||||
cdata[j + (i*8)] =
|
||||
bit_merger(andM, xorM);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/* Update cursor variables appropriately. */
|
||||
si->cursor.width = width;
|
||||
si->cursor.height = height;
|
||||
si->cursor.hot_x = hot_x;
|
||||
si->cursor.hot_y = hot_y;
|
||||
|
||||
/* Turn on cursor */
|
||||
SHOW_CURSOR(true);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Move the cursor to the specified position on the desktop. If we're
|
||||
using some kind of virtual desktop, adjust the display start position
|
||||
accordingly and position the cursor in the proper "virtual" location.
|
||||
*/
|
||||
void
|
||||
MOVE_CURSOR(uint16 x, uint16 y) {
|
||||
|
||||
bool move_screen = false;
|
||||
uint16 hds = si->dm.h_display_start; /* the current horizontal starting pixel */
|
||||
uint16 vds = si->dm.v_display_start; /* the current vertical starting line */
|
||||
int xoff, yoff; /* offsets of cursor if it goes out of the screen */
|
||||
/*
|
||||
Most cards can't set the starting horizontal pixel to anything but a multiple
|
||||
of eight. If your card can, then you can change the adjustment factor here.
|
||||
Oftentimes the restriction is mode dependant, so you could be fancier and
|
||||
perhaps get smoother horizontal scrolling with more work. It's a sample driver,
|
||||
so we're going to be lazy here.
|
||||
*/
|
||||
uint16 h_adjust = 7; /* a mask to make horizontal values a multiple of 8 */
|
||||
|
||||
/* clamp cursor to virtual display */
|
||||
if (x >= si->dm.virtual_width) x = si->dm.virtual_width - 1;
|
||||
if (y >= si->dm.virtual_height) y = si->dm.virtual_height - 1;
|
||||
|
||||
/* adjust h/v_display_start to move cursor onto screen */
|
||||
if (x >= (si->dm.timing.h_display + hds)) {
|
||||
hds = ((x - si->dm.timing.h_display) + 1 + h_adjust) & ~h_adjust;
|
||||
move_screen = true;
|
||||
} else if (x < hds) {
|
||||
hds = x & ~h_adjust;
|
||||
move_screen = true;
|
||||
}
|
||||
if (y >= (si->dm.timing.v_display + vds)) {
|
||||
vds = y - si->dm.timing.v_display + 1;
|
||||
move_screen = true;
|
||||
} else if (y < vds) {
|
||||
vds = y;
|
||||
move_screen = true;
|
||||
}
|
||||
/* reposition the desktop on the display if required */
|
||||
if (move_screen) MOVE_DISPLAY(hds,vds);
|
||||
|
||||
/* put cursor in correct physical position */
|
||||
x -= hds;
|
||||
y -= vds;
|
||||
|
||||
/* Take care of hot_x hot_y */
|
||||
xoff = x - si->cursor.hot_x;
|
||||
yoff = y - si->cursor.hot_y;
|
||||
|
||||
/* Do we have to fake the cursor going out of the screen ? */
|
||||
if (xoff < 0) {
|
||||
xoff = -xoff;
|
||||
} else {
|
||||
xoff = 0;
|
||||
x -= si->cursor.hot_x;
|
||||
}
|
||||
|
||||
if (yoff < 0) {
|
||||
yoff = -yoff;
|
||||
} else {
|
||||
yoff = 0;
|
||||
y -= si->cursor.hot_y;
|
||||
}
|
||||
|
||||
/* Position the offset of the cursor */
|
||||
outw(CUR_HORZ_VERT_OFF, (yoff << 16) | xoff);
|
||||
|
||||
|
||||
/* position the cursor on the display */
|
||||
/* this will be card dependant */
|
||||
|
||||
/* printf(" Place %08x %d %d \n", si->regs + CUR_HORZ_VERT_POSN, x, y);*/
|
||||
|
||||
outw(CUR_HORZ_VERT_POSN, (y << 16) | x);
|
||||
|
||||
}
|
||||
|
||||
void SHOW_CURSOR(bool is_visible) {
|
||||
|
||||
if (is_visible) {
|
||||
/* add cursor showing code here */
|
||||
WaitQueue(4);
|
||||
while (!(inw(CRTC_VLINE_CRNT_VLINE) & CRTC_CRNT_VLINE));
|
||||
outb(GEN_TEST_CNTL, inb(GEN_TEST_CNTL) | HWCURSOR_ENABLE);
|
||||
} else {
|
||||
/* add cursor hiding code here */
|
||||
WaitQueue(4);
|
||||
outb(GEN_TEST_CNTL, inb(GEN_TEST_CNTL) & (~HWCURSOR_ENABLE));
|
||||
}
|
||||
|
||||
WaitIdleEmpty();
|
||||
|
||||
/* record for our info */
|
||||
si->cursor.is_visible = is_visible;
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
|
||||
static engine_token ati_engine_token = { 1, B_2D_ACCELERATION, NULL };
|
||||
|
||||
uint32 ACCELERANT_ENGINE_COUNT(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et) {
|
||||
/* acquire the shared benaphore */
|
||||
AQUIRE_BEN(si->engine.lock)
|
||||
/* sync if required */
|
||||
if (st) SYNC_TO_TOKEN(st);
|
||||
|
||||
/* return an engine token */
|
||||
*et = &ati_engine_token;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t RELEASE_ENGINE(engine_token *et, sync_token *st) {
|
||||
/* update the sync token, if any */
|
||||
if (st) {
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = si->engine.count;
|
||||
}
|
||||
|
||||
/* release the shared benaphore */
|
||||
RELEASE_BEN(si->engine.lock)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void WAIT_ENGINE_IDLE(void) {
|
||||
|
||||
// Wait until engine finishes
|
||||
WaitIdleEmpty();
|
||||
// note our current possition
|
||||
si->engine.last_idle = si->engine.count;
|
||||
}
|
||||
|
||||
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st) {
|
||||
st->engine_id = et->engine_id;
|
||||
st->counter = si->engine.count;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t SYNC_TO_TOKEN(sync_token *st) {
|
||||
|
||||
uint64 fifo_diff;
|
||||
uint64 fifo_limit;
|
||||
|
||||
/* a quick out */
|
||||
if (st->counter < si->engine.last_idle) return B_OK;
|
||||
|
||||
/* the full monty */
|
||||
fifo_limit = si->engine.fifo_limit;
|
||||
/* fifo_mask = si->fifo_mask;*/
|
||||
do {
|
||||
/* calculate the age of the sync token */
|
||||
fifo_diff = (vuint64)(si->engine.count) - st->counter;
|
||||
/* add in the number of free slots in the fifo */
|
||||
fifo_diff += (uint64)((inw(GUI_STAT) >> 16) & 0x003f);
|
||||
/*
|
||||
The astute observer will notice that the free slot counter
|
||||
doesn't have enough bits to represent the full FIFO depth.
|
||||
This means that for "recent" operations, we end up waiting
|
||||
on engine idle :-(
|
||||
*/
|
||||
#if 1
|
||||
/* add one if the engine is idle (for when st->counter == si->engine.count) */
|
||||
if (!(inw(GUI_STAT) & 0x01)) fifo_diff++;
|
||||
#endif
|
||||
/* anything more than fifo_limit fifo slots ago is guaranteed done */
|
||||
/* if the engine is idle, bail out */
|
||||
} while ((fifo_diff <= fifo_limit) && (inw(GUI_STAT) & 0x01));
|
||||
|
||||
/* WAIT_ENGINE_IDLE(); */
|
||||
|
||||
si->engine.last_idle = st->counter;
|
||||
return B_OK;
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
#include "generic.h"
|
||||
|
||||
/*
|
||||
|
||||
The standard entry point. Given a uint32 feature identifier, this routine
|
||||
returns a pointer to the function that implements the feature. Some features
|
||||
require more information than just the identifier to select the proper
|
||||
function. The extra information (which is specific to the feature) is
|
||||
pointed at by the void *data parameter. By default, no extra information
|
||||
is available. Any extra information available to choose the function will be
|
||||
noted on a case by case below.
|
||||
|
||||
*/
|
||||
void * get_accelerant_hook(uint32 feature, void *data) {
|
||||
switch (feature) {
|
||||
/*
|
||||
These definitions are out of pure lazyness.
|
||||
*/
|
||||
#define HOOK(x) case B_##x: return (void *)x
|
||||
#define ZERO(x) case B_##x: return (void *)0
|
||||
|
||||
/*
|
||||
One of either B_INIT_ACCELERANT or B_CLONE_ACCELERANT will be requested and
|
||||
subsequently called before any other hook is requested. All other feature
|
||||
hook selections can be predicated on variables assigned during the accelerant
|
||||
initialization process.
|
||||
*/
|
||||
/* initialization */
|
||||
HOOK(INIT_ACCELERANT);
|
||||
HOOK(CLONE_ACCELERANT);
|
||||
|
||||
HOOK(ACCELERANT_CLONE_INFO_SIZE);
|
||||
HOOK(GET_ACCELERANT_CLONE_INFO);
|
||||
HOOK(UNINIT_ACCELERANT);
|
||||
//HOOK(GET_ACCELERANT_DEVICE_INFO);
|
||||
HOOK(ACCELERANT_RETRACE_SEMAPHORE);
|
||||
|
||||
/* mode configuration */
|
||||
HOOK(ACCELERANT_MODE_COUNT);
|
||||
HOOK(GET_MODE_LIST);
|
||||
HOOK(PROPOSE_DISPLAY_MODE);
|
||||
HOOK(SET_DISPLAY_MODE);
|
||||
HOOK(GET_DISPLAY_MODE);
|
||||
HOOK(GET_FRAME_BUFFER_CONFIG);
|
||||
HOOK(GET_PIXEL_CLOCK_LIMITS);
|
||||
HOOK(MOVE_DISPLAY);
|
||||
HOOK(SET_INDEXED_COLORS);
|
||||
//HOOK(GET_TIMING_CONSTRAINTS);
|
||||
|
||||
HOOK(DPMS_CAPABILITIES);
|
||||
HOOK(DPMS_MODE);
|
||||
HOOK(SET_DPMS_MODE);
|
||||
|
||||
/* cursor managment */
|
||||
HOOK(SET_CURSOR_SHAPE);
|
||||
HOOK(MOVE_CURSOR);
|
||||
HOOK(SHOW_CURSOR);
|
||||
|
||||
/* synchronization */
|
||||
HOOK(ACCELERANT_ENGINE_COUNT);
|
||||
HOOK(ACQUIRE_ENGINE);
|
||||
HOOK(RELEASE_ENGINE);
|
||||
HOOK(WAIT_ENGINE_IDLE);
|
||||
HOOK(GET_SYNC_TOKEN);
|
||||
HOOK(SYNC_TO_TOKEN);
|
||||
|
||||
/*
|
||||
When requesting an acceleration hook, the calling application provides a
|
||||
pointer to the display_mode for which the acceleration function will be used.
|
||||
Depending on the engine architecture, you may choose to provide a different
|
||||
function to be used with each bit-depth. In the sample driver we return
|
||||
the same function all the time.
|
||||
*/
|
||||
/* 2D acceleration */
|
||||
HOOK(SCREEN_TO_SCREEN_BLIT);
|
||||
HOOK(FILL_RECTANGLE);
|
||||
HOOK(INVERT_RECTANGLE);
|
||||
HOOK(FILL_SPAN);
|
||||
#undef HOOK
|
||||
#undef ZERO
|
||||
}
|
||||
/*
|
||||
Return a null pointer for any feature we don't understand.
|
||||
*/
|
||||
return 0;
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
extern uint32 calcBitsPerPixel(uint32 cs);
|
||||
|
||||
/*
|
||||
Return the current display mode. The only time you might return an
|
||||
error is if a mode hasn't been set.
|
||||
*/
|
||||
status_t GET_DISPLAY_MODE(display_mode *current_mode) {
|
||||
/* easy for us, we return the last mode we set */
|
||||
*current_mode = si->dm;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the frame buffer configuration information.
|
||||
*/
|
||||
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *afb) {
|
||||
/* easy again, as the last mode set stored the info in a convienient form */
|
||||
*afb = si->fbc;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the maximum and minium pixel clock limits for the specified mode.
|
||||
*/
|
||||
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high) {
|
||||
/*
|
||||
Note that we're not making any guarantees about the ability of the attached
|
||||
display to handle pixel clocks within the limits we return. A future monitor
|
||||
capablilities database will post-process this information.
|
||||
*/
|
||||
uint32 total_pix = (uint32)dm->timing.h_total * (uint32)dm->timing.v_total;
|
||||
uint32 clock_limit;
|
||||
float i;
|
||||
|
||||
/* max pixel clock is pixel depth dependant */
|
||||
switch (calcBitsPerPixel(dm->space)) {
|
||||
case 32: clock_limit = si->pix_clk_max32; break;
|
||||
case 15:
|
||||
case 16: clock_limit = si->pix_clk_max16; break;
|
||||
case 8: clock_limit = si->pix_clk_max8; break;
|
||||
default:
|
||||
clock_limit = 0;
|
||||
}
|
||||
/* printf("low %d, high %d %d \n", *low, clock_limit, si->pix_clk_max8);*/
|
||||
/* lower limit of about 48Hz vertical refresh */
|
||||
*low = (total_pix * 48L) / 1000L;
|
||||
i = (total_pix * 48L) / 1000L;
|
||||
|
||||
/* printf("low %d, high %d %08X \n", *low, clock_limit, dm->space);*/
|
||||
|
||||
if (*low > clock_limit) return B_ERROR;
|
||||
*high = clock_limit;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the semaphore id that will be used to signal a vertical retrace
|
||||
occured.
|
||||
*/
|
||||
sem_id ACCELERANT_RETRACE_SEMAPHORE(void) {
|
||||
/*
|
||||
NOTE:
|
||||
The kernel driver created this for us. We don't know if the system is
|
||||
using real interrupts, or if we're faking it, and we don't care.
|
||||
If we choose not to support this at all, we'd just return B_ERROR here,
|
||||
and the user wouldn't get any kind of vertical retrace support.
|
||||
*/
|
||||
/* return si->vblank;*/
|
||||
return B_ERROR;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#include "GlobalData.h"
|
||||
|
||||
int fd;
|
||||
shared_info *si;
|
||||
area_id shared_info_area;
|
||||
vuint32 *regs;
|
||||
area_id regs_area;
|
||||
display_mode *atimach64_mode_list;
|
||||
area_id atimach64_mode_list_area;
|
||||
int accelerantIsClone;
|
|
@ -1,16 +0,0 @@
|
|||
#if !defined(GLOBALDATA_H)
|
||||
#define GLOBALDATA_H
|
||||
|
||||
#include "DriverInterface.h"
|
||||
#include "regmach64.h"
|
||||
|
||||
extern int fd;
|
||||
extern shared_info *si;
|
||||
extern area_id shared_info_area;
|
||||
extern vuint32 *regs;
|
||||
extern area_id regs_area;
|
||||
extern display_mode *atimach64_mode_list;
|
||||
extern area_id atimach64_mode_list_area;
|
||||
extern int accelerantIsClone;
|
||||
|
||||
#endif
|
|
@ -1,373 +0,0 @@
|
|||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "Mach64.h"
|
||||
|
||||
#include "string.h"
|
||||
#include "unistd.h"
|
||||
#include "sys/types.h"
|
||||
#include "sys/stat.h"
|
||||
#include "fcntl.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include "stdio.h"
|
||||
|
||||
/* defined in ProposeDisplayMode.c */
|
||||
extern status_t create_mode_list(void);
|
||||
/* defined in Cursor.c */
|
||||
extern void set_cursor_colors(void);
|
||||
|
||||
// Determines the amount of card memory available by seeing how far up the frame buffer
|
||||
// data can be written and read back reliably. Does a paranoia check to make sure that
|
||||
// It isn't just wrapping, either.
|
||||
unsigned long Get_Card_Mem_Size()
|
||||
{
|
||||
// Allowed sizes actually go up to 16 megs, but clip at the register window for now.
|
||||
const unsigned long AllowedSizes[] =
|
||||
{ 0x00080000, 0x00100000, 0x00180000, 0x00200000,
|
||||
0x00280000, 0x00300000, 0x00380000, 0x00400000,
|
||||
0x00500000, 0x00600000, 0x00700000, 0x007FF800,
|
||||
0x0 };
|
||||
|
||||
unsigned long MaxMem;
|
||||
unsigned long RWIndex;
|
||||
int iMaxIndex, iTestIndex, iX;
|
||||
unsigned long LTemp;
|
||||
int IsOk;
|
||||
uint32 *VramBase;
|
||||
|
||||
VramBase = (uint32 *)si->framebuffer;
|
||||
MaxMem = 0; // Default.
|
||||
IsOk = 1;
|
||||
// Step through ever-larger memory sizes, recording size if passes test and
|
||||
// ignoring otherwise.
|
||||
for (iMaxIndex = 0; (AllowedSizes[iMaxIndex] != 0) && IsOk; iMaxIndex++)
|
||||
{
|
||||
// Write test values to the linear aperature.
|
||||
// Only need to do this for the farthest location, as previous locations
|
||||
// already have been written to in previous passes.
|
||||
RWIndex = AllowedSizes[iMaxIndex];
|
||||
RWIndex = (RWIndex - 16384) >> 2;
|
||||
for (iX = 0; iX < 4096; iX++)
|
||||
{
|
||||
LTemp = RWIndex;
|
||||
// Hash LTemp. As the parameters for the hash are prime, it should
|
||||
// be extremely unlikely to get these values through a glitch, and
|
||||
// the pattern only repeats at prime intervals, so aliasing shouldn't
|
||||
// fool the test either.
|
||||
LTemp = (263 * (LTemp % 65521) + 29) % 65521;
|
||||
// Extend this to 32 bits.
|
||||
LTemp |= (LTemp ^ 0x0000FFFFul) << 16;
|
||||
VramBase[RWIndex] = LTemp;
|
||||
RWIndex++;
|
||||
}
|
||||
|
||||
// Verify that all test patterns are still intact. If values written past the
|
||||
// end of memory drop off the face of the frame buffer, the farthest pattern(s)
|
||||
// will not be what they should be. If values written past the end of memory
|
||||
// wrap, then previous patterns will be overwritten (or partly overwritten,
|
||||
// as the test location at 8 megs is actually at 8 megs - 2k).
|
||||
// As soon as an invalid value is detected, IsOk is set to 0, which should
|
||||
// quickly terminate the test loops.
|
||||
for (iTestIndex = 0; (iTestIndex <= iMaxIndex) && IsOk; iTestIndex++)
|
||||
{
|
||||
RWIndex = AllowedSizes[iTestIndex];
|
||||
RWIndex = (RWIndex - 16384) >> 2;
|
||||
for (iX = 0; (iX < 4096) && IsOk; iX++)
|
||||
{
|
||||
LTemp = RWIndex;
|
||||
// Hash LTemp. As the parameters for the hash are prime, it should
|
||||
// be extremely unlikely to get these values through a glitch, and
|
||||
// the pattern only repeats at prime intervals, so aliasing shouldn't
|
||||
// fool the test either.
|
||||
LTemp = (263 * (LTemp % 65521) + 29) % 65521;
|
||||
// Extend this to 32 bits.
|
||||
LTemp |= (LTemp ^ 0x0000FFFFul) << 16;
|
||||
// Test against the value read from the frame buffer.
|
||||
if (VramBase[RWIndex] != LTemp)
|
||||
IsOk = 0;
|
||||
RWIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// If the test patterns check out, update MaxMem accordingly.
|
||||
if (IsOk)
|
||||
MaxMem = AllowedSizes[iMaxIndex];
|
||||
}
|
||||
return MaxMem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static status_t init_common(int the_fd);
|
||||
|
||||
/* Initialization code shared between primary and cloned accelerants */
|
||||
static status_t init_common(int the_fd) {
|
||||
status_t result;
|
||||
atimach64_get_private_data gpd;
|
||||
|
||||
/* memorize the file descriptor */
|
||||
fd = the_fd;
|
||||
/* set the magic number so the driver knows we're for real */
|
||||
gpd.magic = ATIMACH64_PRIVATE_DATA_MAGIC;
|
||||
/* contact driver and get a pointer to the registers and shared data */
|
||||
result = ioctl(fd, ATIMACH64_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
|
||||
|
||||
if (result != B_OK) goto error0;
|
||||
|
||||
/* clone the shared area for our use */
|
||||
shared_info_area = clone_area("ATIMACH64 shared info", (void **)&si, B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area);
|
||||
if (shared_info_area < 0) {
|
||||
result = shared_info_area;
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* all done */
|
||||
goto error0;
|
||||
|
||||
error0:
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Clean up code shared between primary and cloned accelrants */
|
||||
static void uninit_common(void) {
|
||||
/* release the memory mapped registers */
|
||||
/* delete_area(regs_area); */
|
||||
/* a little cheap paranoia */
|
||||
regs = 0;
|
||||
/* release our copy of the shared info from the kernel driver */
|
||||
delete_area(shared_info_area);
|
||||
/* more cheap paranoia */
|
||||
si = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize the accelerant. the_fd is the file handle of the device (in
|
||||
/dev/graphics) that has been opened by the app_server (or some test harness).
|
||||
We need to determine if the kernel driver and the accelerant are compatible.
|
||||
If they are, get the accelerant ready to handle other hook functions and
|
||||
report success or failure.
|
||||
*/
|
||||
status_t INIT_ACCELERANT(int the_fd) {
|
||||
status_t result;
|
||||
|
||||
/* note that we're the primary accelerant (accelerantIsClone is global) */
|
||||
accelerantIsClone = 0;
|
||||
|
||||
/* do the initialization common to both the primary and the clones */
|
||||
result = init_common(the_fd);
|
||||
|
||||
/* bail out if the common initialization failed */
|
||||
if (result != B_OK) goto error0;
|
||||
|
||||
/*
|
||||
If there is a possiblity that the kernel driver will recognize a card that
|
||||
the accelerant can't support, you should check for that here. Perhaps some
|
||||
odd memory configuration or some such.
|
||||
*/
|
||||
|
||||
/*
|
||||
This is a good place to go and initialize your card. The details are so
|
||||
device specific, we're not even going to pretend to provide you with sample
|
||||
code. If this fails, we'll have to bail out, cleaning up the resources
|
||||
we've already allocated.
|
||||
*/
|
||||
/* call the device specific init code */
|
||||
if (si->mem_size != Get_Card_Mem_Size()){
|
||||
result = B_ERROR;
|
||||
}
|
||||
|
||||
mach64InitAperture();
|
||||
mach64ResetEngine();
|
||||
WaitIdleEmpty();
|
||||
|
||||
/* Disable all interrupts */
|
||||
outw(CRTC_INT_CNTL, 0);
|
||||
|
||||
WaitIdleEmpty();
|
||||
|
||||
/* bail out if it failed */
|
||||
if (result != B_OK) goto error1;
|
||||
|
||||
/*
|
||||
Now would be a good time to figure out what video modes your card supports.
|
||||
We'll place the list of modes in another shared area so all of the copies
|
||||
of the driver can see them. The primary copy of the accelerant (ie the one
|
||||
initialized with this routine) will own the "one true copy" of the list.
|
||||
Everybody else get's a read-only clone.
|
||||
*/
|
||||
|
||||
result = create_mode_list();
|
||||
if (result != B_OK) goto error2;
|
||||
|
||||
/*
|
||||
Initialize the frame buffer and cursor pointers. Most newer video cards
|
||||
have integrated the DAC into the graphics engine, and so the cursor shape
|
||||
is stored in the frame buffer RAM. Also, newer cards tend not to have as
|
||||
many restrictions about the placement of the start of the frame buffer in
|
||||
frame buffer RAM. If you're supporting an older card with frame buffer
|
||||
positioning restrictions, or one without an integrated DAC, you'll have to
|
||||
change this accordingly.
|
||||
*/
|
||||
|
||||
/*
|
||||
Put the cursor at the start of the frame buffer. The typical 64x64 4 color
|
||||
(black, white, transparent, inverse) takes up 1024 bytes of RAM.
|
||||
*/
|
||||
si->cursor.data = (uint8 *)si->framebuffer;
|
||||
|
||||
/* Initialize cursor as transparent */
|
||||
memset(si->cursor.data, 0xaa, 1024);
|
||||
|
||||
/* Initialize the rest of the cursor information while we're here */
|
||||
si->cursor.width = 0;
|
||||
si->cursor.height = 0;
|
||||
si->cursor.hot_x = 0;
|
||||
si->cursor.hot_y = 0;
|
||||
si->cursor.x = 0;
|
||||
si->cursor.y = 0;
|
||||
|
||||
/* Tell the hardware all the cursor info */
|
||||
|
||||
outw(CUR_OFFSET, 0x00000000); /* Where it is in memory */
|
||||
outw(CUR_HORZ_VERT_POSN, 0x00000000); /* Position in screen */
|
||||
outw(CUR_HORZ_VERT_OFF, 0x00000000); /* Hot x,y */
|
||||
|
||||
/*
|
||||
Put the frame buffer immediately following the cursor data. We store this
|
||||
info in a frame_buffer_config structure to make it convienient to return
|
||||
to the app_server later.
|
||||
*/
|
||||
si->fbc.frame_buffer = (void *)(((char *)si->framebuffer) + 1024);
|
||||
si->fbc.frame_buffer_dma = (void *)(((char *)si->framebuffer_pci) + 1024);
|
||||
|
||||
/* init the shared semaphore */
|
||||
INIT_BEN(si->engine.lock);
|
||||
/* initialize the engine synchronization variables */
|
||||
|
||||
/* count of issued parameters or commands */
|
||||
si->engine.last_idle = si->engine.count = 0;
|
||||
|
||||
/* bail out if something failed */
|
||||
if (result != B_OK) goto error3;
|
||||
|
||||
/* set the cursor colors. You may or may not have to do this, depending
|
||||
on the device. */
|
||||
set_cursor_colors();
|
||||
|
||||
/* ensure cursor state */
|
||||
SHOW_CURSOR(false);
|
||||
/* a winner! */
|
||||
result = B_OK;
|
||||
goto error0;
|
||||
|
||||
error3:
|
||||
/* free up the benaphore */
|
||||
DELETE_BEN(si->engine.lock);
|
||||
|
||||
error2:
|
||||
/*
|
||||
Clean up any resources allocated in your device specific initialization
|
||||
code.
|
||||
*/
|
||||
|
||||
error1:
|
||||
/*
|
||||
Initialization failed after init_common() succeeded, so we need to clean
|
||||
up before quiting.
|
||||
*/
|
||||
uninit_common();
|
||||
|
||||
error0:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Return the number of bytes required to hold the information required
|
||||
to clone the device.
|
||||
*/
|
||||
ssize_t ACCELERANT_CLONE_INFO_SIZE(void) {
|
||||
/*
|
||||
Since we're passing the name of the device as the only required
|
||||
info, return the size of the name buffer
|
||||
*/
|
||||
return MAX_ATIMACH64_DEVICE_NAME_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Return the info required to clone the device. void *data points to
|
||||
a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
|
||||
*/
|
||||
void GET_ACCELERANT_CLONE_INFO(void *data) {
|
||||
atimach64_device_name dn;
|
||||
status_t result;
|
||||
|
||||
/* call the kernel driver to get the device name */
|
||||
dn.magic = ATIMACH64_PRIVATE_DATA_MAGIC;
|
||||
/* store the returned info directly into the passed buffer */
|
||||
dn.name = (char *)data;
|
||||
result = ioctl(fd, ATIMACH64_DEVICE_NAME, &dn, sizeof(dn));
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize a copy of the accelerant as a clone. void *data points to
|
||||
a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
|
||||
*/
|
||||
status_t CLONE_ACCELERANT(void *data) {
|
||||
status_t result;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
/* the data is the device name */
|
||||
strcpy(path, "/dev/");
|
||||
strcat(path, (const char *)data);
|
||||
/* open the device, the permissions aren't important */
|
||||
fd = open(path, B_READ_WRITE);
|
||||
if (fd < 0) {
|
||||
result = errno;
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* note that we're a clone accelerant */
|
||||
accelerantIsClone = 1;
|
||||
|
||||
/* call the shared initialization code */
|
||||
result = init_common(fd);
|
||||
|
||||
/* bail out if the common initialization failed */
|
||||
if (result != B_OK) goto error1;
|
||||
|
||||
/* get shared area for display modes */
|
||||
result = atimach64_mode_list_area = clone_area(
|
||||
"ATIMACH64 cloned display_modes",
|
||||
(void **)&atimach64_mode_list,
|
||||
B_ANY_ADDRESS,
|
||||
B_READ_AREA,
|
||||
si->mode_area
|
||||
);
|
||||
if (result < B_OK) goto error2;
|
||||
|
||||
/* all done */
|
||||
result = B_OK;
|
||||
goto error0;
|
||||
|
||||
error2:
|
||||
/* free up the areas we cloned */
|
||||
uninit_common();
|
||||
error1:
|
||||
/* close the device we opened */
|
||||
close(fd);
|
||||
error0:
|
||||
return result;
|
||||
}
|
||||
|
||||
void UNINIT_ACCELERANT(void) {
|
||||
/* free our mode list area */
|
||||
delete_area(atimach64_mode_list_area);
|
||||
/* paranoia */
|
||||
atimach64_mode_list = 0;
|
||||
/* release our cloned data */
|
||||
uninit_common();
|
||||
/* close the file handle ONLY if we're the clone */
|
||||
if (accelerantIsClone) close(fd);
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
SubDir HAIKU_TOP src add-ons accelerants atimach64 ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics atimach64 ] ;
|
||||
|
||||
Addon atimach64.accelerant :
|
||||
Acceleration.c
|
||||
Cursor.c
|
||||
EngineManagment.c
|
||||
GetAccelerantHook.c
|
||||
GlobalData.c
|
||||
GetModeInfo.c
|
||||
InitAccelerant.c
|
||||
Mach64.c
|
||||
Mach64fifo.c
|
||||
ProposeDisplayMode.c
|
||||
SetDisplayMode.c
|
||||
;
|
||||
|
||||
Depends atimach64.accelerant : atimach64.driver ;
|
||||
|
|
@ -1,447 +0,0 @@
|
|||
/* All this code has been reversed engineered from Xfree86 Project :-)
|
||||
|
||||
Copyright 1999 by
|
||||
|
||||
Rene MacKinney <rene_@freenet.co.uk>
|
||||
|
||||
7.May.99
|
||||
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/* $XFree86: xc/programs/Xserver/hw/xfree86/accel/mach64/mach64.c,v 3.62.2.15 19
|
||||
98/10/18 20:42:04 hohndel Exp $ */
|
||||
/*
|
||||
* Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
|
||||
* Copyright 1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Car
|
||||
olina.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Thomas Roell not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Thomas Roell makes no representations
|
||||
* about the suitability of this software for any purpose. It is provided
|
||||
* "as is" without express or implied warranty.
|
||||
*
|
||||
* THOMAS ROELL, KEVIN E. MARTIN, AND RICKARD E. FAITH DISCLAIM ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE AUTHORS
|
||||
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Thomas Roell, roell@informatik.tu-muenchen.de
|
||||
*
|
||||
* Rewritten for the 8514/A by Kevin E. Martin (martin@cs.unc.edu)
|
||||
* Modified for the Mach-8 by Rickard E. Faith (faith@cs.unc.edu)
|
||||
* Rewritten for the Mach32 by Kevin E. Martin (martin@cs.unc.edu)
|
||||
* Rewritten for the Mach64 by Kevin E. Martin (martin@cs.unc.edu)
|
||||
* Support for the Mach64 CT added by David Dawes (dawes@XFree86.org)
|
||||
*
|
||||
*/
|
||||
/* $XConsortium: mach64.c /main/34 1996/10/28 04:46:47 kaleb $ */
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "Mach64fifo.h"
|
||||
#include "Mach64.h"
|
||||
|
||||
|
||||
/*
|
||||
* mach64FIFOdepth --
|
||||
* Calculates the correct FIFO depth for the Mach64 depending on the
|
||||
* color depth and clock selected.
|
||||
*/
|
||||
int mach64FIFOdepth(cdepth, clock, width)
|
||||
int cdepth;
|
||||
int clock;
|
||||
int width;
|
||||
{
|
||||
int fifo_depth;
|
||||
|
||||
if (si->device_id == MACH64_VT_ID) {
|
||||
if (si->revision == 0x48) { /* VTA4 */
|
||||
fifo_depth = mach64FIFOdepthVTA4(cdepth, clock, width);
|
||||
} else { /* VTA3 */
|
||||
fifo_depth = mach64FIFOdepthVTA3(cdepth, clock, width);
|
||||
}
|
||||
} else if (si->device_id == MACH64_GT_ID) {
|
||||
fifo_depth = mach64FIFOdepthGT(cdepth, clock, width);
|
||||
} else if (si->device_id == MACH64_CT_ID && si->revision == 0x0a) {
|
||||
/* CT-D has a larger FIFO and thus requires special code */
|
||||
fifo_depth = mach64FIFOdepthCTD(cdepth, clock, width);
|
||||
} else if (si->device_id == MACH64_CT_ID ||
|
||||
si->device_id == MACH64_ET_ID) {
|
||||
fifo_depth = mach64FIFOdepthCT(cdepth, clock, width);
|
||||
} else {
|
||||
fifo_depth = mach64FIFOdepthDefault(cdepth, clock, width);
|
||||
}
|
||||
|
||||
return(fifo_depth);
|
||||
}
|
||||
|
||||
/*
|
||||
* mach64ProgramClkMach64CT --
|
||||
*
|
||||
*/
|
||||
void mach64ProgramClkMach64CT(clkCntl, MHz100)
|
||||
int clkCntl;
|
||||
int MHz100;
|
||||
{
|
||||
char old_crtc_ext_disp;
|
||||
#ifdef DEBUG
|
||||
extern void mach64PrintCTPLL();
|
||||
#endif
|
||||
int M, N, P, R;
|
||||
float Q;
|
||||
int postDiv;
|
||||
int mhz100 = MHz100;
|
||||
unsigned char tmp1, tmp2;
|
||||
int ext_div = 0;
|
||||
float current_dot_clock;
|
||||
|
||||
old_crtc_ext_disp = inb(CRTC_GEN_CNTL+3);
|
||||
outb(CRTC_GEN_CNTL+3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24));
|
||||
|
||||
M = si->RefDivider;
|
||||
R = si->RefFreq;
|
||||
|
||||
if (clkCntl > 3) clkCntl = 3;
|
||||
|
||||
if (mhz100 < si->MinFreq) mhz100 = si->MinFreq;
|
||||
if (mhz100 > si->MaxFreq) mhz100 = si->MaxFreq;
|
||||
|
||||
Q = (mhz100 * M)/(2.0 * R);
|
||||
|
||||
if (false) { /* mach64HasDSP) { */
|
||||
if (Q > 255) {
|
||||
/* printf("mach64ProgramClkMach64CT: Warning: Q > 255\n");*/
|
||||
Q = 255;
|
||||
P = 0;
|
||||
postDiv = 1;
|
||||
} else if (Q > 127.5) {
|
||||
P = 0;
|
||||
postDiv = 1;
|
||||
} else if (Q > 85) {
|
||||
P = 1;
|
||||
postDiv = 2;
|
||||
} else if (Q > 63.75) {
|
||||
P = 0;
|
||||
postDiv = 3;
|
||||
ext_div = 1;
|
||||
} else if (Q > 42.5) {
|
||||
P = 2;
|
||||
postDiv = 4;
|
||||
} else if (Q > 31.875) {
|
||||
P = 2;
|
||||
postDiv = 6;
|
||||
ext_div = 1;
|
||||
} else if (Q > 21.25) {
|
||||
P = 3;
|
||||
postDiv = 8;
|
||||
} else if (Q >= 10.6666666667) {
|
||||
P = 3;
|
||||
postDiv = 12;
|
||||
ext_div = 1;
|
||||
} else {
|
||||
/* printf("mach64ProgramClkMach64CT: Warning: Q < 10.66666667\n");*/
|
||||
P = 3;
|
||||
postDiv = 12;
|
||||
ext_div = 1;
|
||||
}
|
||||
} else {
|
||||
if (Q > 255) {
|
||||
/* printf("mach64ProgramClkMach64CT: Warning: Q > 255\n");*/
|
||||
Q = 255;
|
||||
P = 0;
|
||||
}
|
||||
else if (Q > 127.5)
|
||||
P = 0;
|
||||
else if (Q > 63.75)
|
||||
P = 1;
|
||||
else if (Q > 31.875)
|
||||
P = 2;
|
||||
else if (Q >= 16)
|
||||
P = 3;
|
||||
else {
|
||||
/* printf("mach64ProgramClkMach64CT: Warning: Q < 16\n");*/
|
||||
P = 3;
|
||||
}
|
||||
postDiv = 1 << P;
|
||||
}
|
||||
N = (int)(Q * postDiv + 0.5);
|
||||
|
||||
current_dot_clock = (2.0 * R * N)/(M * postDiv);
|
||||
|
||||
#ifdef DEBUG_HARNESS
|
||||
printf("Q = %f N = %d P = %d, postDiv = %d R = %d M = %d\n", Q, N, P, postDiv, R, M);
|
||||
printf("New freq: %.2f\n", (double)((2 * R * N)/(M * postDiv)) / 100.0);
|
||||
#endif
|
||||
|
||||
outb(CLOCK_CNTL + 1, PLL_VCLK_CNTL << 2);
|
||||
#ifdef DEBUG_HARNESS
|
||||
printf("CLOCK_CNTL + 1 = 0x%08x\n",PLL_VCLK_CNTL << 2);
|
||||
#endif
|
||||
tmp1 = inb(CLOCK_CNTL + 2);
|
||||
outb(CLOCK_CNTL + 1, (PLL_VCLK_CNTL << 2) | PLL_WR_EN);
|
||||
outb(CLOCK_CNTL + 2, tmp1 | 0x04);
|
||||
outb(CLOCK_CNTL + 1, VCLK_POST_DIV << 2);
|
||||
tmp2 = inb(CLOCK_CNTL + 2);
|
||||
outb(CLOCK_CNTL + 1, ((VCLK0_FB_DIV + clkCntl) << 2) | PLL_WR_EN);
|
||||
outb(CLOCK_CNTL + 2, N);
|
||||
outb(CLOCK_CNTL + 1, (VCLK_POST_DIV << 2) | PLL_WR_EN);
|
||||
outb(CLOCK_CNTL + 2,
|
||||
(tmp2 & ~(0x03 << (2 * clkCntl))) | (P << (2 * clkCntl)));
|
||||
outb(CLOCK_CNTL + 1, (PLL_VCLK_CNTL << 2) | PLL_WR_EN);
|
||||
outb(CLOCK_CNTL + 2, tmp1 & ~0x04);
|
||||
|
||||
if (false) { /* mach64HasDSP) { */
|
||||
outb(CLOCK_CNTL + 1, PLL_XCLK_CNTL << 2);
|
||||
tmp1 = inb(CLOCK_CNTL + 2);
|
||||
outb(CLOCK_CNTL + 1, (PLL_XCLK_CNTL << 2) | PLL_WR_EN);
|
||||
if (ext_div)
|
||||
outb(CLOCK_CNTL + 2, tmp1 | (1 << (clkCntl + 4)));
|
||||
else
|
||||
outb(CLOCK_CNTL + 2, tmp1 & ~(1 << (clkCntl + 4)));
|
||||
}
|
||||
|
||||
snooze(5000);
|
||||
|
||||
(void)inb(DAC_REGS); /* Clear DAC Counter */
|
||||
outb(CRTC_GEN_CNTL+3, old_crtc_ext_disp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* CalcCRTCRegs --
|
||||
* Calculate appropiate values for CRTC Registers
|
||||
*/
|
||||
void
|
||||
CalcCRTCRegs(crtcRegs, mode)
|
||||
mach64CRTCRegPtr crtcRegs;
|
||||
display_mode *mode;
|
||||
{
|
||||
int h_pol = (mode->timing.flags & B_POSITIVE_HSYNC) ? 1 : 0;
|
||||
int v_pol = (mode->timing.flags & B_POSITIVE_VSYNC) ? 1 : 0;
|
||||
|
||||
/* Register CRTC_H_TOTAL_DISP
|
||||
bits 23-16 Horizontal total visible in character clocks (8 pixel units)
|
||||
bits 7-0 Horizontal display end in character clocks
|
||||
*/
|
||||
crtcRegs->h_total_disp = (((mode->timing.h_display >> 3) - 1) << 16) |
|
||||
((mode->timing.h_total >> 3) - 1);
|
||||
|
||||
/* Register CRTC_H_SYNC_STRT_WID
|
||||
bits 21 Horizontal sync polarity
|
||||
bits 20-16 Horizontal sync width in character clocks
|
||||
bits 10-8 Horizontal sync start delay in pixels
|
||||
bits 7-0 Horizontal sync start in character clocks
|
||||
*/
|
||||
crtcRegs->h_sync_strt_wid = h_pol << 21 |
|
||||
(((mode->timing.h_sync_end - mode->timing.h_sync_start) >> 3) << 16) |
|
||||
/* ((mode->timing.h_sync_start % 8) << 8) |*/
|
||||
((mode->timing.h_sync_start >> 3) - 1);
|
||||
|
||||
/* Register CRTC_V_TOTAL_DISP
|
||||
bits 23-16 Vertical total visible in lines
|
||||
bits 7-0 Vertical display end in lines
|
||||
*/
|
||||
crtcRegs->v_total_disp = ((mode->timing.v_display - 1) << 16) |
|
||||
(mode->timing.v_total - 1);
|
||||
|
||||
/* Register CRTC_V_SYNC_STRT_WID
|
||||
bits 21 Vertical sync polarity
|
||||
bits 20-16 Vertical sync width in lines
|
||||
bits 10-0 Vertical sync start in lines
|
||||
*/
|
||||
crtcRegs->v_sync_strt_wid = v_pol << 21 |
|
||||
((mode->timing.v_sync_end - mode->timing.v_sync_start) << 16) |
|
||||
(mode->timing.v_sync_start - 1);
|
||||
|
||||
switch (mode->space & 0x0fff) {
|
||||
case B_CMAP8:
|
||||
crtcRegs->color_depth = CRTC_PIX_WIDTH_8BPP;
|
||||
break;
|
||||
case B_RGB15:
|
||||
crtcRegs->color_depth = CRTC_PIX_WIDTH_15BPP;
|
||||
break;
|
||||
case B_RGB16:
|
||||
crtcRegs->color_depth = CRTC_PIX_WIDTH_16BPP;
|
||||
break;
|
||||
case B_RGB32:
|
||||
crtcRegs->color_depth = CRTC_PIX_WIDTH_32BPP;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
crtcRegs->crtc_gen_cntl = 0;
|
||||
if (mode->timing.flags & B_TIMING_INTERLACED)
|
||||
crtcRegs->crtc_gen_cntl |= CRTC_INTERLACE_EN;
|
||||
|
||||
|
||||
crtcRegs->clock_cntl = 0x03; /* Hack */
|
||||
crtcRegs->dot_clock = mode->timing.pixel_clock / 10;
|
||||
|
||||
crtcRegs->fifo_v1 = mach64FIFOdepth(crtcRegs->color_depth,
|
||||
crtcRegs->dot_clock, mode->timing.h_display);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* SetCRTCRegs
|
||||
* Write values to the CRTC Registers */
|
||||
void
|
||||
SetCRTCRegs(crtcRegs, mode)
|
||||
mach64CRTCRegPtr crtcRegs;
|
||||
display_mode *mode;
|
||||
{
|
||||
int crtcGenCntl;
|
||||
uint32 offset;
|
||||
|
||||
WaitIdleEmpty();
|
||||
crtcGenCntl = inw(CRTC_GEN_CNTL);
|
||||
outw(CRTC_GEN_CNTL, crtcGenCntl & ~(CRTC_EXT_EN | CRTC_LOCK_REGS));
|
||||
|
||||
/* Program the clock chip */
|
||||
mach64ProgramClkMach64CT(0x03, crtcRegs->dot_clock);
|
||||
|
||||
|
||||
/* Horizontal CRTC registers */
|
||||
outw(CRTC_H_TOTAL_DISP, crtcRegs->h_total_disp);
|
||||
outw(CRTC_H_SYNC_STRT_WID, crtcRegs->h_sync_strt_wid);
|
||||
|
||||
/* Vertical CRTC registers */
|
||||
outw(CRTC_V_TOTAL_DISP, crtcRegs->v_total_disp);
|
||||
outw(CRTC_V_SYNC_STRT_WID, crtcRegs->v_sync_strt_wid);
|
||||
|
||||
/* Clock select register */
|
||||
outw(CLOCK_CNTL, crtcRegs->clock_cntl | CLOCK_STROBE);
|
||||
|
||||
/* Zero overscan register to insure proper color */
|
||||
/* outw(OVR_CLR, 0);
|
||||
outw(OVR_WID_LEFT_RIGHT, 0);
|
||||
outw(OVR_WID_TOP_BOTTOM, 0);
|
||||
*/
|
||||
/* Set the offset and width of the display
|
||||
We could just use the offset value we already know (1024) but this
|
||||
will deal with any changes
|
||||
*/
|
||||
offset = (si->fbc.frame_buffer - si->framebuffer) >> 3;
|
||||
|
||||
outw(CRTC_OFF_PITCH, ((mode->virtual_width >> 3) << 22) | offset);
|
||||
outw(DST_OFF_PITCH, ((mode->virtual_width >> 3) << 22) | offset);
|
||||
outw(SRC_OFF_PITCH, ((mode->virtual_width >> 3) << 22) | offset);
|
||||
|
||||
|
||||
|
||||
/* Display control register -- this one turns on the display */
|
||||
|
||||
outw(CRTC_GEN_CNTL,
|
||||
(crtcGenCntl & 0xff0000ff &
|
||||
~(CRTC_PIX_BY_2_EN | CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN |
|
||||
CRTC_HSYNC_DIS | CRTC_VSYNC_DIS)) |
|
||||
(crtcRegs->crtc_gen_cntl & ~CRTC_PIX_BY_2_EN) |
|
||||
crtcRegs->color_depth |
|
||||
(((crtcRegs->fifo_v1 & 0x0f) << 16) |
|
||||
CRTC_EXT_DISP_EN | CRTC_EXT_EN));
|
||||
|
||||
/* printf(" crtcGenCntl 0x%08x\n", (crtcGenCntl & 0xff0000ff &
|
||||
~(CRTC_PIX_BY_2_EN | CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN |
|
||||
CRTC_HSYNC_DIS | CRTC_VSYNC_DIS)) |
|
||||
(crtcRegs->crtc_gen_cntl & ~CRTC_PIX_BY_2_EN) |
|
||||
crtcRegs->color_depth |
|
||||
(((crtcRegs->fifo_v1 & 0x0f) << 16) |
|
||||
CRTC_EXT_DISP_EN | CRTC_EXT_EN));*/
|
||||
|
||||
|
||||
/* Set the DAC for the currect mode */
|
||||
/* mach64SetRamdac(crtcRegs->color_depth, TRUE, crtcRegs->dot_clock);
|
||||
*/
|
||||
WaitIdleEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* mach64InitAperture --
|
||||
* Initialize the aperture for the Mach64.
|
||||
*/
|
||||
void mach64InitAperture()
|
||||
{
|
||||
ulong apaddr = (ulong) si->framebuffer_pci;
|
||||
|
||||
outw(CONFIG_CNTL, ((apaddr/(4*1024*1024)) << 4) | 2);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* mach64ResetEngine --
|
||||
* Resets the GUI engine and clears any FIFO errors.
|
||||
*/
|
||||
void mach64ResetEngine()
|
||||
{
|
||||
int temp;
|
||||
|
||||
/* Ensure engine is not locked up by clearing any FIFO errors */
|
||||
outw(BUS_CNTL, inw(BUS_CNTL) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK);
|
||||
|
||||
/* Reset engine */
|
||||
temp = inw(GEN_TEST_CNTL);
|
||||
outw(GEN_TEST_CNTL, temp & ~GUI_ENGINE_ENABLE);
|
||||
|
||||
outw(GEN_TEST_CNTL, temp | GUI_ENGINE_ENABLE);
|
||||
|
||||
WaitIdleEmpty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
InitRAMDAC(uint32 colorDepth, uint32 flags)
|
||||
{
|
||||
int count;
|
||||
uint8 val;
|
||||
|
||||
WaitIdleEmpty();
|
||||
|
||||
/* Initialize Acceleration Mode */
|
||||
|
||||
outb(CRTC_GEN_CNTL+3, ((CRTC_EXT_DISP_EN | CRTC_EXT_EN) >> 24));
|
||||
|
||||
switch(colorDepth){
|
||||
case 8:
|
||||
val = inb(DAC_CNTL+1);
|
||||
if (flags & B_8_BIT_DAC)
|
||||
outb(DAC_CNTL + 1, val | 0x01);
|
||||
else
|
||||
outb(DAC_CNTL + 1, val & ~0x01);
|
||||
break;
|
||||
case 15:
|
||||
case 16:
|
||||
case 24:
|
||||
case 32:
|
||||
val = inb(DAC_CNTL + 1);
|
||||
outb(DAC_CNTL + 1, val | 0x01);
|
||||
outb(DAC_CNTL + 2, 0xff);
|
||||
outb(DAC_REGS, 0x00);
|
||||
for(count = 0; count < 256; count ++) {
|
||||
outb(DAC_REGS+1, count);
|
||||
outb(DAC_REGS+1, count);
|
||||
outb(DAC_REGS+1, count);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
extern void mach64InitAperture();
|
||||
extern void mach64ResetEngine();
|
||||
extern void CalcCRTCRegs(mach64CRTCRegPtr, display_mode *);
|
||||
extern void SetCRTCRegs(mach64CRTCRegPtr, display_mode *);
|
||||
void InitRAMDAC(uint32, uint32);
|
File diff suppressed because it is too large
Load Diff
|
@ -1,72 +0,0 @@
|
|||
/* $XConsortium: mach64fifo.h /main/1 1996/10/27 18:06:29 kaleb $ */
|
||||
/*
|
||||
* Copyright 1996 by Kevin E. Martin, Chapel Hill, North Carolina.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of Kevin
|
||||
* E. Martin not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Kevin E. Martin makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* KEVIN E. MARTIN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
/* $XFree86: xc/programs/Xserver/hw/xfree86/accel/mach64/mach64fifo.h,v 3.1 1996/12/27 06:55:52 dawes Exp $ */
|
||||
|
||||
extern int mach64FIFOdepthDefault(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthVTA3(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthVTA4(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthGT(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthCT(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
||||
|
||||
extern int mach64FIFOdepthCTD(
|
||||
#if NeedFunctionPrototypes
|
||||
int cdepth,
|
||||
int clock,
|
||||
int width
|
||||
#endif
|
||||
);
|
|
@ -1,399 +0,0 @@
|
|||
#include <GraphicsDefs.h>
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
|
||||
|
||||
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
|
||||
#define MODE_FLAGS (B_SCROLL | B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS)
|
||||
#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
|
||||
|
||||
static const display_mode mode_list[] = {
|
||||
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
|
||||
{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
|
||||
{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */
|
||||
{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
|
||||
{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
|
||||
{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
|
||||
{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
|
||||
{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
|
||||
{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
|
||||
{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */
|
||||
{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */
|
||||
{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */
|
||||
{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */
|
||||
{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
|
||||
{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
|
||||
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
|
||||
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
|
||||
{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
|
||||
{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
|
||||
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
|
||||
{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
|
||||
{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */
|
||||
{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */
|
||||
{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */
|
||||
{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */
|
||||
{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
|
||||
{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS} /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
|
||||
};
|
||||
|
||||
|
||||
/* create a mask of one "bits" bits wide */
|
||||
#define MASKFROMWIDTH(bits) ((1 << bits) - 1)
|
||||
|
||||
/*
|
||||
Validate a target display mode is both
|
||||
a) a valid display mode for this device and
|
||||
b) falls between the contraints imposed by "low" and "high"
|
||||
|
||||
If the mode is not (or cannot) be made valid for this device, return B_ERROR.
|
||||
If a valid mode can be constructed, but it does not fall within the limits,
|
||||
return B_BAD_VALUE.
|
||||
If the mode is both valid AND falls within the limits, return B_OK.
|
||||
*/
|
||||
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high) {
|
||||
|
||||
const uint16 h_display_bits = MASKFROMWIDTH(8);
|
||||
const uint16 h_sync_bits = MASKFROMWIDTH(5);
|
||||
const uint16 h_total_bits = MASKFROMWIDTH(9);
|
||||
const uint16 v_display_bits = MASKFROMWIDTH(11);
|
||||
const uint16 v_sync_bits = MASKFROMWIDTH(5);
|
||||
const uint16 v_total_bits = MASKFROMWIDTH(11);
|
||||
|
||||
int i, color_depth;
|
||||
|
||||
int mach64CDepths [] = { -1, 4, 8, 15, 16, 24, 32, -1 };
|
||||
|
||||
status_t
|
||||
result = B_ERROR;
|
||||
uint32
|
||||
row_bytes,
|
||||
limit_clock;
|
||||
double
|
||||
target_refresh = ((double)target->timing.pixel_clock * 1000.0) / ((double)target->timing.h_total * (double)target->timing.v_total);
|
||||
bool
|
||||
want_same_width = target->timing.h_display == target->virtual_width,
|
||||
want_same_height = target->timing.v_display == target->virtual_height;
|
||||
|
||||
/*
|
||||
NOTE:
|
||||
Different devices provide different levels of control over the various CRTC values.
|
||||
This code should be used as a *GUIDELINE ONLY*. The device you're controling may
|
||||
have very different constraints, and the code below may be insufficient to insure
|
||||
that a particular display_mode is valid for your device. You would do well to
|
||||
spend quite a bit of time ensuring that you understand the limitations of your
|
||||
device, as setting these values incorrectly can create a display_mode that could
|
||||
turn your monitor into a useless slag of molten components, burn up your card,
|
||||
lock up the PCI bus, cause partialy or multiply repeating display images, or
|
||||
otherwise look just plain wierd. Honest.
|
||||
*/
|
||||
/*
|
||||
NOTE:
|
||||
This code doesn't explicitly support interlaced video modes.
|
||||
*/
|
||||
|
||||
/* validate horizontal timings */
|
||||
{
|
||||
/* for most devices, horizontal parameters must be multiples of 8 */
|
||||
uint16 h_display = target->timing.h_display >> 3;
|
||||
uint16 h_sync_start = target->timing.h_sync_start >> 3;
|
||||
uint16 h_sync_end = target->timing.h_sync_end >> 3;
|
||||
uint16 h_total = target->timing.h_total >> 3;
|
||||
|
||||
/* ensure reasonable minium display and sequential order of parms */
|
||||
|
||||
if (h_display < (320 >> 3)) h_display = 320 >> 3;
|
||||
if (h_display > (2048 >> 3)) h_display = 2048 >> 3;
|
||||
if (h_sync_start < (h_display + 2)) h_sync_start = h_display + 2;
|
||||
if (h_sync_end < (h_sync_start + 3)) h_sync_end = h_sync_start + 3; /*(0x001f >> 2);*/
|
||||
|
||||
if (h_total < (h_sync_end + 1)) h_total = h_sync_end + 1;
|
||||
/* adjust for register limitations: */
|
||||
/* h_total is 9 bits */
|
||||
|
||||
if (h_total > h_total_bits) h_total = h_total_bits;
|
||||
/* h_display is 8 bits - handled above */
|
||||
/* h_sync_start is 9 bits */
|
||||
/* h_sync_width is 5 bits */
|
||||
if ((h_sync_end - h_sync_start) > h_sync_bits) h_sync_end = h_sync_start + h_sync_bits;
|
||||
|
||||
/* shift back to the full width values */
|
||||
|
||||
target->timing.h_display = h_display << 3;
|
||||
target->timing.h_sync_start = h_sync_start << 3;
|
||||
target->timing.h_sync_end = h_sync_end << 3;
|
||||
target->timing.h_total = h_total << 3;
|
||||
}
|
||||
|
||||
/* did we fall out of one of the limits? */
|
||||
|
||||
if (
|
||||
(target->timing.h_display < low->timing.h_display) ||
|
||||
(target->timing.h_display > high->timing.h_display) ||
|
||||
(target->timing.h_sync_start < low->timing.h_sync_start) ||
|
||||
(target->timing.h_sync_start > high->timing.h_sync_start) ||
|
||||
(target->timing.h_sync_end < low->timing.h_sync_end) ||
|
||||
(target->timing.h_sync_end > high->timing.h_sync_end) ||
|
||||
(target->timing.h_total < low->timing.h_total) ||
|
||||
(target->timing.h_total > high->timing.h_total)
|
||||
) result = B_BAD_VALUE;
|
||||
|
||||
|
||||
/* validate vertical timings */
|
||||
|
||||
{
|
||||
uint16 v_display = target->timing.v_display;
|
||||
uint16 v_sync_start = target->timing.v_sync_start;
|
||||
uint16 v_sync_end = target->timing.v_sync_end;
|
||||
uint16 v_total = target->timing.v_total;
|
||||
|
||||
/* ensure reasonable minium display and sequential order of parms */
|
||||
/* v_display is 11 bits */
|
||||
/* v_total is 11 bits */
|
||||
/* v_sync_start is 11 bits */
|
||||
/* v_sync_width is 5 bits */
|
||||
|
||||
if (v_display < 200) v_display = 200;
|
||||
if (v_display > (v_display_bits - 5)) v_display = (v_display_bits - 5); /* leave room for the sync pulse */
|
||||
if (v_sync_start < (v_display + 1)) v_sync_start = v_display + 1;
|
||||
if (v_sync_end < v_sync_start) v_sync_end = v_sync_start + 3;
|
||||
if (v_total < (v_sync_end + 1)) v_total = v_sync_end + 1;
|
||||
/* adjust for register limitations */
|
||||
|
||||
if ((v_sync_end - v_sync_start) > v_sync_bits) v_sync_end = v_sync_start + v_sync_bits;
|
||||
target->timing.v_display = v_display;
|
||||
target->timing.v_sync_start = v_sync_start;
|
||||
target->timing.v_sync_end = v_sync_end;
|
||||
target->timing.v_total = v_total;
|
||||
}
|
||||
|
||||
/* did we fall out of one of the limits? */
|
||||
|
||||
if (
|
||||
(target->timing.v_display < low->timing.v_display) ||
|
||||
(target->timing.v_display > high->timing.v_display) ||
|
||||
(target->timing.v_sync_start < low->timing.v_sync_start) ||
|
||||
(target->timing.v_sync_start > high->timing.h_sync_start) ||
|
||||
(target->timing.v_sync_end < low->timing.v_sync_end) ||
|
||||
(target->timing.v_sync_end > high->timing.v_sync_end) ||
|
||||
(target->timing.v_total < low->timing.v_total) ||
|
||||
(target->timing.v_total > high->timing.v_total)
|
||||
) result = B_BAD_VALUE;
|
||||
|
||||
/* adjust pixel clock for DAC limits and target refresh rate */
|
||||
/*
|
||||
We're re-calcuating the pixel_clock here because we might have
|
||||
changed the h/v totals above. If we didn't change anything
|
||||
the calculation is wasted, but it's no big deal.
|
||||
*/
|
||||
target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0 + .5;
|
||||
|
||||
/*
|
||||
Select the maximum pixel clock based on the color space. Your
|
||||
device may have other constraints. In this sample driver, we
|
||||
calculated the maximum pixel clock for this device in the
|
||||
initialization code.
|
||||
This is also a convienient place to determine the number of bytes
|
||||
per pixel for a later display pitch calculation.
|
||||
*/
|
||||
switch (target->space & 0x0fff) {
|
||||
case B_CMAP8:
|
||||
limit_clock = si->pix_clk_max8;
|
||||
row_bytes = 1;
|
||||
color_depth = 8;
|
||||
break;
|
||||
case B_RGB15:
|
||||
case B_RGB16:
|
||||
limit_clock = si->pix_clk_max16;
|
||||
row_bytes = 2;
|
||||
color_depth = 16;
|
||||
break;
|
||||
case B_RGB32:
|
||||
limit_clock = si->pix_clk_max32;
|
||||
row_bytes = 4;
|
||||
color_depth = 32;
|
||||
break;
|
||||
default:
|
||||
/* no amount of adjusting will fix not being able to support the pixel format */
|
||||
return B_ERROR;
|
||||
}
|
||||
/* make sure we don't generate more pixel bandwidth than the device can handle */
|
||||
|
||||
if (target->timing.pixel_clock > limit_clock) target->timing.pixel_clock = limit_clock;
|
||||
/* we probably ought to check against too low of a pixel rate, but I'm lazy */
|
||||
|
||||
/* note if we fell outside the limits */
|
||||
if (
|
||||
(target->timing.pixel_clock < low->timing.pixel_clock) ||
|
||||
(target->timing.pixel_clock > high->timing.pixel_clock)
|
||||
) return B_ERROR;
|
||||
|
||||
/* validate display vs. virtual */
|
||||
|
||||
if ((target->timing.h_display > target->virtual_width) || want_same_width)
|
||||
target->virtual_width = target->timing.h_display;
|
||||
if ((target->timing.v_display > target->virtual_height) || want_same_height)
|
||||
target->virtual_height = target->timing.v_display;
|
||||
if (target->virtual_width > 2048)
|
||||
target->virtual_width = 2048;
|
||||
|
||||
/* adjust virtual width for engine limitations */
|
||||
|
||||
target->virtual_width = (target->virtual_width + 7) & ~7;
|
||||
if (
|
||||
(target->virtual_width < low->virtual_width) ||
|
||||
(target->virtual_width > high->virtual_width)
|
||||
) result = B_BAD_VALUE;
|
||||
|
||||
/* calculate rowbytes after we've nailed the virtual width */
|
||||
|
||||
row_bytes *= target->virtual_width;
|
||||
|
||||
/* memory requirement for frame buffer */
|
||||
|
||||
if ((row_bytes * target->virtual_height) > si->mem_size)
|
||||
target->virtual_height = si->mem_size / row_bytes;
|
||||
|
||||
if (target->virtual_height > 2048)
|
||||
target->virtual_height = 2048;
|
||||
|
||||
|
||||
if (target->virtual_height < target->timing.v_display){
|
||||
/* not enough frame buffer memory for the mode */
|
||||
return B_ERROR;}
|
||||
else if (
|
||||
(target->virtual_height < low->virtual_height) ||
|
||||
(target->virtual_height > high->virtual_height)
|
||||
) result = B_BAD_VALUE;
|
||||
|
||||
/*
|
||||
Bit Flag Encoding
|
||||
|
||||
The way the bit flags works is as follows:
|
||||
|
||||
low high meaning
|
||||
--- ---- -------
|
||||
0 0 Feature must NOT be enabled
|
||||
0 1 Feature MAY be enabled, prefered enabled
|
||||
1 0 Feature MAY be enabled, prefered disabled
|
||||
1 1 Feature MUST be enabled
|
||||
|
||||
*/
|
||||
/* MORE WORK REQUIRED HERE. Current drivers mostly ignore the flags */
|
||||
|
||||
/* Look to see if there if the mode is doable */
|
||||
if (result != B_BAD_VALUE)
|
||||
for(i = 0; si->Freq_Table[i].h_disp != 0; i++) {
|
||||
|
||||
if ((si->Freq_Table[i].h_disp << 3 >= target->timing.h_display) &&
|
||||
(si->Freq_Table[i].dacmask >= si->DAC_SubType) &&
|
||||
(si->Freq_Table[i].max_dot_clock >= (target->timing.pixel_clock / 1000.0)) &&
|
||||
(mach64CDepths[si->Freq_Table[i].color_depth & 0x07] >= color_depth)){
|
||||
result = B_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Return the number of modes this device will return from GET_MODE_LIST().
|
||||
*/
|
||||
uint32 ACCELERANT_MODE_COUNT(void) {
|
||||
/* return the number of 'built-in' display modes */
|
||||
return si->mode_count;
|
||||
}
|
||||
|
||||
/*
|
||||
Copy the list of guaranteed supported video modes to the location
|
||||
provided.
|
||||
*/
|
||||
status_t GET_MODE_LIST(display_mode *dm) {
|
||||
/* copy them to the buffer pointed at by *dm */
|
||||
memcpy(dm, atimach64_mode_list, si->mode_count * sizeof(display_mode));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t get_first_mode(display_mode *dm) {
|
||||
/* copy first valid mode to the buffer pointed at by *dm */
|
||||
memcpy(dm, atimach64_mode_list, sizeof(display_mode));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Create a list of display_modes to pass back to the caller.
|
||||
*/
|
||||
status_t create_mode_list(void) {
|
||||
size_t max_size;
|
||||
uint32
|
||||
i, j,
|
||||
pix_clk_range;
|
||||
const display_mode
|
||||
*src;
|
||||
display_mode
|
||||
*dst,
|
||||
low,
|
||||
high;
|
||||
|
||||
/*
|
||||
We prefer frame buffers to have the same endianness as the host CPU, but it's
|
||||
not required. You can even return both, although there isn't a way for the
|
||||
current Screen preferences panel to allow the user to choose which one to use.
|
||||
*/
|
||||
#if defined(__INTEL__)
|
||||
color_space spaces[4] = {B_CMAP8, B_RGB15_LITTLE, B_RGB16_LITTLE, B_RGB32_LITTLE};
|
||||
#else
|
||||
color_space spaces[4] = {B_CMAP8, B_RGB15_BIG, B_RGB16_BIG, B_RGB32_BIG};
|
||||
#endif
|
||||
|
||||
/* printf(" Mode count %ld \n", MODE_COUNT);*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* figure out how big the list could be, and adjust up to nearest multiple of B_PAGE_SIZE */
|
||||
max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
|
||||
/* create an area to hold the info */
|
||||
si->mode_area = atimach64_mode_list_area =
|
||||
create_area("ATIMACH64 accelerant mode info", (void **)&atimach64_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||
if (atimach64_mode_list_area < B_OK) return atimach64_mode_list_area;
|
||||
|
||||
/* walk through our predefined list and see which modes fit this device */
|
||||
src = mode_list;
|
||||
dst = atimach64_mode_list;
|
||||
si->mode_count = 0;
|
||||
for (i = 0; i < MODE_COUNT; i++) {
|
||||
/* set ranges for acceptable values */
|
||||
low = high = *src;
|
||||
/* range is 6.25% of default clock: arbitrarily picked */
|
||||
|
||||
pix_clk_range = low.timing.pixel_clock >> 5;
|
||||
low.timing.pixel_clock -= pix_clk_range;
|
||||
high.timing.pixel_clock += pix_clk_range;
|
||||
/* some cards need wider virtual widths for certain modes */
|
||||
high.virtual_width = 2048;
|
||||
/* do it once for each depth we want to support */
|
||||
for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++) {
|
||||
/* set target values */
|
||||
*dst = *src;
|
||||
/* poke the specific space */
|
||||
dst->space = low.space = high.space = spaces[j];
|
||||
/* ask for a compatible mode */
|
||||
if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
|
||||
/* count it, and move on to next mode */
|
||||
dst++;
|
||||
si->mode_count++;
|
||||
}
|
||||
}
|
||||
/* advance to next mode */
|
||||
src++;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
#include <GraphicsDefs.h>
|
||||
|
||||
#include "GlobalData.h"
|
||||
#include "generic.h"
|
||||
#include "Mach64.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
|
||||
/*
|
||||
Enable/Disable interrupts. Just a wrapper around the
|
||||
ioctl() to the kernel driver.
|
||||
*/
|
||||
static void interrupt_enable(bool flag) {
|
||||
status_t result;
|
||||
atimach64_set_bool_state sbs;
|
||||
|
||||
/* set the magic number so the driver knows we're for real */
|
||||
sbs.magic = ATIMACH64_PRIVATE_DATA_MAGIC;
|
||||
sbs.do_it = flag;
|
||||
/* contact driver and get a pointer to the registers and shared data */
|
||||
result = ioctl(fd, ATIMACH64_RUN_INTERRUPTS, &sbs, sizeof(sbs));
|
||||
}
|
||||
|
||||
/*
|
||||
Calculates the number of bits for a given color_space.
|
||||
Usefull for mode setup routines, etc.
|
||||
*/
|
||||
uint32 calcBitsPerPixel(uint32 cs) {
|
||||
uint32 bpp = 0;
|
||||
|
||||
switch (cs) {
|
||||
case B_RGB32_BIG:
|
||||
case B_RGBA32_BIG:
|
||||
case B_RGB32_LITTLE:
|
||||
case B_RGBA32_LITTLE:
|
||||
bpp = 32; break;
|
||||
case B_RGB24_BIG:
|
||||
case B_RGB24_LITTLE:
|
||||
bpp = 24; break;
|
||||
case B_RGB16_BIG:
|
||||
case B_RGB16_LITTLE:
|
||||
bpp = 16; break;
|
||||
case B_RGB15_BIG:
|
||||
case B_RGBA15_BIG:
|
||||
case B_RGB15_LITTLE:
|
||||
case B_RGBA15_LITTLE:
|
||||
bpp = 15; break;
|
||||
case B_CMAP8:
|
||||
bpp = 8; break;
|
||||
}
|
||||
return bpp;
|
||||
}
|
||||
|
||||
/*
|
||||
The code to actually configure the display. Unfortunately, there's not much
|
||||
that can be provided in the way of sample code. If you're lucky, you're writing
|
||||
a driver for a device that has all (or at least most) of the bits for a particular
|
||||
configuration value in the same register, rather than spread out over the standard
|
||||
VGA registers + a zillion expansion bits. In any case, I've found that the way
|
||||
to simplify this routine is to do all of the error checking in PROPOSE_DISPLAY_MODE(),
|
||||
and just assume that the values I get here are acceptable.
|
||||
*/
|
||||
static void do_set_display_mode(display_mode *dm) {
|
||||
|
||||
mach64CRTCRegRec Regs;
|
||||
|
||||
|
||||
CalcCRTCRegs(&Regs, dm);
|
||||
|
||||
/* disable interrupts using the kernel driver */
|
||||
interrupt_enable(false);
|
||||
|
||||
SetCRTCRegs(&Regs, dm);
|
||||
|
||||
/* Initialize RAMDAC */
|
||||
InitRAMDAC(calcBitsPerPixel(dm->space), dm->flags);
|
||||
|
||||
/* enable interrupts using the kernel driver */
|
||||
interrupt_enable(true);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
The exported mode setting routine. First validate the mode, then call our
|
||||
private routine to hammer the registers.
|
||||
*/
|
||||
status_t SET_DISPLAY_MODE(display_mode *mode_to_set) {
|
||||
display_mode bounds, target;
|
||||
|
||||
/* ask for the specific mode */
|
||||
target = bounds = *mode_to_set;
|
||||
if (PROPOSE_DISPLAY_MODE(&target, &bounds, &bounds) == B_ERROR)
|
||||
return B_ERROR;
|
||||
|
||||
do_set_display_mode(&target);
|
||||
|
||||
/* update shared info */
|
||||
target.h_display_start = 0;
|
||||
target.v_display_start = 0;
|
||||
si->dm = target;
|
||||
|
||||
/* calculate bytes per row ans set it */
|
||||
si->fbc.bytes_per_row = ((calcBitsPerPixel(target.space) + 1) / 8)
|
||||
*target.virtual_width;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Set which pixel of the virtual frame buffer will show up in the
|
||||
top left corner of the display device. Used for page-flipping
|
||||
games and virtual desktops.
|
||||
*/
|
||||
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
|
||||
int byte_offset;
|
||||
/*
|
||||
Many devices have limitations on the granularity of the horizontal offset.
|
||||
Make any checks for this here. A future revision of the driver API will
|
||||
add a hook to return the granularity for a given display mode.
|
||||
*/
|
||||
/* most cards can handle multiples of 8 */
|
||||
if (h_display_start & 0x07)
|
||||
return B_ERROR;
|
||||
/* do not run past end of display */
|
||||
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
|
||||
return B_ERROR;
|
||||
if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
|
||||
return B_ERROR;
|
||||
|
||||
/* everybody remember where we parked... */
|
||||
si->dm.h_display_start = h_display_start;
|
||||
si->dm.v_display_start = v_display_start;
|
||||
|
||||
/* Calculate offset remebering to include the cursor area */
|
||||
byte_offset = (si->fbc.frame_buffer - si->framebuffer) >> 3;
|
||||
byte_offset += ((h_display_start + v_display_start*si->dm.virtual_width) *
|
||||
(calcBitsPerPixel(si->dm.space) / 8)) >> 3;
|
||||
|
||||
/* actually set the registers */
|
||||
if (~(si->dm.flags & B_HARDWARE_CURSOR))
|
||||
SHOW_CURSOR(false);
|
||||
|
||||
outw(CRTC_OFF_PITCH, (inw(CRTC_OFF_PITCH) & 0xfff00000) | byte_offset);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Set the indexed color palette.
|
||||
*/
|
||||
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
|
||||
|
||||
/*
|
||||
Some cards use the indexed color regisers in the DAC for gamma correction.
|
||||
If this is true with your device (and it probably is), you need to protect
|
||||
against setting these registers when not in an indexed mode.
|
||||
*/
|
||||
if (si->dm.space != B_CMAP8) return;
|
||||
|
||||
/*
|
||||
There isn't any need to keep a copy of the data being stored, as the app_server
|
||||
will set the colors each time it switches to an 8bpp mode, or takes ownership
|
||||
of an 8bpp mode after a GameKit app has used it.
|
||||
*/
|
||||
|
||||
/*
|
||||
You're on your own from here. Chances are your code will look something like
|
||||
what follows:
|
||||
*/
|
||||
/*
|
||||
Due to the nature of the SAMPLE card, we need to do bytewise writes
|
||||
to the dac regs. Stupid, but there you go. So, we do it like we're
|
||||
supposed to.
|
||||
*/
|
||||
|
||||
WaitQueue(1);
|
||||
|
||||
outb(DAC_REGS, first);
|
||||
|
||||
while (count--) {
|
||||
outb(DAC_REGS+1, *color_data++);
|
||||
outb(DAC_REGS+1, *color_data++);
|
||||
outb(DAC_REGS+1, *color_data++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* masks for DPMS control bits */
|
||||
enum {
|
||||
H_SYNC_OFF = 0x01,
|
||||
V_SYNC_OFF = 0x02,
|
||||
DISPLAY_OFF = 0x04,
|
||||
BITSMASK = H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF
|
||||
};
|
||||
|
||||
/*
|
||||
Put the display into one of the Display Power Management modes.
|
||||
*/
|
||||
status_t SET_DPMS_MODE(uint32 dpms_flags) {
|
||||
uint32 LTemp;
|
||||
|
||||
/*
|
||||
The register containing the horizontal and vertical sync control bits
|
||||
usually contains other control bits, so do a read-modify-write.
|
||||
*/
|
||||
/* read bits */
|
||||
LTemp = inw(CRTC_GEN_CNTL);
|
||||
/* mask them */
|
||||
LTemp &= ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS); /* clear all disable bits (including display disable) */
|
||||
|
||||
/* now pick one of the DPMS configurations */
|
||||
switch(dpms_flags) {
|
||||
case B_DPMS_ON: /* H: on, V: on */
|
||||
/* do nothing, bits already clear */
|
||||
/* usually, but it may be different for your device */
|
||||
break;
|
||||
case B_DPMS_STAND_BY: /* H: off, V: on, display off */
|
||||
LTemp |= CRTC_HSYNC_DIS;
|
||||
break;
|
||||
case B_DPMS_SUSPEND: /* H: on, V: off, display off */
|
||||
LTemp |= CRTC_VSYNC_DIS;
|
||||
break;
|
||||
case B_DPMS_OFF: /* H: off, V: off, display off */
|
||||
LTemp |= CRTC_HSYNC_DIS | CRTC_VSYNC_DIS;
|
||||
break;
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
/* write the bits */
|
||||
outw(CRTC_GEN_CNTL, LTemp);
|
||||
|
||||
snooze(10000);
|
||||
|
||||
/*
|
||||
NOTE: if you're driving a device with a backlight (like a digital LCD),
|
||||
you may want to turn off the backlight here when in a DPMS power saving mode.
|
||||
*/
|
||||
if (dpms_flags == B_DPMS_ON)
|
||||
/* turn on the back light */
|
||||
;
|
||||
else
|
||||
/* turn off the back light */
|
||||
;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Report device DPMS capabilities. Most newer cards can do it all.
|
||||
I've only seen one older card that can do a subset (ON and OFF).
|
||||
Very early cards may not be able to do this at all.
|
||||
*/
|
||||
uint32 DPMS_CAPABILITIES(void) {
|
||||
return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Return the current DPMS mode.
|
||||
*/
|
||||
uint32 DPMS_MODE(void) {
|
||||
uint32 LTemp;
|
||||
uint32 mode = B_DPMS_ON;
|
||||
|
||||
/* read the control bits from the device */
|
||||
/* read the bits */
|
||||
LTemp = inw(CRTC_GEN_CNTL);
|
||||
|
||||
/* what mode is set? */
|
||||
switch (LTemp & (CRTC_HSYNC_DIS | CRTC_VSYNC_DIS)) {
|
||||
case 0: /* H: on, V: on */
|
||||
mode = B_DPMS_ON;
|
||||
break;
|
||||
case CRTC_HSYNC_DIS: /* H: off, V: on */
|
||||
mode = B_DPMS_STAND_BY;
|
||||
break;
|
||||
case CRTC_VSYNC_DIS: /* H: on, V: off */
|
||||
mode = B_DPMS_SUSPEND;
|
||||
break;
|
||||
case (CRTC_HSYNC_DIS | CRTC_VSYNC_DIS): /* H: off, V: off */
|
||||
mode = B_DPMS_OFF;
|
||||
break;
|
||||
}
|
||||
return mode;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
#if !defined(GENERIC_H)
|
||||
#define GENERIC_H
|
||||
|
||||
#include <Accelerant.h>
|
||||
|
||||
status_t INIT_ACCELERANT(int fd);
|
||||
ssize_t ACCELERANT_CLONE_INFO_SIZE(void);
|
||||
void GET_ACCELERANT_CLONE_INFO(void *data);
|
||||
status_t CLONE_ACCELERANT(void *data);
|
||||
void UNINIT_ACCELERANT(void);
|
||||
status_t GET_ACCELERANT_DEVICE_INFO(accelerant_device_info *adi);
|
||||
sem_id ACCELERANT_RETRACE_SEMAPHORE(void);
|
||||
|
||||
uint32 ACCELERANT_MODE_COUNT(void);
|
||||
status_t GET_MODE_LIST(display_mode *dm);
|
||||
status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high);
|
||||
status_t SET_DISPLAY_MODE(display_mode *mode_to_set);
|
||||
status_t GET_DISPLAY_MODE(display_mode *current_mode);
|
||||
status_t GET_FRAME_BUFFER_CONFIG(frame_buffer_config *a_frame_buffer);
|
||||
status_t GET_PIXEL_CLOCK_LIMITS(display_mode *dm, uint32 *low, uint32 *high);
|
||||
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start);
|
||||
status_t GET_TIMING_CONSTRAINTS(display_timing_constraints *dtc);
|
||||
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags);
|
||||
|
||||
uint32 DPMS_CAPABILITIES(void);
|
||||
uint32 DPMS_MODE(void);
|
||||
status_t SET_DPMS_MODE(uint32 dpms_flags);
|
||||
|
||||
status_t SET_CURSOR_SHAPE(uint16 width, uint16 height, uint16 hot_x, uint16 hot_y, uint8 *andMask, uint8 *xorMask);
|
||||
void MOVE_CURSOR(uint16 x, uint16 y);
|
||||
void SHOW_CURSOR(bool is_visible);
|
||||
|
||||
uint32 ACCELERANT_ENGINE_COUNT(void);
|
||||
status_t ACQUIRE_ENGINE(uint32 capabilities, uint32 max_wait, sync_token *st, engine_token **et);
|
||||
status_t RELEASE_ENGINE(engine_token *et, sync_token *st);
|
||||
void WAIT_ENGINE_IDLE(void);
|
||||
status_t GET_SYNC_TOKEN(engine_token *et, sync_token *st);
|
||||
status_t SYNC_TO_TOKEN(sync_token *st);
|
||||
|
||||
void SCREEN_TO_SCREEN_BLIT(engine_token *et, blit_params *list, uint32 count);
|
||||
void FILL_RECTANGLE(engine_token *et, uint32 color, fill_rect_params *list, uint32 count);
|
||||
void INVERT_RECTANGLE(engine_token *et, fill_rect_params *list, uint32 count);
|
||||
|
||||
void FILL_SPAN(engine_token *et, uint32 color, uint16 *list, uint32 count);
|
||||
|
||||
#endif
|
|
@ -1,5 +1,6 @@
|
|||
SubDir HAIKU_TOP src add-ons kernel drivers graphics ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics ati ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics common ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics et6x00 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics intel_extreme ;
|
||||
|
@ -14,5 +15,3 @@ SubInclude HAIKU_TOP src add-ons kernel drivers graphics skeleton ;
|
|||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics vesa ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics via ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers graphics vmware ;
|
||||
|
||||
SubIncludeGPL HAIKU_TOP src add-ons kernel drivers graphics atimach64 ;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
SubDir HAIKU_TOP src add-ons kernel drivers graphics ati ;
|
||||
|
||||
UsePrivateHeaders [ FDirName graphics ati ] ;
|
||||
UsePrivateHeaders [ FDirName graphics common ] ;
|
||||
UsePrivateHeaders graphics kernel ;
|
||||
|
||||
KernelAddon ati :
|
||||
driver.cpp
|
||||
;
|
File diff suppressed because it is too large
Load Diff
|
@ -1,339 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
|
@ -1,11 +0,0 @@
|
|||
SubDir HAIKU_TOP src add-ons kernel drivers graphics atimach64 ;
|
||||
SubDirCcFlags -DSEMAPHORE=1 ;
|
||||
|
||||
UsePrivateHeaders graphics ;
|
||||
UsePrivateHeaders [ FDirName graphics atimach64 ] ;
|
||||
|
||||
KernelAddon atimach64.driver :
|
||||
driver.c
|
||||
m64info.c
|
||||
;
|
||||
|
|
@ -1,976 +0,0 @@
|
|||
/*
|
||||
|
||||
Driver for ATIMach64VT
|
||||
|
||||
Lots of rewriting to be able to work with other ATIMACH64 cards
|
||||
|
||||
Rene MacKinney <rene_@freenet.co.uk>
|
||||
|
||||
6.May.1999
|
||||
|
||||
|
||||
Based on GraphicDriverKit for R4 alpha release
|
||||
|
||||
Huge thanks to Trey for all the help
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* standard kernel driver stuff */
|
||||
#include <KernelExport.h>
|
||||
#include <PCI.h>
|
||||
#include <OS.h>
|
||||
#include <malloc.h>
|
||||
|
||||
/* this is for the standardized portion of the driver API */
|
||||
/* currently only one operation is defined: B_GET_ACCELERANT_SIGNATURE */
|
||||
#include <graphic_driver.h>
|
||||
|
||||
/* this is for sprintf() */
|
||||
#include <stdio.h>
|
||||
|
||||
/* this is for string compares */
|
||||
#include <string.h>
|
||||
|
||||
/* The private interface between the accelerant and the kernel driver. */
|
||||
#include "DriverInterface.h"
|
||||
|
||||
/* ATI Mach64 Definitions */
|
||||
#include "regmach64.h"
|
||||
#include "ATIMach64.h"
|
||||
|
||||
#if DEBUG > 0
|
||||
#define ddprintf(a) dprintf a
|
||||
#else
|
||||
#define ddprintf(a)
|
||||
#endif
|
||||
|
||||
#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
|
||||
#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
|
||||
|
||||
/* Given the fact that the VT is a motherboard integrated
|
||||
card we only support one */
|
||||
|
||||
#define MAX_DEVICES 1
|
||||
|
||||
/* The vertical retrace semaphore is not implemented instead of erasing
|
||||
all the code about it we simply don't compile it. Waiting for the
|
||||
implementation */
|
||||
|
||||
#define SEMAPHORE 0
|
||||
|
||||
|
||||
/* Tell the kernel what revision of the driver API we support */
|
||||
int32 api_version = 2;
|
||||
|
||||
/* these structures are private to the kernel driver */
|
||||
typedef struct device_info device_info;
|
||||
|
||||
#if defined(POST_R4_0)
|
||||
typedef struct {
|
||||
timer te; /* timer entry for add_timer() */
|
||||
device_info *di; /* pointer to the owning device */
|
||||
bigtime_t when_target; /* when we're supposed to wake up */
|
||||
} timer_info;
|
||||
#endif
|
||||
|
||||
struct device_info {
|
||||
uint32 is_open; /* a count of how many times the devices has been opened */
|
||||
area_id shared_area; /* the area shared between the driver and all of the accelerants */
|
||||
shared_info *si; /* a pointer to the shared area, for convenience */
|
||||
vuint32 *regs; /* kernel's pointer to memory mapped registers */
|
||||
int32 can_interrupt; /* when we're faking interrupts, let's us know if we should generate one */
|
||||
#if defined(POST_R4_0)
|
||||
timer_info ti_a; /* a pool of two timer managment buffers */
|
||||
timer_info ti_b;
|
||||
timer_info *current_timer; /* the timer buffer that's currently in use */
|
||||
#else
|
||||
thread_id tid;
|
||||
#endif
|
||||
#if DEBUG > 0
|
||||
uint32 interrupt_count; /* if we're debugging, a count of how many times the interrupt handler has
|
||||
been called for this device */
|
||||
#endif
|
||||
pci_info pcii; /* a convenience copy of the pci info for this device */
|
||||
char name[B_OS_NAME_LENGTH]; /* where we keep the name of the device for publishing and comparing */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
#if DEBUG > 0
|
||||
uint32 total_interrupts; /* total number of interrupts seen by our handler */
|
||||
#endif
|
||||
uint32 count; /* number of devices actually found */
|
||||
benaphore kernel; /* for serializing opens/closes */
|
||||
char *device_names[MAX_DEVICES+1]; /* device name pointer storage */
|
||||
device_info di[MAX_DEVICES]; /* device specific stuff */
|
||||
} DeviceData;
|
||||
|
||||
/* prototypes for our private functions */
|
||||
static status_t open_hook (const char* name, uint32 flags, void** cookie);
|
||||
static status_t close_hook (void* dev);
|
||||
static status_t free_hook (void* dev);
|
||||
static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len);
|
||||
static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len);
|
||||
static status_t control_hook (void* dev, uint32 msg, void *buf, size_t len);
|
||||
static status_t map_device(device_info *di);
|
||||
static void unmap_device(device_info *di);
|
||||
static void probe_devices(void);
|
||||
static int32 atimach64_interrupt(void *data);
|
||||
|
||||
#if DEBUG > 0
|
||||
static int dump(int argc, char **argv);
|
||||
#endif
|
||||
|
||||
static DeviceData *pd;
|
||||
static pci_module_info *pci_bus;
|
||||
static device_hooks graphics_device_hooks = {
|
||||
open_hook,
|
||||
close_hook,
|
||||
free_hook,
|
||||
control_hook,
|
||||
read_hook,
|
||||
write_hook,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static uint16 ati_device_list[] = {
|
||||
PCI_MACH64_VT_ID, /* Mach64 VT device */
|
||||
0
|
||||
};
|
||||
|
||||
static struct {
|
||||
uint16 vendor;
|
||||
uint16 *devices;
|
||||
} SupportedDevices[] = {
|
||||
{PCI_ATI_VENDOR_ID, ati_device_list},
|
||||
{0x0000, NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
init_hardware() - Returns B_OK if one is
|
||||
found, otherwise returns B_ERROR so the driver will be unloaded.
|
||||
*/
|
||||
status_t
|
||||
init_hardware(void) {
|
||||
long pci_index = 0;
|
||||
pci_info pcii;
|
||||
bool found_one = FALSE;
|
||||
|
||||
|
||||
/* choke if we can't find the PCI bus */
|
||||
if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
/* while there are more pci devices */
|
||||
while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) {
|
||||
int vendor = 0;
|
||||
|
||||
ddprintf(("SKD init_hardware(): checking pci index %ld, device 0x%04x/0x%04x\n", pci_index, pcii.vendor_id, pcii.device_id));
|
||||
/* if we match a supported vendor */
|
||||
while (SupportedDevices[vendor].vendor) {
|
||||
if (SupportedDevices[vendor].vendor == pcii.vendor_id) {
|
||||
uint16 *devices = SupportedDevices[vendor].devices;
|
||||
/* while there are more supported devices */
|
||||
while (*devices) {
|
||||
/* if we match a supported device */
|
||||
if (*devices == pcii.device_id ) {
|
||||
|
||||
ddprintf(("SKD: we support this device\n"));
|
||||
found_one = TRUE;
|
||||
goto done;
|
||||
}
|
||||
/* next supported device */
|
||||
devices++;
|
||||
}
|
||||
}
|
||||
vendor++;
|
||||
}
|
||||
/* next pci_info struct, please */
|
||||
pci_index++;
|
||||
}
|
||||
ddprintf(("SKD: init_hardware - no supported devices\n"));
|
||||
|
||||
done:
|
||||
/* put away the module manager */
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
return (found_one ? B_OK : B_ERROR);
|
||||
}
|
||||
|
||||
status_t
|
||||
init_driver(void) {
|
||||
|
||||
/* get a handle for the pci bus */
|
||||
if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
/* driver private data */
|
||||
pd = (DeviceData *)calloc(1, sizeof(DeviceData));
|
||||
if (!pd) {
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
return B_ERROR;
|
||||
}
|
||||
/* initialize the benaphore */
|
||||
INIT_BEN(pd->kernel);
|
||||
/* find all of our supported devices */
|
||||
probe_devices();
|
||||
#if DEBUG > 0
|
||||
add_debugger_command("dump", dump, "dump ATIMach64 kernel driver persistant data");
|
||||
#endif
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
const char **
|
||||
publish_devices(void) {
|
||||
/* return the list of supported devices */
|
||||
return (const char **)pd->device_names;
|
||||
}
|
||||
|
||||
device_hooks *
|
||||
find_device(const char *name) {
|
||||
int index = 0;
|
||||
while (pd->device_names[index]) {
|
||||
if (strcmp(name, pd->device_names[index]) == 0)
|
||||
return &graphics_device_hooks;
|
||||
index++;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
uninit_driver(void) {
|
||||
|
||||
#if DEBUG > 0
|
||||
remove_debugger_command("dump", dump);
|
||||
#endif
|
||||
|
||||
/* free the driver data */
|
||||
DELETE_BEN(pd->kernel);
|
||||
free(pd);
|
||||
pd = NULL;
|
||||
|
||||
/* put the pci module away */
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
}
|
||||
|
||||
static status_t map_device(device_info *di) {
|
||||
/* default: frame buffer in [0], control regs in [1] */
|
||||
/* int regs = 1; */
|
||||
int fb = 0;
|
||||
char buffer[B_OS_NAME_LENGTH];
|
||||
shared_info *si = di->si;
|
||||
uint32 tmpUlong;
|
||||
pci_info *pcii = &(di->pcii);
|
||||
uint32 rom_base;
|
||||
|
||||
|
||||
/* enable memory mapped IO, disable VGA I/O */
|
||||
tmpUlong = get_pci(PCI_command, 4);
|
||||
tmpUlong |= PCI_command_memory;
|
||||
tmpUlong &= ~((uint32) PCI_command_io);
|
||||
set_pci(PCI_command, 4, tmpUlong);
|
||||
|
||||
/* enable ROM decoding */
|
||||
/* tmpUlong = get_pci(PCI_rom_base, 4);
|
||||
tmpUlong |= PCI_rom_enable;
|
||||
set_pci(PCI_rom_base, 4, tmpUlong); */
|
||||
|
||||
/* map the rom */
|
||||
/* If rom_base points to 0x00 try using standard ROM location for Mach64 */
|
||||
rom_base = (di->pcii.u.h0.rom_base == 0) ? 0x000c0000 : di->pcii.u.h0.rom_base;
|
||||
sprintf(buffer, "%04X_%04X_%02X%02X%02X rom",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
si->rom_area = map_physical_memory(
|
||||
buffer,
|
||||
(void *)rom_base,
|
||||
di->pcii.u.h0.rom_size,
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
B_READ_AREA,
|
||||
(void **)&(si->rom));
|
||||
|
||||
/* return the error if there was some problem */
|
||||
if (si->rom_area < 0) {
|
||||
delete_area(si->regs_area);
|
||||
si->regs_area = -1;
|
||||
return si->rom_area;
|
||||
}
|
||||
|
||||
sprintf(buffer, "%04X_%04X_%02X%02X%02X framebuffer",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
si->fb_area = map_physical_memory(
|
||||
buffer,
|
||||
(void *) di->pcii.u.h0.base_registers[fb],
|
||||
di->pcii.u.h0.base_register_sizes[fb],
|
||||
#if defined(__INTEL__)
|
||||
#if defined(POST_R4_0)
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
|
||||
#else
|
||||
B_ANY_KERNEL_ADDRESS | B_MTR_WC,
|
||||
#endif
|
||||
#else
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||
#endif
|
||||
B_READ_AREA + B_WRITE_AREA,
|
||||
&(si->framebuffer));
|
||||
|
||||
#if defined(__INTEL__)
|
||||
if (si->fb_area < 0) {
|
||||
/* try to map this time without write combining */
|
||||
/*
|
||||
After R4.0 (Intel), map_physical_memory() will try B_ANY_KERNEL_ADDRESS if
|
||||
a call with B_ANY_KERNEL_BLOCK_ADDRESS would fail. It always worked this way
|
||||
under PPC.
|
||||
*/
|
||||
si->fb_area = map_physical_memory(
|
||||
buffer,
|
||||
(void *) di->pcii.u.h0.base_registers[fb],
|
||||
di->pcii.u.h0.base_register_sizes[fb],
|
||||
#if defined(POST_R4_0)
|
||||
B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||
#else
|
||||
B_ANY_KERNEL_ADDRESS,
|
||||
#endif
|
||||
B_READ_AREA + B_WRITE_AREA,
|
||||
&(si->framebuffer));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if there was an error, delete our other areas */
|
||||
if (si->fb_area < 0) {
|
||||
delete_area(si->regs_area);
|
||||
si->regs_area = -1;
|
||||
delete_area(si->rom_area);
|
||||
si->rom_area = -1;
|
||||
}
|
||||
/* remember the DMA address of the frame buffer for BDirectWindow purposes */
|
||||
si->framebuffer_pci = (void *) di->pcii.u.h0.base_registers_pci[fb];
|
||||
|
||||
return si->fb_area;
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_device(device_info *di) {
|
||||
shared_info *si = di->si;
|
||||
uint32 tmpUlong;
|
||||
pci_info *pcii = &(di->pcii);
|
||||
|
||||
ddprintf(("unmap_device(%08lx) begins...\n", (uint32)di));
|
||||
ddprintf((" regs_area: %ld\n fb_area: %ld\n", si->regs_area, si->fb_area));
|
||||
/* disable memory mapped IO */
|
||||
tmpUlong = get_pci(PCI_command, 4);
|
||||
tmpUlong &= 0xfffffffc;
|
||||
set_pci(PCI_command, 4, tmpUlong);
|
||||
/* disable ROM decoding */
|
||||
tmpUlong = get_pci(PCI_rom_base, 4);
|
||||
tmpUlong &= 0xfffffffe;
|
||||
set_pci(PCI_rom_base, 4, tmpUlong);
|
||||
/* delete the areas */
|
||||
if (si->rom_area >= 0) delete_area(si->rom_area);
|
||||
/* if (si->regs_area >= 0) delete_area(si->regs_area);*/
|
||||
if (si->fb_area >= 0) delete_area(si->fb_area);
|
||||
si->rom_area = si->regs_area = si->fb_area = -1;
|
||||
si->framebuffer = NULL;
|
||||
di->regs = NULL;
|
||||
si->rom = NULL;
|
||||
ddprintf(("unmap_device() ends.\n"));
|
||||
}
|
||||
|
||||
static void
|
||||
probe_devices(void) {
|
||||
uint32 pci_index = 0;
|
||||
uint32 count = 0;
|
||||
device_info *di = pd->di;
|
||||
|
||||
/* while there are more pci devices */
|
||||
while ((count < MAX_DEVICES) && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) {
|
||||
int vendor = 0;
|
||||
|
||||
/* if we match a supported vendor */
|
||||
while (SupportedDevices[vendor].vendor) {
|
||||
if (SupportedDevices[vendor].vendor == di->pcii.vendor_id) {
|
||||
uint16 *devices = SupportedDevices[vendor].devices;
|
||||
/* while there are more supported devices */
|
||||
while (*devices) {
|
||||
/* if we match a supported device */
|
||||
if (*devices == di->pcii.device_id ) {
|
||||
/* publish the device name */
|
||||
sprintf(di->name, "graphics/%04X_%04X_%02X%02X%02X",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
ddprintf(("SKD: making /dev/%s\n", di->name));
|
||||
/* remember the name */
|
||||
pd->device_names[count] = di->name;
|
||||
/* mark the driver as available for R/W open */
|
||||
di->is_open = 0;
|
||||
/* mark areas as not yet created */
|
||||
di->shared_area = -1;
|
||||
/* mark pointer to shared data as invalid */
|
||||
di->si = NULL;
|
||||
/* inc pointer to device info */
|
||||
di++;
|
||||
/* inc count */
|
||||
count++;
|
||||
/* break out of these while loops */
|
||||
goto next_device;
|
||||
}
|
||||
/* next supported device */
|
||||
devices++;
|
||||
}
|
||||
}
|
||||
vendor++;
|
||||
}
|
||||
next_device:
|
||||
/* next pci_info struct, please */
|
||||
pci_index++;
|
||||
}
|
||||
/* propagate count */
|
||||
pd->count = count;
|
||||
/* terminate list of device names with a null pointer */
|
||||
pd->device_names[pd->count] = NULL;
|
||||
ddprintf(("SKD probe_devices: %ld supported devices\n", pd->count));
|
||||
}
|
||||
|
||||
static uint32
|
||||
thread_interrupt_work(int32 *flags, vuint32 *regs, shared_info *si) {
|
||||
uint32 handled = B_HANDLED_INTERRUPT;
|
||||
/* release the vblank semaphore */
|
||||
if (si->vblank >= 0) {
|
||||
int32 blocked;
|
||||
if ((get_sem_count(si->vblank, &blocked) == B_OK) && (blocked < 0)) {
|
||||
release_sem_etc(si->vblank, -blocked, B_DO_NOT_RESCHEDULE);
|
||||
handled = B_INVOKE_SCHEDULER;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
static int32
|
||||
atimach64_interrupt(void *data)
|
||||
{
|
||||
int32 handled = B_UNHANDLED_INTERRUPT;
|
||||
device_info *di = (device_info *)data;
|
||||
shared_info *si = di->si;
|
||||
int32 *flags = &(si->flags);
|
||||
vuint32 *regs;
|
||||
|
||||
#if DEBUG > 0
|
||||
pd->total_interrupts++;
|
||||
#endif
|
||||
|
||||
/* is someone already handling an interrupt for this device? */
|
||||
if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) {
|
||||
#if DEBUG > 0
|
||||
kprintf("SKD: Already in handler!\n");
|
||||
#endif
|
||||
goto exit0;
|
||||
}
|
||||
/* get regs */
|
||||
regs = di->regs;
|
||||
|
||||
/* read the interrrupt status register */
|
||||
|
||||
/* did this card cause an interrupt */
|
||||
if (0 /* replace this expression */) {
|
||||
/* do our stuff */
|
||||
handled = thread_interrupt_work(flags, regs, si);
|
||||
#if DEBUG > 0
|
||||
/* increment the counter for this device */
|
||||
di->interrupt_count++;
|
||||
#endif
|
||||
/* clear the interrupt status */
|
||||
}
|
||||
|
||||
/* note that we're not in the handler any more */
|
||||
atomic_and(flags, ~SKD_HANDLER_INSTALLED);
|
||||
|
||||
exit0:
|
||||
return handled;
|
||||
}
|
||||
|
||||
#if SEMAPHORE
|
||||
#if defined(POST_R4_0)
|
||||
static int32 timer_interrupt_func(timer *te, uint32 pc) {
|
||||
bigtime_t now = system_time();
|
||||
/* get the pointer to the device we're handling this time */
|
||||
device_info *di = ((timer_info *)te)->di;
|
||||
shared_info *si = di->si;
|
||||
int32 *flags = &(si->flags);
|
||||
vuint32 *regs = di->regs;
|
||||
uint32 vbl_status = 0 /* read vertical blank status */;
|
||||
int32 result = B_HANDLED_INTERRUPT;
|
||||
|
||||
/* are we suppoesed to handle interrupts still? */
|
||||
if (atomic_and(flags, -1) & SKD_HANDLER_INSTALLED) {
|
||||
/* reschedule with same period by default */
|
||||
bigtime_t when = si->refresh_period;
|
||||
timer *to;
|
||||
|
||||
/* if interrupts are "enabled", do our thing */
|
||||
if (di->can_interrupt) {
|
||||
/* insert code to sync to interrupts here */
|
||||
if (!vbl_status) {
|
||||
when -= si->blank_period - 4;
|
||||
}
|
||||
/* do the things we do when we notice a vertical retrace */
|
||||
result = thread_interrupt_work(flags, regs, si);
|
||||
|
||||
}
|
||||
|
||||
/* pick the "other" timer */
|
||||
to = (timer *)&(di->ti_a);
|
||||
if (to == te) to = (timer *)&(di->ti_b);
|
||||
/* our guess as to when we should be back */
|
||||
((timer_info *)to)->when_target = now + when;
|
||||
/* reschedule the interrupt */
|
||||
add_timer(to, timer_interrupt_func, ((timer_info *)to)->when_target, B_ONE_SHOT_ABSOLUTE_TIMER);
|
||||
/* remember the currently active timer */
|
||||
di->current_timer = (timer_info *)to;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
static int32
|
||||
fake_interrupt_thread_func(void *_di)
|
||||
{
|
||||
device_info *di; /* = (device_info *)_di; */
|
||||
shared_info *si; /* = di->si; */
|
||||
int32 *flags; /* = &(si->flags); */
|
||||
vuint32 *regs; /* = di->regs; */
|
||||
|
||||
bigtime_t last_sync;
|
||||
bigtime_t this_sync;
|
||||
bigtime_t diff_sync;
|
||||
|
||||
uint32 counter = 1;
|
||||
|
||||
ddprintf((" Device info points to %08x\n",(device_info *)_di));
|
||||
di = (device_info *)_di;
|
||||
ddprintf((" Shared info points to %08x\n",di->si));
|
||||
si = di->si;
|
||||
ddprintf((" Flags points to %08x\n",&(si->flags)));
|
||||
flags = &(si->flags);
|
||||
ddprintf((" Regs points to %08x\n",di->regs));
|
||||
regs = di->regs;
|
||||
|
||||
/* a lie, but we have to start somewhen */
|
||||
|
||||
last_sync = system_time() - 8333;
|
||||
|
||||
ddprintf(("fake_interrupt_thread_func begins\ndi: 0x%08lx\nsi: 0x%08lx\nflags: 0x%08lx\n", (uint32)di, (uint32)si, (uint32)flags));
|
||||
|
||||
/* loop until notified */
|
||||
|
||||
while(atomic_and(flags, -1) & SKD_HANDLER_INSTALLED) {
|
||||
/* see if "interrupts" are enabled */
|
||||
|
||||
if((volatile int32)(di->can_interrupt)) {
|
||||
/* poll the retrace flag until set */
|
||||
|
||||
/* YOUR CODE HERE */
|
||||
|
||||
/* get the system_time */
|
||||
this_sync = system_time();
|
||||
|
||||
/* do our stuff */
|
||||
thread_interrupt_work(flags, regs, si);
|
||||
} else {
|
||||
/* get the system_time */
|
||||
this_sync = system_time();
|
||||
}
|
||||
|
||||
/* find out how long it took */
|
||||
diff_sync = this_sync - last_sync;
|
||||
|
||||
/* back off a little so we're sure to catch the retrace */
|
||||
diff_sync -= diff_sync / 10;
|
||||
|
||||
/*
|
||||
impose some limits so we can recover from refresh rate changes
|
||||
Supported refresh rates are 48 Hz - 120 Hz, so these limits should
|
||||
be slightly wider.
|
||||
*/
|
||||
if(diff_sync < 8000) {
|
||||
diff_sync = 8000; /* not less than 1/125th of sec */
|
||||
}
|
||||
|
||||
if(diff_sync > 16666) {
|
||||
diff_sync = 20000; /* not more than 1/40th of sec */
|
||||
}
|
||||
|
||||
if((counter++ & 0x01ff) == 0) {
|
||||
diff_sync >>= 2; /* periodically quarter the wait to resync */
|
||||
}
|
||||
|
||||
/* update for next go-around */
|
||||
last_sync = this_sync;
|
||||
|
||||
/* snooze until our next retrace */
|
||||
|
||||
snooze_until(this_sync + diff_sync, B_SYSTEM_TIMEBASE);
|
||||
}
|
||||
|
||||
ddprintf(("fake_interrupt_thread_func ends with flags = 0x%08lx\n", *flags));
|
||||
|
||||
/* gotta return something */
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if DEBUG > 0
|
||||
static int dump(int argc, char **argv) {
|
||||
int i;
|
||||
|
||||
kprintf("ATIMach64 Kernel Driver Persistant Data\n\nThere are %ld card(s)\n", pd->count);
|
||||
kprintf("Driver wide benahpore: %ld/%ld\n", pd->kernel.ben, pd->kernel.sem);
|
||||
|
||||
kprintf("Total seen interrupts: %ld\n", pd->total_interrupts);
|
||||
for (i = 0; i < pd->count; i++) {
|
||||
device_info *di = &(pd->di[i]);
|
||||
uint16 device_id = di->pcii.device_id;
|
||||
shared_info *si = di->si;
|
||||
kprintf(" device_id: 0x%04x\n", device_id);
|
||||
kprintf(" interrupt count: %ld\n", di->interrupt_count);
|
||||
if (si) {
|
||||
kprintf(" cursor: %d,%d\n", si->cursor.x, si->cursor.y);
|
||||
kprintf(" flags:");
|
||||
if (si->flags & SKD_MOVE_CURSOR) kprintf(" SKD_MOVE_CURSOR");
|
||||
if (si->flags & SKD_PROGRAM_CLUT) kprintf(" SKD_PROGRAM_CLUT");
|
||||
if (si->flags & SKD_SET_START_ADDR) kprintf(" SKD_SET_START_ADDR");
|
||||
kprintf(" vblank semaphore id: %ld\n", si->vblank);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1; /* the magic number for success */
|
||||
}
|
||||
#endif
|
||||
|
||||
static status_t open_hook (const char* name, uint32 flags, void** cookie) {
|
||||
int32 index = 0;
|
||||
device_info *di;
|
||||
shared_info *si;
|
||||
#if SEMAPHORE
|
||||
thread_id thid;
|
||||
thread_info thinfo;
|
||||
#endif
|
||||
status_t result = B_OK;
|
||||
vuint32 *regs;
|
||||
char shared_name[B_OS_NAME_LENGTH];
|
||||
|
||||
ddprintf(("SKD open_hook(%s, %ld, 0x%08lx)\n", name, flags, (uint32)cookie));
|
||||
|
||||
/* find the device name in the list of devices */
|
||||
/* we're never passed a name we didn't publish */
|
||||
while (pd->device_names[index] && (strcmp(name, pd->device_names[index]) != 0)) index++;
|
||||
|
||||
/* for convienience */
|
||||
di = &(pd->di[index]);
|
||||
|
||||
/* make sure no one else has write access to the common data */
|
||||
AQUIRE_BEN(pd->kernel);
|
||||
|
||||
/* if it's already open for writing */
|
||||
if (di->is_open) {
|
||||
/* mark it open another time */
|
||||
goto mark_as_open;
|
||||
}
|
||||
/* create the shared area */
|
||||
sprintf(shared_name, "%04X_%04X_%02X%02X%02X shared",
|
||||
di->pcii.vendor_id, di->pcii.device_id,
|
||||
di->pcii.bus, di->pcii.device, di->pcii.function);
|
||||
/* create this area with NO user-space read or write permissions, to prevent accidental dammage */
|
||||
di->shared_area = create_area(shared_name, (void **)&(di->si), B_ANY_KERNEL_ADDRESS, ((sizeof(shared_info) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), B_FULL_LOCK, 0);
|
||||
if (di->shared_area < 0) {
|
||||
/* return the error */
|
||||
result = di->shared_area;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* save a few dereferences */
|
||||
si = di->si;
|
||||
|
||||
/* save the vendor and device IDs */
|
||||
si->vendor_id = di->pcii.vendor_id;
|
||||
si->device_id = di->pcii.device_id;
|
||||
si->revision = di->pcii.revision;
|
||||
|
||||
|
||||
/* map the device */
|
||||
result = map_device(di);
|
||||
|
||||
if (result < 0) goto free_shared;
|
||||
|
||||
/* Find registers in memory */
|
||||
/* This is the place for 2MB and 8MB boards */
|
||||
si->regs = (void *)((unsigned int)si->framebuffer + 0x7ffc00);
|
||||
if ((unsigned int)si->device_id != (inw(CONFIG_CHIP_ID) & CFG_CHIP_TYPE)) {
|
||||
/* Try place for 4MB */
|
||||
si->regs = (void *)((unsigned int)si->framebuffer + 0x3ffc00);
|
||||
if (si->device_id != (inw(CONFIG_CHIP_ID) & CFG_CHIP_TYPE)) {
|
||||
ddprintf(("Registers not found ! \n"));
|
||||
goto free_shared;
|
||||
}
|
||||
}
|
||||
|
||||
/* obtain all information related to the Mach64 */
|
||||
|
||||
result = GetATIInfo(si);
|
||||
if (result < 0) goto free_shared;
|
||||
|
||||
|
||||
/* create a semaphore for vertical blank management */
|
||||
#if SEMAPHORE
|
||||
si->vblank = create_sem(0, di->name);
|
||||
if (si->vblank < 0) {
|
||||
result = si->vblank;
|
||||
goto unmap;
|
||||
}
|
||||
#else
|
||||
/* No semafore for the moment */
|
||||
si->vblank = B_ERROR;
|
||||
#endif
|
||||
|
||||
/* change the owner of the semaphores to the opener's team */
|
||||
/* this is required because apps can't aquire kernel semaphores */
|
||||
#if SEMAPHORE
|
||||
thid = find_thread(NULL);
|
||||
get_thread_info(thid, &thinfo);
|
||||
set_sem_owner(si->vblank, thinfo.team);
|
||||
#endif
|
||||
|
||||
/* assign local regs pointer for ATIMACH64xx() macros */
|
||||
regs = di->regs;
|
||||
|
||||
/* disable and clear any pending interrupts */
|
||||
|
||||
#if SEMAPHORE
|
||||
/* if we're faking interrupts */
|
||||
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){
|
||||
/* fake some kind of interrupt with a timer */
|
||||
di->can_interrupt = FALSE;
|
||||
si->flags = SKD_HANDLER_INSTALLED;
|
||||
si->refresh_period = 16666; /* fake 60Hz to start */
|
||||
si->blank_period = si->refresh_period / 20;
|
||||
#if defined(POST_R4_0)
|
||||
di->ti_a.di = di; /* refer to ourself */
|
||||
di->ti_b.di = di;
|
||||
di->current_timer = &(di->ti_a);
|
||||
/* program the first timer interrupt, and it will handle the rest */
|
||||
result = add_timer((timer *)(di->current_timer), timer_interrupt_func, si->refresh_period, B_ONE_SHOT_RELATIVE_TIMER);
|
||||
/* bail if we can't add the timer */
|
||||
if (result != B_OK) goto delete_the_sem;
|
||||
#else */
|
||||
/* fake some kind of interrupt with a thread */
|
||||
result = di->tid = spawn_kernel_thread(fake_interrupt_thread_func, "SKD fake interrupt", B_REAL_TIME_DISPLAY_PRIORITY, di);
|
||||
/* bail if we can't spawn the thread */
|
||||
if(result < 0) goto delete_the_sem;
|
||||
/* start up the thread */
|
||||
resume_thread(di->tid);
|
||||
|
||||
#endif
|
||||
} else {
|
||||
/* otherwise install our interrupt handler */
|
||||
result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, atimach64_interrupt, (void *)di, 0);
|
||||
/* bail if we couldn't install the handler */
|
||||
if (result != B_OK) goto delete_the_sem;
|
||||
}
|
||||
#endif
|
||||
|
||||
mark_as_open:
|
||||
/* mark the device open */
|
||||
di->is_open++;
|
||||
|
||||
/* send the cookie to the opener */
|
||||
*cookie = di;
|
||||
|
||||
goto done;
|
||||
|
||||
/* delete_the_sem: */
|
||||
delete_sem(si->vblank);
|
||||
|
||||
/* unmap: */
|
||||
unmap_device(di);
|
||||
|
||||
free_shared:
|
||||
/* clean up our shared area */
|
||||
delete_area(di->shared_area);
|
||||
di->shared_area = -1;
|
||||
di->si = NULL;
|
||||
|
||||
done:
|
||||
/* end of critical section */
|
||||
RELEASE_BEN(pd->kernel);
|
||||
|
||||
/* all done, return the status */
|
||||
ddprintf(("open_hook returning 0x%08lx\n", result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ----------
|
||||
read_hook - does nothing, gracefully
|
||||
----- */
|
||||
static status_t
|
||||
read_hook (void* dev, off_t pos, void* buf, size_t* len)
|
||||
{
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
write_hook - does nothing, gracefully
|
||||
----- */
|
||||
static status_t
|
||||
write_hook (void* dev, off_t pos, const void* buf, size_t* len)
|
||||
{
|
||||
*len = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
/* ----------
|
||||
close_hook - does nothing, gracefully
|
||||
----- */
|
||||
static status_t
|
||||
close_hook (void* dev)
|
||||
{
|
||||
ddprintf(("SKD close_hook(%08lx)\n", (uint32)dev));
|
||||
/* we don't do anything on close: there might be dup'd fd */
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
/* -----------
|
||||
free_hook - close down the device
|
||||
----------- */
|
||||
static status_t
|
||||
free_hook (void* dev) {
|
||||
device_info *di = (device_info *)dev;
|
||||
shared_info *si = di->si;
|
||||
|
||||
ddprintf(("SKD free_hook() begins...\n"));
|
||||
/* lock the driver */
|
||||
AQUIRE_BEN(pd->kernel);
|
||||
|
||||
/* if opened multiple times, decrement the open count and exit */
|
||||
if (di->is_open > 1)
|
||||
goto unlock_and_exit;
|
||||
|
||||
#if SEMAPHORE
|
||||
/* disable and clear any pending interrupts */
|
||||
|
||||
|
||||
/* if we were faking the interrupts */
|
||||
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){
|
||||
/* stop our interrupt faking thread */
|
||||
si->flags = 0;
|
||||
di->can_interrupt = FALSE;
|
||||
#if defined(POST_R4_0)
|
||||
/* cancel the timer */
|
||||
/* we don't know which one is current, so cancel them both and ignore any error */
|
||||
cancel_timer((timer *)&(di->ti_a));
|
||||
cancel_timer((timer *)&(di->ti_b));
|
||||
#else
|
||||
/* we don't do anything here, as the R4 kernel reaps its own threads */
|
||||
/* After R4.0 we can do it ourselves, but we'd rather use timers */
|
||||
#endif
|
||||
/* otherwise */
|
||||
} else {
|
||||
/* remove interrupt handler */
|
||||
remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, atimach64_interrupt, di);
|
||||
}
|
||||
|
||||
/* delete the semaphores, ignoring any errors ('cause the owning team may have died on us) */
|
||||
delete_sem(si->vblank);
|
||||
#endif
|
||||
si->vblank = -1;
|
||||
|
||||
|
||||
/* free regs and framebuffer areas */
|
||||
unmap_device(di);
|
||||
|
||||
/* clean up our shared area */
|
||||
delete_area(di->shared_area);
|
||||
di->shared_area = -1;
|
||||
di->si = NULL;
|
||||
|
||||
unlock_and_exit:
|
||||
/* mark the device available */
|
||||
di->is_open--;
|
||||
/* unlock the driver */
|
||||
RELEASE_BEN(pd->kernel);
|
||||
ddprintf(("SKD free_hook() ends.\n"));
|
||||
/* all done */
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* -----------
|
||||
control_hook - where the real work is done
|
||||
----------- */
|
||||
static status_t
|
||||
control_hook (void* dev, uint32 msg, void *buf, size_t len) {
|
||||
device_info *di = (device_info *)dev;
|
||||
status_t result = B_DEV_INVALID_IOCTL;
|
||||
|
||||
/* ddprintf(("ioctl: %d, buf: 0x%08x, len: %d\n", msg, buf, len));*/
|
||||
switch (msg) {
|
||||
/* the only PUBLIC ioctl */
|
||||
case B_GET_ACCELERANT_SIGNATURE: {
|
||||
char *sig = (char *)buf;
|
||||
strcpy(sig, "atimach64vt.accelerant");
|
||||
result = B_OK;
|
||||
} break;
|
||||
|
||||
/* PRIVATE ioctl from here on */
|
||||
case ATIMACH64_GET_PRIVATE_DATA: {
|
||||
atimach64_get_private_data *gpd = (atimach64_get_private_data *)buf;
|
||||
if (gpd->magic == ATIMACH64_PRIVATE_DATA_MAGIC) {
|
||||
gpd->shared_info_area = di->shared_area;
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
case ATIMACH64_GET_PCI: {
|
||||
atimach64_get_set_pci *gsp = (atimach64_get_set_pci *)buf;
|
||||
if (gsp->magic == ATIMACH64_PRIVATE_DATA_MAGIC) {
|
||||
pci_info *pcii = &(di->pcii);
|
||||
gsp->value = get_pci(gsp->offset, gsp->size);
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
case ATIMACH64_SET_PCI: {
|
||||
atimach64_get_set_pci *gsp = (atimach64_get_set_pci *)buf;
|
||||
if (gsp->magic == ATIMACH64_PRIVATE_DATA_MAGIC) {
|
||||
pci_info *pcii = &(di->pcii);
|
||||
set_pci(gsp->offset, gsp->size, gsp->value);
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
case ATIMACH64_RUN_INTERRUPTS: {
|
||||
atimach64_set_bool_state *ri = (atimach64_set_bool_state *)buf;
|
||||
if (ri->magic == ATIMACH64_PRIVATE_DATA_MAGIC) {
|
||||
/* are we faking interrupts? */
|
||||
if ((di->pcii.u.h0.interrupt_pin == 0x00) || (di->pcii.u.h0.interrupt_line == 0xff)){
|
||||
di->can_interrupt = ri->do_it;
|
||||
} else {
|
||||
vuint32 *regs = di->regs;
|
||||
if (ri->do_it) {
|
||||
/* resume interrupts */
|
||||
*regs = *regs; /* CHANGE ME */
|
||||
} else {
|
||||
/* disable interrupts */
|
||||
*regs = *regs; /* CHANGE ME */
|
||||
}
|
||||
}
|
||||
result = B_OK;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -1,256 +0,0 @@
|
|||
/* All this code belongs to Linux Xfree86 Project with lots of modifications */
|
||||
/*
|
||||
Rene MacKinney <rene_@freenet.co.uk>
|
||||
|
||||
7.May.99
|
||||
*/
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include "DriverInterface.h"
|
||||
#include "regmach64.h"
|
||||
#include "string.h"
|
||||
|
||||
#if DEBUG > 0
|
||||
#define ddprintf(a) dprintf a
|
||||
#else
|
||||
#define ddprintf(a)
|
||||
#endif
|
||||
|
||||
status_t
|
||||
GetATIInfo(si)
|
||||
shared_info *si;
|
||||
{
|
||||
char signature[] = " 761295520";
|
||||
char *bios_data = rommem(0x00);
|
||||
char bios_signature[10];
|
||||
unsigned short *sbios_data = (unsigned short *)bios_data;
|
||||
int tmp,i,j;
|
||||
int ROM_Table_Offset;
|
||||
int Freq_Table_Ptr;
|
||||
int CDepth_Table_Ptr;
|
||||
int CTable_Size;
|
||||
|
||||
|
||||
if (si->rom == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
memcpy(bios_signature, rommem(0x30), 10);
|
||||
|
||||
if (strncmp( signature, bios_signature, 10 )) {
|
||||
ddprintf(("Mach64 probe failed on BIOS signature\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
si->board_identifier[0] = bios_data[ 0x40 ];
|
||||
si->board_identifier[1] = bios_data[ 0x41 ];
|
||||
si->equipment_flags[0] = bios_data[ 0x42 ];
|
||||
si->equipment_flags[1] = bios_data[ 0x44 ];
|
||||
si->asic_identifier = bios_data[ 0x43 ];
|
||||
si->bios_major = bios_data[ 0x4c ];
|
||||
si->bios_minor = bios_data[ 0x4d ];
|
||||
strncpy( si->bios_date, bios_data + 0x50, 20 );
|
||||
|
||||
si->VGA_Wonder_Present = bios_data[ 0x44 ] & 0x40;
|
||||
|
||||
si->Mach64_Present = 1; /* Test for Mach64 product */
|
||||
|
||||
tmp = inw(SCRATCH_REG0);
|
||||
|
||||
|
||||
outw(SCRATCH_REG0, 0x55555555);
|
||||
if (inw(SCRATCH_REG0) != 0x55555555) {
|
||||
si->Mach64_Present = 0;
|
||||
ddprintf(("Mach64 probe failed on read 1 of SCRATCH_REG0 %x\n",
|
||||
SCRATCH_REG0));
|
||||
} else {
|
||||
outw(SCRATCH_REG0, 0xaaaaaaaa);
|
||||
if (inw(SCRATCH_REG0) != 0xaaaaaaaa) {
|
||||
si->Mach64_Present = 0;
|
||||
ddprintf(("Mach64 probe failed on read 2 of SCRATCH_REG0 %x\n",
|
||||
SCRATCH_REG0));
|
||||
}
|
||||
}
|
||||
|
||||
outw(SCRATCH_REG0, tmp);
|
||||
|
||||
if (!si->Mach64_Present)
|
||||
return B_ERROR;
|
||||
|
||||
tmp = inw(CONFIG_CHIP_ID);
|
||||
if (si->device_id != (tmp & CFG_CHIP_TYPE)) {
|
||||
ddprintf(("%x %x: Mach64 chipset mismatch",
|
||||
si->device_id, tmp & CFG_CHIP_TYPE));
|
||||
return(B_ERROR);
|
||||
}
|
||||
|
||||
ddprintf(("CONFIG_CHIP_ID reports: %x rev %d\n",
|
||||
si->device_id, si->revision));
|
||||
|
||||
tmp = inw(CONFIG_STAT0);
|
||||
if (si->device_id == MACH64_GX_ID || si->device_id == MACH64_CX_ID) {
|
||||
si->Bus_Type = tmp & CFG_BUS_TYPE;
|
||||
si->Mem_Type = (tmp & CFG_MEM_TYPE) >> 3;
|
||||
si->DAC_Type = (tmp & CFG_INIT_DAC_TYPE) >> 9;
|
||||
si->DAC_SubType = (inb(SCRATCH_REG1+1) & 0xf0) | si->DAC_Type;
|
||||
} else {
|
||||
si->Mem_Type = tmp & CFG_MEM_TYPE_xT;
|
||||
si->DAC_Type = DAC_INTERNAL;
|
||||
si->DAC_SubType = DAC_INTERNAL;
|
||||
|
||||
ddprintf(("CONFIG_STAT0 reports mem type %d\n", si->Mem_Type));
|
||||
ddprintf(("CONFIG_STAT0 is 0x%08x\n", tmp));
|
||||
}
|
||||
|
||||
/* The copy of the registers starts at 0x7ffc00 or 0x3ffc00 depending on the
|
||||
memory on the card */
|
||||
|
||||
tmp = inw(MEM_CNTL);
|
||||
if (si->device_id == MACH64_GX_ID ||
|
||||
si->device_id == MACH64_CX_ID ||
|
||||
si->device_id == MACH64_CT_ID ||
|
||||
si->device_id == MACH64_ET_ID ||
|
||||
((si->device_id == MACH64_VT_ID || si->device_id == MACH64_GT_ID) &&
|
||||
!(si->revision & 0x07))) {
|
||||
switch (tmp & MEM_SIZE_ALIAS) {
|
||||
case MEM_SIZE_512K:
|
||||
si->mem_size = 512 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_1M:
|
||||
si->mem_size = 1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_2M:
|
||||
si->mem_size = 2*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_4M:
|
||||
si->mem_size = 4*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_6M:
|
||||
si->mem_size = 6*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_8M:
|
||||
si->mem_size = 8*1024 * 1024;
|
||||
break;
|
||||
}
|
||||
si->Mem_Size = tmp & MEM_SIZE_ALIAS;
|
||||
} else {
|
||||
switch (tmp & MEM_SIZE_ALIAS_GTB) {
|
||||
case MEM_SIZE_512K:
|
||||
si->mem_size = 512 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_1M:
|
||||
si->mem_size = 1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_2M_GTB:
|
||||
si->mem_size = 2*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_4M_GTB:
|
||||
si->mem_size = 4*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_6M_GTB:
|
||||
si->mem_size = 6*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_8M_GTB:
|
||||
si->mem_size = 8*1024 * 1024;
|
||||
break;
|
||||
case MEM_SIZE_16M_GTB:
|
||||
si->mem_size = 16*1024 * 1024;
|
||||
break;
|
||||
}
|
||||
si->Mem_Size = tmp & MEM_SIZE_ALIAS_GTB;
|
||||
}
|
||||
|
||||
ddprintf(("Card Reports 0x%08x Memory\n", si->mem_size));
|
||||
|
||||
ROM_Table_Offset = sbios_data[0x48 >> 1];
|
||||
Freq_Table_Ptr = sbios_data[(ROM_Table_Offset >> 1) + 8];
|
||||
si->Clock_Type = bios_data[Freq_Table_Ptr];
|
||||
|
||||
si->MinFreq = sbios_data[(Freq_Table_Ptr >> 1) + 1];
|
||||
si->MaxFreq = sbios_data[(Freq_Table_Ptr >> 1) + 2];
|
||||
si->RefFreq = sbios_data[(Freq_Table_Ptr >> 1) + 4];
|
||||
si->RefDivider = sbios_data[(Freq_Table_Ptr >> 1) + 5];
|
||||
si->NAdj = sbios_data[(Freq_Table_Ptr >> 1) + 6];
|
||||
si->DRAMMemClk = sbios_data[(Freq_Table_Ptr >> 1) + 8];
|
||||
si->VRAMMemClk = sbios_data[(Freq_Table_Ptr >> 1) + 9];
|
||||
si->MemClk = bios_data[Freq_Table_Ptr + 22];
|
||||
si->CXClk = bios_data[Freq_Table_Ptr + 6];
|
||||
|
||||
CDepth_Table_Ptr = sbios_data[(Freq_Table_Ptr >> 1) - 3];
|
||||
Freq_Table_Ptr = sbios_data[(Freq_Table_Ptr >> 1) - 1];
|
||||
|
||||
for (i = 0; i < MACH64_NUM_CLOCKS; i++)
|
||||
si->Clocks[i] = sbios_data[(Freq_Table_Ptr >> 1) + i];
|
||||
|
||||
si->MemCycle = bios_data[ROM_Table_Offset + 0];
|
||||
|
||||
CTable_Size = bios_data[CDepth_Table_Ptr - 1];
|
||||
for (i = 0, j = 0;
|
||||
bios_data[CDepth_Table_Ptr + i] != 0;
|
||||
i += CTable_Size, j++) {
|
||||
si->Freq_Table[j].h_disp = bios_data[CDepth_Table_Ptr + i];
|
||||
si->Freq_Table[j].dacmask = bios_data[CDepth_Table_Ptr + i + 1];
|
||||
si->Freq_Table[j].ram_req = bios_data[CDepth_Table_Ptr + i + 2];
|
||||
si->Freq_Table[j].max_dot_clock = bios_data[CDepth_Table_Ptr + i + 3];
|
||||
si->Freq_Table[j].color_depth = bios_data[CDepth_Table_Ptr + i + 4];
|
||||
switch(si->Freq_Table[j].color_depth) {
|
||||
case 2: /* 8 Bit */
|
||||
si->pix_clk_max8 = max(si->pix_clk_max8, si->Freq_Table[j].max_dot_clock);
|
||||
break;
|
||||
case 4: /* 16 Bit */
|
||||
si->pix_clk_max16 = max(si->pix_clk_max16, si->Freq_Table[j].max_dot_clock);
|
||||
break;
|
||||
case 6: /* 8 Bit */
|
||||
si->pix_clk_max32 = max(si->pix_clk_max32, si->Freq_Table2[j].max_dot_clock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
si->Freq_Table[j].h_disp = 0;
|
||||
|
||||
if (bios_data[CDepth_Table_Ptr + i + 1] != 0) {
|
||||
CDepth_Table_Ptr += i + 2;
|
||||
CTable_Size = bios_data[CDepth_Table_Ptr - 1];
|
||||
for (i = 0, j = 0;
|
||||
bios_data[CDepth_Table_Ptr + i] != 0;
|
||||
i += CTable_Size, j++) {
|
||||
si->Freq_Table2[j].h_disp = bios_data[CDepth_Table_Ptr + i];
|
||||
si->Freq_Table2[j].dacmask = bios_data[CDepth_Table_Ptr + i +
|
||||
1];
|
||||
si->Freq_Table2[j].ram_req = bios_data[CDepth_Table_Ptr + i +
|
||||
2];
|
||||
si->Freq_Table2[j].max_dot_clock = bios_data[CDepth_Table_Ptr + i +
|
||||
3];
|
||||
si->Freq_Table2[j].color_depth = bios_data[CDepth_Table_Ptr + i +
|
||||
4];
|
||||
switch(si->Freq_Table[j].color_depth) {
|
||||
case 2: /* 8 Bit */
|
||||
si->pix_clk_max8 = max(si->pix_clk_max8, si->Freq_Table2[j].max_dot_clock);
|
||||
break;
|
||||
case 4: /* 16 Bit */
|
||||
si->pix_clk_max16 = max(si->pix_clk_max16, si->Freq_Table2[j].max_dot_clock);
|
||||
break;
|
||||
case 6: /* 8 Bit */
|
||||
si->pix_clk_max32 = max(si->pix_clk_max32, si->Freq_Table2[j].max_dot_clock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
si->Freq_Table2[j].h_disp = 0;
|
||||
} else
|
||||
si->Freq_Table2[0].h_disp = 0;
|
||||
|
||||
/* Hardwired 120000 for 8bpp and 80000 for the rest */
|
||||
|
||||
ddprintf(("Clocks %ld %ld %ld\n",si->pix_clk_max32,
|
||||
si->pix_clk_max16, si->pix_clk_max8));
|
||||
|
||||
|
||||
si->pix_clk_max32 = 80000;
|
||||
si->pix_clk_max16 = 80000;
|
||||
si->pix_clk_max8 = 120000;
|
||||
|
||||
|
||||
ddprintf(("Clocks %ld %ld %ld\n",si->pix_clk_max32,
|
||||
si->pix_clk_max16, si->pix_clk_max8));
|
||||
|
||||
|
||||
return B_OK;
|
||||
}
|
Loading…
Reference in New Issue