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:
Rene Gollent 2009-06-05 02:50:25 +00:00
parent cb8948154c
commit 80829ec813
45 changed files with 5446 additions and 5884 deletions

View File

@ -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

View File

@ -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 ;

View File

@ -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
;

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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__

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 ++;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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__

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 ++;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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 ;

View File

@ -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;
}
}

View File

@ -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

View File

@ -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
);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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 ;

View File

@ -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

View File

@ -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.

View File

@ -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
;

View File

@ -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;
}

View File

@ -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;
}