* introduce mc control calls
* malloc storage for mc state info * redo pll range struct * change to ATOM_ENCODER_MODE for connector info * redo pll calculations to match AtomBIOS requirements * some structure changes * no longer init already posted AtomBIOS as it causes an infinite loop of AtomBIOS calls git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42644 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -51,15 +51,6 @@
|
||||
#define RHD_POWER_UNKNOWN 3 /* initial state */
|
||||
|
||||
|
||||
// info about PLL on graphics card
|
||||
struct pll_info {
|
||||
uint32 reference_frequency;
|
||||
uint32 max_frequency;
|
||||
uint32 min_frequency;
|
||||
uint32 divisor_register;
|
||||
};
|
||||
|
||||
|
||||
struct ring_buffer {
|
||||
struct lock lock;
|
||||
uint32 register_base;
|
||||
@@ -129,7 +120,6 @@ struct radeon_shared_info {
|
||||
|
||||
uint16 device_chipset;
|
||||
char device_identifier[32];
|
||||
struct pll_info pll_info;
|
||||
};
|
||||
|
||||
//----------------- ioctl() interface ----------------
|
||||
@@ -171,10 +161,40 @@ struct radeon_free_graphics_memory {
|
||||
#define R6XX_CONFIG_APER_SIZE 0x5430 // r600>
|
||||
#define OLD_CONFIG_APER_SIZE 0x0108 // <r600
|
||||
|
||||
#define R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914
|
||||
#define R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c
|
||||
#define R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114
|
||||
#define R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c
|
||||
#define D1CRTC_CONTROL 0x6080
|
||||
#define CRTC_EN (1 << 0)
|
||||
#define D1CRTC_STATUS 0x609c
|
||||
#define D1CRTC_UPDATE_LOCK 0x60E8
|
||||
#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110
|
||||
#define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118
|
||||
#define D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914 // r700>
|
||||
#define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c // r700>
|
||||
|
||||
#define D2CRTC_CONTROL 0x6880
|
||||
#define D2CRTC_STATUS 0x689c
|
||||
#define D2CRTC_UPDATE_LOCK 0x68E8
|
||||
#define D2GRPH_PRIMARY_SURFACE_ADDRESS 0x6910
|
||||
#define D2GRPH_SECONDARY_SURFACE_ADDRESS 0x6918
|
||||
#define D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114 // r700>
|
||||
#define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c // r700>
|
||||
|
||||
#define D1VGA_CONTROL 0x0330
|
||||
#define DVGA_CONTROL_MODE_ENABLE (1 << 0)
|
||||
#define DVGA_CONTROL_TIMING_SELECT (1 << 8)
|
||||
#define DVGA_CONTROL_SYNC_POLARITY_SELECT (1 << 9)
|
||||
#define DVGA_CONTROL_OVERSCAN_TIMING_SELECT (1 << 10)
|
||||
#define DVGA_CONTROL_OVERSCAN_COLOR_EN (1 << 16)
|
||||
#define DVGA_CONTROL_ROTATE (1 << 24)
|
||||
#define D2VGA_CONTROL 0x0338
|
||||
|
||||
#define VGA_HDP_CONTROL 0x328
|
||||
#define VGA_MEM_PAGE_SELECT_EN (1 << 0)
|
||||
#define VGA_MEMORY_DISABLE (1 << 4)
|
||||
#define VGA_RBBM_LOCK_DISABLE (1 << 8)
|
||||
#define VGA_SOFT_RESET (1 << 16)
|
||||
#define VGA_MEMORY_BASE_ADDRESS 0x0310
|
||||
#define VGA_RENDER_CONTROL 0x0300
|
||||
#define VGA_VSTATUS_CNTL_MASK 0x00030000
|
||||
|
||||
// cursor
|
||||
#define RADEON_CURSOR_CONTROL 0x70080
|
||||
|
||||
@@ -108,6 +108,8 @@ init_common(int device, bool isClone)
|
||||
|
||||
memset(gInfo, 0, sizeof(accelerant_info));
|
||||
|
||||
gInfo->mc_info = (gpu_mc_info *)malloc(sizeof(gpu_mc_info));
|
||||
|
||||
for (uint32 id = 0; id < MAX_DISPLAY; id++) {
|
||||
gDisplay[id] = (display_info *)malloc(sizeof(display_info));
|
||||
if (gDisplay[id] == NULL)
|
||||
@@ -130,6 +132,7 @@ init_common(int device, bool isClone)
|
||||
|
||||
if (ioctl(device, RADEON_GET_PRIVATE_DATA, &data,
|
||||
sizeof(radeon_get_private_data)) != 0) {
|
||||
free(gInfo->mc_info);
|
||||
free(gInfo);
|
||||
return B_ERROR;
|
||||
}
|
||||
@@ -140,6 +143,7 @@ init_common(int device, bool isClone)
|
||||
data.shared_info_area);
|
||||
status_t status = sharedCloner.InitCheck();
|
||||
if (status < B_OK) {
|
||||
free(gInfo->mc_info);
|
||||
free(gInfo);
|
||||
TRACE("%s, failed to create shared area\n", __func__);
|
||||
return status;
|
||||
@@ -151,6 +155,7 @@ init_common(int device, bool isClone)
|
||||
gInfo->shared_info->registers_area);
|
||||
status = regsCloner.InitCheck();
|
||||
if (status < B_OK) {
|
||||
free(gInfo->mc_info);
|
||||
free(gInfo);
|
||||
TRACE("%s, failed to create mmio area\n", __func__);
|
||||
return status;
|
||||
@@ -171,12 +176,6 @@ init_common(int device, bool isClone)
|
||||
sharedCloner.Keep();
|
||||
regsCloner.Keep();
|
||||
|
||||
// Define Radeon PLL default ranges
|
||||
gInfo->shared_info->pll_info.reference_frequency
|
||||
= RHD_PLL_REFERENCE_DEFAULT;
|
||||
gInfo->shared_info->pll_info.min_frequency = RHD_PLL_MIN_DEFAULT;
|
||||
gInfo->shared_info->pll_info.max_frequency = RHD_PLL_MAX_DEFAULT;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -196,6 +195,7 @@ uninit_common(void)
|
||||
if (gInfo->is_clone)
|
||||
close(gInfo->device);
|
||||
|
||||
free(gInfo->mc_info);
|
||||
free(gInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,16 @@
|
||||
// Maximum displays (more then two requires AtomBIOS)
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32 d1vga_control;
|
||||
uint32 d2vga_control;
|
||||
uint32 vga_render_control;
|
||||
uint32 vga_hdp_control;
|
||||
uint32 d1crtc_control;
|
||||
uint32 d2crtc_control;
|
||||
} gpu_mc_info;
|
||||
|
||||
|
||||
struct accelerant_info {
|
||||
vuint8 *regs;
|
||||
area_id regs_area;
|
||||
@@ -46,6 +56,8 @@ struct accelerant_info {
|
||||
int device;
|
||||
bool is_clone;
|
||||
|
||||
gpu_mc_info *mc_info; // used for last known mc state
|
||||
|
||||
// LVDS panel mode passed from the bios/startup.
|
||||
display_mode lvds_panel_mode;
|
||||
};
|
||||
@@ -91,6 +103,41 @@ struct register_info {
|
||||
};
|
||||
|
||||
|
||||
struct pll_info {
|
||||
/* reference frequency */
|
||||
uint32 reference_freq;
|
||||
|
||||
/* fixed dividers */
|
||||
uint32 reference_div;
|
||||
uint32 post_div;
|
||||
|
||||
/* pll in/out limits */
|
||||
uint32 pll_in_min;
|
||||
uint32 pll_in_max;
|
||||
uint32 pll_out_min;
|
||||
uint32 pll_out_max;
|
||||
uint32 lcd_pll_out_min;
|
||||
uint32 lcd_pll_out_max;
|
||||
uint32 best_vco;
|
||||
|
||||
/* divider limits */
|
||||
uint32 min_ref_div;
|
||||
uint32 max_ref_div;
|
||||
uint32 min_post_div;
|
||||
uint32 max_post_div;
|
||||
uint32 min_feedback_div;
|
||||
uint32 max_feedback_div;
|
||||
uint32 min_frac_feedback_div;
|
||||
uint32 max_frac_feedback_div;
|
||||
|
||||
/* flags for the current clock */
|
||||
uint32 flags;
|
||||
|
||||
/* pll id */
|
||||
uint32 id;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
uint32 connection_type;
|
||||
@@ -101,24 +148,19 @@ typedef struct {
|
||||
uint32 vfreq_min;
|
||||
uint32 hfreq_max;
|
||||
uint32 hfreq_min;
|
||||
pll_info pll;
|
||||
} display_info;
|
||||
|
||||
|
||||
// display_info connection_type
|
||||
#define CONNECTION_DAC 0x0001
|
||||
#define CONNECTION_TMDS 0x0002
|
||||
#define CONNECTION_LVDS 0x0004
|
||||
|
||||
// register MMIO modes
|
||||
#define OUT 0x1 // direct MMIO calls
|
||||
#define CRT 0x2 // crt controler calls
|
||||
#define VGA 0x3 // vga calls
|
||||
#define OUT 0x1 // Direct MMIO calls
|
||||
#define CRT 0x2 // Crt controller calls
|
||||
#define VGA 0x3 // Vga calls
|
||||
#define PLL 0x4 // PLL calls
|
||||
#define MC 0x5 // Memory Controler calls
|
||||
#define MC 0x5 // Memory controller calls
|
||||
|
||||
|
||||
extern accelerant_info *gInfo;
|
||||
//extern void *gAtomBIOS;
|
||||
extern atom_context *gAtomContext;
|
||||
extern display_info *gDisplay[MAX_DISPLAY];
|
||||
|
||||
@@ -139,22 +181,6 @@ _write32(uint32 offset, uint32 value)
|
||||
}
|
||||
|
||||
|
||||
inline uint32
|
||||
_read32PLL(uint16 offset)
|
||||
{
|
||||
_write32(CLOCK_CNTL_INDEX, offset & PLL_ADDR);
|
||||
return _read32(CLOCK_CNTL_DATA);
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
_write32PLL(uint16 offset, uint32 data)
|
||||
{
|
||||
_write32(CLOCK_CNTL_INDEX, (offset & PLL_ADDR) | PLL_WR_EN);
|
||||
_write32(CLOCK_CNTL_DATA, data);
|
||||
}
|
||||
|
||||
|
||||
inline uint32
|
||||
Read32(uint32 subsystem, uint32 offset)
|
||||
{
|
||||
@@ -162,13 +188,11 @@ Read32(uint32 subsystem, uint32 offset)
|
||||
default:
|
||||
case OUT:
|
||||
case VGA:
|
||||
case MC:
|
||||
return _read32(offset);
|
||||
case CRT:
|
||||
return _read32(offset);
|
||||
case PLL:
|
||||
return _read32(offset);
|
||||
//return _read32PLL(offset);
|
||||
case MC:
|
||||
return _read32(offset);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -180,15 +204,12 @@ Write32(uint32 subsystem, uint32 offset, uint32 value)
|
||||
default:
|
||||
case OUT:
|
||||
case VGA:
|
||||
case MC:
|
||||
_write32(offset, value);
|
||||
return;
|
||||
case CRT:
|
||||
_write32(offset, value);
|
||||
return;
|
||||
case PLL:
|
||||
_write32(offset, value);
|
||||
//_write32PLL(offset, value);
|
||||
return;
|
||||
case MC:
|
||||
_write32(offset, value);
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -59,6 +59,51 @@ radeon_bios_init_scratch()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
radeon_bios_isposted()
|
||||
{
|
||||
// aka, is primary graphics card that POST loaded
|
||||
|
||||
radeon_shared_info &info = *gInfo->shared_info;
|
||||
uint32 reg;
|
||||
|
||||
if (info.device_chipset == (RADEON_R1000 | 0x50)) {
|
||||
// palms
|
||||
reg = Read32(OUT, EVERGREEN_CRTC_CONTROL
|
||||
+ EVERGREEN_CRTC0_REGISTER_OFFSET)
|
||||
| Read32(OUT, EVERGREEN_CRTC_CONTROL
|
||||
+ EVERGREEN_CRTC1_REGISTER_OFFSET);
|
||||
if (reg & EVERGREEN_CRTC_MASTER_EN)
|
||||
return true;
|
||||
} else if (info.device_chipset >= RADEON_R1000) {
|
||||
// evergreen or higher
|
||||
reg = Read32(OUT, EVERGREEN_CRTC_CONTROL
|
||||
+ EVERGREEN_CRTC0_REGISTER_OFFSET)
|
||||
| Read32(OUT, EVERGREEN_CRTC_CONTROL
|
||||
+ EVERGREEN_CRTC1_REGISTER_OFFSET)
|
||||
| Read32(OUT, EVERGREEN_CRTC_CONTROL
|
||||
+ EVERGREEN_CRTC2_REGISTER_OFFSET)
|
||||
| Read32(OUT, EVERGREEN_CRTC_CONTROL
|
||||
+ EVERGREEN_CRTC3_REGISTER_OFFSET)
|
||||
| Read32(OUT, EVERGREEN_CRTC_CONTROL
|
||||
+ EVERGREEN_CRTC4_REGISTER_OFFSET)
|
||||
| Read32(OUT, EVERGREEN_CRTC_CONTROL
|
||||
+ EVERGREEN_CRTC5_REGISTER_OFFSET);
|
||||
if (reg & EVERGREEN_CRTC_MASTER_EN)
|
||||
return true;
|
||||
} else if (info.device_chipset > RADEON_R580) {
|
||||
// avivio through r700
|
||||
reg = Read32(OUT, AVIVO_D1CRTC_CONTROL) |
|
||||
Read32(OUT, AVIVO_D2CRTC_CONTROL);
|
||||
if (reg & AVIVO_CRTC_EN) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
radeon_init_bios(uint8* bios)
|
||||
{
|
||||
@@ -114,12 +159,16 @@ radeon_init_bios(uint8* bios)
|
||||
radeon_bios_init_scratch();
|
||||
atom_allocate_fb_scratch(gAtomContext);
|
||||
|
||||
// TODO : this is only *required* on cards <= r500
|
||||
// is it ok to run on cards > r500 before asic_init?
|
||||
radeon_gpu_reset();
|
||||
|
||||
atom_asic_init(gAtomContext);
|
||||
// Post card
|
||||
// post card atombios if needed
|
||||
if (!radeon_bios_isposted()) {
|
||||
TRACE("%s: init AtomBIOS for this card as it is not not posted\n",
|
||||
__func__);
|
||||
// radeon_gpu_reset(); // <= r500 only?
|
||||
atom_asic_init(gAtomContext);
|
||||
} else {
|
||||
TRACE("%s: AtomBIOS is already posted\n",
|
||||
__func__);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
|
||||
status_t radeon_init_bios(uint8* bios);
|
||||
bool radeon_bios_isposted();
|
||||
status_t radeon_dump_bios();
|
||||
|
||||
|
||||
|
||||
@@ -112,11 +112,11 @@ init_registers(register_info* regs, uint8 crtid)
|
||||
|
||||
// Surface Address high only used on r770+
|
||||
regs->grphPrimarySurfaceAddrHigh
|
||||
= crtid == 1 ? R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH
|
||||
: R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH;
|
||||
= crtid == 1 ? D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH
|
||||
: D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH;
|
||||
regs->grphSecondarySurfaceAddrHigh
|
||||
= crtid == 1 ? R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH
|
||||
: R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH;
|
||||
= crtid == 1 ? D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH
|
||||
: D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH;
|
||||
|
||||
regs->grphPitch
|
||||
= crtid == 1 ? D2GRPH_PITCH : D1GRPH_PITCH;
|
||||
@@ -233,7 +233,7 @@ detect_displays()
|
||||
for (uint32 id = 0; id < 2; id++) {
|
||||
if (DACSense(id)) {
|
||||
gDisplay[index]->active = true;
|
||||
gDisplay[index]->connection_type = CONNECTION_DAC;
|
||||
gDisplay[index]->connection_type = ATOM_ENCODER_MODE_CRT;
|
||||
gDisplay[index]->connection_id = id;
|
||||
init_registers(gDisplay[index]->regs, index);
|
||||
if (detect_crt_ranges(index) == B_OK)
|
||||
@@ -250,7 +250,8 @@ detect_displays()
|
||||
for (uint32 id = 0; id < 1; id++) {
|
||||
if (TMDSSense(id)) {
|
||||
gDisplay[index]->active = true;
|
||||
gDisplay[index]->connection_type = CONNECTION_TMDS;
|
||||
gDisplay[index]->connection_type = ATOM_ENCODER_MODE_DVI;
|
||||
// or ATOM_ENCODER_MODE_HDMI?
|
||||
gDisplay[index]->connection_id = id;
|
||||
init_registers(gDisplay[index]->regs, index);
|
||||
if (detect_crt_ranges(index) == B_OK)
|
||||
@@ -266,7 +267,7 @@ detect_displays()
|
||||
// No monitors? Lets assume LVDS for now
|
||||
if (index == 0) {
|
||||
gDisplay[index]->active = true;
|
||||
gDisplay[index]->connection_type = CONNECTION_LVDS;
|
||||
gDisplay[index]->connection_type = ATOM_ENCODER_MODE_LVDS;
|
||||
gDisplay[index]->connection_id = 1;
|
||||
// 0 : LVDSA ; 1 : LVDSB / TDMSB
|
||||
init_registers(gDisplay[index]->regs, index);
|
||||
@@ -285,14 +286,40 @@ debug_displays()
|
||||
id, gDisplay[id]->active ? "true" : "false");
|
||||
|
||||
if (gDisplay[id]->active) {
|
||||
if (gDisplay[id]->connection_type == CONNECTION_DAC)
|
||||
TRACE(" + connection: DAC\n");
|
||||
else if (gDisplay[id]->connection_type == CONNECTION_TMDS)
|
||||
TRACE(" + connection: TMDS\n");
|
||||
else if (gDisplay[id]->connection_type == CONNECTION_LVDS)
|
||||
TRACE(" + connection: LVDS\n");
|
||||
else
|
||||
TRACE(" + connection: UNKNOWN\n");
|
||||
switch (gDisplay[id]->connection_type) {
|
||||
case ATOM_ENCODER_MODE_DP:
|
||||
TRACE(" + connection: DP\n");
|
||||
break;
|
||||
case ATOM_ENCODER_MODE_LVDS:
|
||||
TRACE(" + connection: LVDS\n");
|
||||
break;
|
||||
case ATOM_ENCODER_MODE_DVI:
|
||||
TRACE(" + connection: DVI\n");
|
||||
break;
|
||||
case ATOM_ENCODER_MODE_HDMI:
|
||||
TRACE(" + connection: HDMI\n");
|
||||
break;
|
||||
case ATOM_ENCODER_MODE_SDVO:
|
||||
TRACE(" + connection: SDVO\n");
|
||||
break;
|
||||
case ATOM_ENCODER_MODE_DP_AUDIO:
|
||||
TRACE(" + connection: DP AUDIO\n");
|
||||
break;
|
||||
case ATOM_ENCODER_MODE_TV:
|
||||
TRACE(" + connection: TV\n");
|
||||
break;
|
||||
case ATOM_ENCODER_MODE_CV:
|
||||
TRACE(" + connection: CV\n");
|
||||
break;
|
||||
case ATOM_ENCODER_MODE_CRT:
|
||||
TRACE(" + connection: CRT\n");
|
||||
break;
|
||||
case ATOM_ENCODER_MODE_DVO:
|
||||
TRACE(" + connection: DVO\n");
|
||||
break;
|
||||
default:
|
||||
TRACE(" + connection: UNKNOWN\n");
|
||||
}
|
||||
|
||||
TRACE(" + connection index: % " B_PRIu8 "\n",
|
||||
gDisplay[id]->connection_id);
|
||||
|
||||
@@ -38,9 +38,10 @@ radeon_gpu_reset()
|
||||
|
||||
TRACE("%s: GPU software reset in progress...\n", __func__);
|
||||
|
||||
// TODO : mc stop
|
||||
// Halt memory controller
|
||||
radeon_gpu_mc_halt();
|
||||
|
||||
if (radeon_gpu_mc_idle() > 0) {
|
||||
if (radeon_gpu_mc_idlecheck() > 0) {
|
||||
ERROR("%s: Timeout waiting for MC to idle!\n", __func__);
|
||||
}
|
||||
|
||||
@@ -152,14 +153,66 @@ radeon_gpu_reset()
|
||||
snooze(50);
|
||||
}
|
||||
|
||||
|
||||
// TODO : mc resume
|
||||
// Resume memory controller
|
||||
radeon_gpu_mc_resume();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
radeon_gpu_mc_halt()
|
||||
{
|
||||
// Backup current memory controller state
|
||||
gInfo->mc_info->d1vga_control = Read32(OUT, D1VGA_CONTROL);
|
||||
gInfo->mc_info->d2vga_control = Read32(OUT, D2VGA_CONTROL);
|
||||
gInfo->mc_info->vga_render_control = Read32(OUT, VGA_RENDER_CONTROL);
|
||||
gInfo->mc_info->vga_hdp_control = Read32(OUT, VGA_HDP_CONTROL);
|
||||
gInfo->mc_info->d1crtc_control = Read32(OUT, D1CRTC_CONTROL);
|
||||
gInfo->mc_info->d2crtc_control = Read32(OUT, D2CRTC_CONTROL);
|
||||
|
||||
// halt all memory controller actions
|
||||
Write32(OUT, D2CRTC_UPDATE_LOCK, 0);
|
||||
Write32(OUT, VGA_RENDER_CONTROL, 0);
|
||||
Write32(OUT, D1CRTC_UPDATE_LOCK, 1);
|
||||
Write32(OUT, D2CRTC_UPDATE_LOCK, 1);
|
||||
Write32(OUT, D1CRTC_CONTROL, 0);
|
||||
Write32(OUT, D2CRTC_CONTROL, 0);
|
||||
Write32(OUT, D1CRTC_UPDATE_LOCK, 0);
|
||||
Write32(OUT, D2CRTC_UPDATE_LOCK, 0);
|
||||
Write32(OUT, D1VGA_CONTROL, 0);
|
||||
Write32(OUT, D2VGA_CONTROL, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
radeon_gpu_mc_resume()
|
||||
{
|
||||
// TODO : do surface addresses disappear on mc halt?
|
||||
//Write32(OUT, D1GRPH_PRIMARY_SURFACE_ADDRESS, rdev->mc.vram_start);
|
||||
//Write32(OUT, D1GRPH_SECONDARY_SURFACE_ADDRESS, rdev->mc.vram_start);
|
||||
//Write32(OUT, D2GRPH_PRIMARY_SURFACE_ADDRESS, rdev->mc.vram_start);
|
||||
//Write32(OUT, D2GRPH_SECONDARY_SURFACE_ADDRESS, rdev->mc.vram_start);
|
||||
//Write32(OUT, VGA_MEMORY_BASE_ADDRESS, rdev->mc.vram_start);
|
||||
|
||||
// Rnlock host access
|
||||
Write32(OUT, VGA_HDP_CONTROL, gInfo->mc_info->vga_hdp_control);
|
||||
snooze(1);
|
||||
|
||||
// Restore memory controller state
|
||||
Write32(OUT, D1VGA_CONTROL, gInfo->mc_info->d1vga_control);
|
||||
Write32(OUT, D2VGA_CONTROL, gInfo->mc_info->d2vga_control);
|
||||
Write32(OUT, D1CRTC_UPDATE_LOCK, 1);
|
||||
Write32(OUT, D2CRTC_UPDATE_LOCK, 1);
|
||||
Write32(OUT, D1CRTC_CONTROL, gInfo->mc_info->d1crtc_control);
|
||||
Write32(OUT, D2CRTC_CONTROL, gInfo->mc_info->d2crtc_control);
|
||||
Write32(OUT, D1CRTC_UPDATE_LOCK, 0);
|
||||
Write32(OUT, D2CRTC_UPDATE_LOCK, 0);
|
||||
Write32(OUT, VGA_RENDER_CONTROL, gInfo->mc_info->vga_render_control);
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
radeon_gpu_mc_idle()
|
||||
radeon_gpu_mc_idlecheck()
|
||||
{
|
||||
uint32 idleStatus;
|
||||
if (!((idleStatus = Read32(MC, SRBM_STATUS)) &
|
||||
@@ -176,13 +229,15 @@ radeon_gpu_mc_setup()
|
||||
{
|
||||
uint32 fb_location_int = gInfo->shared_info->frame_buffer_int;
|
||||
|
||||
uint32 fb_location = Read32(OUT, R6XX_MC_VM_FB_LOCATION);
|
||||
uint32 fb_location = Read32(OUT, R600_MC_VM_FB_LOCATION);
|
||||
uint16 fb_size = (fb_location >> 16) - (fb_location & 0xFFFF);
|
||||
uint32 fb_location_tmp = fb_location_int >> 24;
|
||||
fb_location_tmp |= (fb_location_tmp + fb_size) << 16;
|
||||
uint32 fb_offset_tmp = (fb_location_int >> 8) & 0xff0000;
|
||||
|
||||
uint32 idleState = radeon_gpu_mc_idle();
|
||||
radeon_gpu_mc_halt();
|
||||
|
||||
uint32 idleState = radeon_gpu_mc_idlecheck();
|
||||
if (idleState > 0) {
|
||||
TRACE("%s: Cannot modify non-idle MC! idleState: 0x%" B_PRIX32 "\n",
|
||||
__func__, idleState);
|
||||
@@ -194,8 +249,10 @@ radeon_gpu_mc_setup()
|
||||
__func__, fb_location, fb_location_tmp, fb_size);
|
||||
|
||||
// The MC Write32 will handle cards needing a special MC read/write register
|
||||
Write32(MC, R6XX_MC_VM_FB_LOCATION, fb_location_tmp);
|
||||
Write32(MC, R6XX_HDP_NONSURFACE_BASE, fb_offset_tmp);
|
||||
Write32(MC, R600_MC_VM_FB_LOCATION, fb_location_tmp);
|
||||
Write32(MC, R600_HDP_NONSURFACE_BASE, fb_offset_tmp);
|
||||
|
||||
radeon_gpu_mc_resume();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#define RADEON_HD_GPU_H
|
||||
|
||||
|
||||
#include "accelerant.h"
|
||||
|
||||
|
||||
// GPU Control registers. These are combined as
|
||||
// the registers exist on all models, some flags
|
||||
// are different though and are commented as such
|
||||
@@ -160,7 +163,9 @@
|
||||
|
||||
|
||||
status_t radeon_gpu_reset();
|
||||
uint32 radeon_gpu_mc_idle();
|
||||
void radeon_gpu_mc_halt();
|
||||
void radeon_gpu_mc_resume();
|
||||
uint32 radeon_gpu_mc_idlecheck();
|
||||
status_t radeon_gpu_mc_setup();
|
||||
status_t radeon_gpu_irq_setup();
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "utility.h"
|
||||
#include "mode.h"
|
||||
#include "display.h"
|
||||
#include "pll.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -108,8 +109,8 @@ radeon_set_display_mode(display_mode *mode)
|
||||
continue;
|
||||
}
|
||||
|
||||
//pll_set(gDisplay[id]->connection_id,
|
||||
// mode->timing.pixel_clock, id);
|
||||
pll_set(gDisplay[id]->connection_id,
|
||||
mode->timing.pixel_clock, id);
|
||||
|
||||
// Program CRT Controller
|
||||
display_crtc_set_dtd(id, mode);
|
||||
@@ -119,13 +120,14 @@ radeon_set_display_mode(display_mode *mode)
|
||||
|
||||
// Program connector controllers
|
||||
switch (gDisplay[id]->connection_type) {
|
||||
case CONNECTION_DAC:
|
||||
case ATOM_ENCODER_MODE_CRT:
|
||||
DACSet(gDisplay[id]->connection_id, id);
|
||||
break;
|
||||
case CONNECTION_TMDS:
|
||||
case ATOM_ENCODER_MODE_DVI:
|
||||
case ATOM_ENCODER_MODE_HDMI:
|
||||
TMDSSet(gDisplay[id]->connection_id, mode);
|
||||
break;
|
||||
case CONNECTION_LVDS:
|
||||
case ATOM_ENCODER_MODE_LVDS:
|
||||
LVDSSet(gDisplay[id]->connection_id, mode);
|
||||
break;
|
||||
}
|
||||
@@ -134,17 +136,19 @@ radeon_set_display_mode(display_mode *mode)
|
||||
display_crtc_blank(id, ATOM_DISABLE);
|
||||
display_crtc_power(id, ATOM_ENABLE);
|
||||
|
||||
PLLPower(gDisplay[id]->connection_id, RHD_POWER_ON);
|
||||
//PLLPower(gDisplay[id]->connection_id, RHD_POWER_ON);
|
||||
|
||||
// Power connector controllers
|
||||
switch (gDisplay[id]->connection_type) {
|
||||
case CONNECTION_DAC:
|
||||
case ATOM_ENCODER_MODE_CRT:
|
||||
DACPower(gDisplay[id]->connection_id, RHD_POWER_ON);
|
||||
break;
|
||||
case CONNECTION_TMDS:
|
||||
case ATOM_ENCODER_MODE_DVI:
|
||||
case ATOM_ENCODER_MODE_HDMI:
|
||||
TMDSPower(gDisplay[id]->connection_id, RHD_POWER_ON);
|
||||
break;
|
||||
case CONNECTION_LVDS:
|
||||
case ATOM_ENCODER_MODE_LVDS:
|
||||
LVDSSet(gDisplay[id]->connection_id, mode);
|
||||
LVDSPower(gDisplay[id]->connection_id, RHD_POWER_ON);
|
||||
break;
|
||||
}
|
||||
@@ -197,16 +201,16 @@ radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high)
|
||||
*(uint32)mode->timing.v_total;
|
||||
uint32 low = (totalClocks * 48L) / 1000L;
|
||||
|
||||
if (low < gInfo->shared_info->pll_info.min_frequency)
|
||||
low = gInfo->shared_info->pll_info.min_frequency;
|
||||
else if (low > gInfo->shared_info->pll_info.max_frequency)
|
||||
if (low < PLL_MIN_DEFAULT)
|
||||
low = PLL_MIN_DEFAULT;
|
||||
else if (low > PLL_MAX_DEFAULT)
|
||||
return B_ERROR;
|
||||
|
||||
*_low = low;
|
||||
}
|
||||
|
||||
if (_high != NULL)
|
||||
*_high = gInfo->shared_info->pll_info.max_frequency;
|
||||
*_high = PLL_MAX_DEFAULT;
|
||||
|
||||
//*_low = 48L;
|
||||
//*_high = 100 * 1000000L;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander von Gluck, kallisti5@unixzen.com
|
||||
* Alexander von Gluck, kallisti5@unixzen.com
|
||||
*/
|
||||
|
||||
|
||||
@@ -39,194 +39,129 @@ union set_pixel_clock {
|
||||
};
|
||||
|
||||
|
||||
/* From hardcoded values. */
|
||||
static struct PLL_Control RV610PLLControl[] =
|
||||
{
|
||||
{ 0x0049, 0x159F8704 },
|
||||
{ 0x006C, 0x159B8704 },
|
||||
{ 0xFFFF, 0x159EC704 }
|
||||
};
|
||||
|
||||
/* Some tables are provided by atombios,
|
||||
* it's just that they are hidden away deliberately and not exposed */
|
||||
static struct PLL_Control RV670PLLControl[] =
|
||||
{
|
||||
{ 0x004A, 0x159FC704 },
|
||||
{ 0x0067, 0x159BC704 },
|
||||
{ 0x00C4, 0x159EC704 },
|
||||
{ 0x00F4, 0x1593A704 },
|
||||
{ 0x0136, 0x1595A704 },
|
||||
{ 0x01A4, 0x1596A704 },
|
||||
{ 0x022C, 0x159CE504 },
|
||||
{ 0xFFFF, 0x1591E404 }
|
||||
};
|
||||
|
||||
|
||||
static uint32
|
||||
PLLControlTable(struct PLL_Control *table, uint16 feedbackDivider)
|
||||
pll_compute_post_divider(uint32 targetClock)
|
||||
{
|
||||
int i;
|
||||
radeon_shared_info &info = *gInfo->shared_info;
|
||||
|
||||
for (i = 0; table[i].feedbackDivider < 0xFFFF ; i++) {
|
||||
if (table[i].feedbackDivider >= feedbackDivider)
|
||||
break;
|
||||
// if RADEON_PLL_USE_POST_DIV
|
||||
// return pll->post_div;
|
||||
|
||||
uint32 vco;
|
||||
if (info.device_chipset < (RADEON_R700 | 0x70)) {
|
||||
if (0) // TODO : RADEON_PLL_IS_LCD
|
||||
vco = PLL_MIN_DEFAULT; // pll->lcd_pll_out_min;
|
||||
else
|
||||
vco = PLL_MIN_DEFAULT; // pll->pll_out_min;
|
||||
} else {
|
||||
if (0) // TODO : RADEON_PLL_IS_LCD
|
||||
vco = PLL_MAX_DEFAULT; // pll->lcd_pll_out_max;
|
||||
else
|
||||
vco = PLL_MAX_DEFAULT; // pll->pll_out_min;
|
||||
}
|
||||
|
||||
return table[i].control;
|
||||
uint32 postDivider = vco / targetClock;
|
||||
uint32 tmp = vco % targetClock;
|
||||
|
||||
if (info.device_chipset < (RADEON_R700 | 0x70)) {
|
||||
if (tmp)
|
||||
postDivider++;
|
||||
} else {
|
||||
if (!tmp)
|
||||
postDivider--;
|
||||
}
|
||||
|
||||
if (postDivider > POST_DIV_LIMIT)
|
||||
postDivider = POST_DIV_LIMIT;
|
||||
else if (postDivider < POST_DIV_MIN)
|
||||
postDivider = POST_DIV_MIN;
|
||||
|
||||
return postDivider;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PLLCalculate(uint32 pixelClock, uint16 *reference, uint16 *feedback,
|
||||
uint16 *post)
|
||||
pll_compute(uint32 pixelClock, uint32 *dotclockOut, uint32 *referenceOut,
|
||||
uint32 *feedbackOut, uint32 *feedbackFracOut, uint32 *postOut)
|
||||
{
|
||||
// Freaking phase-locked loops, how do they work?
|
||||
uint32 targetClock = pixelClock / 10;
|
||||
uint32 postDivider = pll_compute_post_divider(targetClock);
|
||||
uint32 referenceDivider = REF_DIV_MIN;
|
||||
uint32 feedbackDivider = 0;
|
||||
uint32 feedbackDividerFrac = 0;
|
||||
|
||||
float ratio = ((float) pixelClock)
|
||||
/ ((float) gInfo->shared_info->pll_info.reference_frequency);
|
||||
// if RADEON_PLL_USE_REF_DIV
|
||||
// ref_div = pll->reference_div;
|
||||
|
||||
uint32 bestDiff = 0xFFFFFFFF;
|
||||
uint32 postDiv;
|
||||
uint32 referenceDiv;
|
||||
uint32 feedbackDiv;
|
||||
// if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
|
||||
// avivo_get_fb_div(pll, targetClock, postDivider, referenceDivider,
|
||||
// &feedbackDivider, &feedbackDividerFrac);
|
||||
// feedbackDividerFrac = (100 * feedbackDividerFrac) / pll->reference_freq;
|
||||
// if (frac_fb_div >= 5) {
|
||||
// frac_fb_div -= 5;
|
||||
// frac_fb_div = frac_fb_div / 10;
|
||||
// frac_fb_div++;
|
||||
// }
|
||||
// if (frac_fb_div >= 10) {
|
||||
// fb_div++;
|
||||
// frac_fb_div = 0;
|
||||
// }
|
||||
// } else {
|
||||
while (referenceDivider <= REF_DIV_LIMIT) {
|
||||
// get feedback divider
|
||||
uint32 retroEncabulator = postDivider * referenceDivider;
|
||||
|
||||
for (postDiv = 2; postDiv < POST_DIV_LIMIT; postDiv++) {
|
||||
uint32 vcoOut = pixelClock * postDiv;
|
||||
retroEncabulator *= targetClock;
|
||||
feedbackDivider = retroEncabulator / PLL_REFERENCE_DEFAULT;
|
||||
feedbackDividerFrac = retroEncabulator % PLL_REFERENCE_DEFAULT;
|
||||
|
||||
/* we are conservative and avoid the limits */
|
||||
if (vcoOut <= gInfo->shared_info->pll_info.min_frequency)
|
||||
continue;
|
||||
if (vcoOut >= gInfo->shared_info->pll_info.max_frequency)
|
||||
break;
|
||||
if (feedbackDivider > FB_DIV_LIMIT)
|
||||
feedbackDivider = FB_DIV_LIMIT;
|
||||
else if (feedbackDivider < FB_DIV_MIN)
|
||||
feedbackDivider = FB_DIV_MIN;
|
||||
|
||||
for (referenceDiv = 1; referenceDiv <= REF_DIV_LIMIT; referenceDiv++) {
|
||||
feedbackDiv = (uint32)((ratio * postDiv * referenceDiv) + 0.5);
|
||||
if (feedbackDividerFrac >= (PLL_REFERENCE_DEFAULT / 2))
|
||||
feedbackDivider++;
|
||||
|
||||
if (feedbackDiv >= FB_DIV_LIMIT)
|
||||
break;
|
||||
if (feedbackDiv > (500 + (13 * referenceDiv))) // rv6x0 limit
|
||||
break;
|
||||
|
||||
uint32 diff = abs(pixelClock - (feedbackDiv
|
||||
* gInfo->shared_info->pll_info.reference_frequency)
|
||||
/ (postDiv * referenceDiv));
|
||||
|
||||
if (diff < bestDiff) {
|
||||
*feedback = feedbackDiv;
|
||||
*reference = referenceDiv;
|
||||
*post = postDiv;
|
||||
bestDiff = diff;
|
||||
feedbackDividerFrac = 0;
|
||||
if (referenceDivider == 0 || postDivider == 0 || targetClock == 0) {
|
||||
TRACE("%s: Caught division by zero\n",
|
||||
__func__);
|
||||
return B_ERROR;
|
||||
}
|
||||
uint32 tmp = (PLL_REFERENCE_DEFAULT * feedbackDivider)
|
||||
/ (postDivider * referenceDivider);
|
||||
tmp = (tmp * 10000) / targetClock;
|
||||
|
||||
if (bestDiff == 0)
|
||||
if (tmp > (10000 + MAX_TOLERANCE))
|
||||
referenceDivider++;
|
||||
else if (tmp >= (10000 - MAX_TOLERANCE))
|
||||
break;
|
||||
else
|
||||
referenceDivider++;
|
||||
}
|
||||
// }
|
||||
|
||||
if (bestDiff == 0)
|
||||
break;
|
||||
if (referenceDivider == 0 || postDivider == 0) {
|
||||
TRACE("%s: Caught division by zero of post or reference divider\n",
|
||||
__func__);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (bestDiff != 0xFFFFFFFF) {
|
||||
TRACE("%s: Successful PLL Calculation: %dkHz = "
|
||||
"(((%i / 0x%X) * 0x%X) / 0x%X) (%dkHz off)\n", __func__,
|
||||
(int) pixelClock,
|
||||
(unsigned int) gInfo->shared_info->pll_info.reference_frequency,
|
||||
*reference, *feedback, *post, (int) bestDiff);
|
||||
return B_OK;
|
||||
}
|
||||
*dotclockOut = ((PLL_REFERENCE_DEFAULT * feedbackDivider * 10)
|
||||
+ (PLL_REFERENCE_DEFAULT * feedbackDividerFrac))
|
||||
/ (referenceDivider * postDivider * 10);
|
||||
|
||||
// Shouldn't ever happen
|
||||
TRACE("%s: Failed to get a valid PLL setting for %dkHz\n",
|
||||
__func__, (int) pixelClock);
|
||||
return B_ERROR;
|
||||
}
|
||||
*feedbackOut = feedbackDivider;
|
||||
*feedbackFracOut = feedbackDividerFrac;
|
||||
*referenceOut = referenceDivider;
|
||||
*postOut = postDivider;
|
||||
|
||||
|
||||
status_t
|
||||
PLLPower(uint8 pllIndex, int command)
|
||||
{
|
||||
uint16 pllControlReg = pllIndex == 1 ? P2PLL_CNTL : P1PLL_CNTL;
|
||||
|
||||
bool hasDccg = DCCGCLKAvailable(pllIndex);
|
||||
|
||||
TRACE("%s: card has DCCG = %c\n", __func__, hasDccg ? 'y' : 'n');
|
||||
|
||||
switch (command) {
|
||||
case RHD_POWER_ON:
|
||||
{
|
||||
TRACE("%s: PLL %d Power On\n", __func__, pllIndex);
|
||||
|
||||
if (hasDccg)
|
||||
DCCGCLKSet(pllIndex, RV620_DCCGCLK_RESET);
|
||||
|
||||
Write32Mask(PLL, pllControlReg, 0, 0x02);
|
||||
// Power On
|
||||
snooze(2);
|
||||
PLLCalibrate(pllIndex);
|
||||
|
||||
if (hasDccg)
|
||||
DCCGCLKSet(pllIndex, RV620_DCCGCLK_GRAB);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
case RHD_POWER_RESET:
|
||||
{
|
||||
TRACE("%s: PLL %d Power Reset\n", __func__, pllIndex);
|
||||
|
||||
if (hasDccg)
|
||||
DCCGCLKSet(pllIndex, RV620_DCCGCLK_RELEASE);
|
||||
|
||||
Write32Mask(PLL, pllControlReg, 0x01, 0x01);
|
||||
// Reset
|
||||
snooze(2);
|
||||
Write32Mask(PLL, pllControlReg, 0, 0x02);
|
||||
// Power On
|
||||
snooze(2);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
case RHD_POWER_SHUTDOWN:
|
||||
default:
|
||||
TRACE("%s: PLL %d Power Shutdown\n", __func__, pllIndex);
|
||||
|
||||
radeon_shared_info &info = *gInfo->shared_info;
|
||||
|
||||
if (hasDccg)
|
||||
DCCGCLKSet(pllIndex, RV620_DCCGCLK_RELEASE);
|
||||
|
||||
Write32Mask(PLL, pllControlReg, 0x01, 0x01);
|
||||
// Reset
|
||||
snooze(2);
|
||||
|
||||
if (info.device_chipset >= (RADEON_R600 | 0x20)) {
|
||||
uint16 pllDiffPostReg
|
||||
= pllIndex == 1 ? RV620_EXT2_DIFF_POST_DIV_CNTL
|
||||
: RV620_EXT1_DIFF_POST_DIV_CNTL;
|
||||
uint16 pllDiffDriverEnable
|
||||
= pllIndex == 1 ? (uint16)RV62_EXT2_DIFF_DRIVER_ENABLE
|
||||
: (uint16)RV62_EXT1_DIFF_DRIVER_ENABLE;
|
||||
|
||||
// Sometimes we have to keep an unused PLL running. X Bug #18016
|
||||
if ((Read32(PLL, pllDiffPostReg)
|
||||
& pllDiffDriverEnable) == 0) {
|
||||
Write32Mask(PLL, pllControlReg, 0x02, 0x02);
|
||||
// Power Down
|
||||
} else {
|
||||
TRACE("%s: PHYA differential clock driver not disabled\n",
|
||||
__func__);
|
||||
}
|
||||
|
||||
snooze(200);
|
||||
|
||||
Write32Mask(PLL, pllControlReg, 0x2000, 0x2000);
|
||||
// Reset anti-glitch?
|
||||
|
||||
} else {
|
||||
Write32Mask(PLL, pllControlReg, 0x02, 0x02);
|
||||
// Power Down
|
||||
snooze(200);
|
||||
}
|
||||
}
|
||||
TRACE("%s: pixel clock: %" B_PRIu32 " gives:"
|
||||
" feedbackDivider = %" B_PRIu32 ".%" B_PRIu32
|
||||
"; referenceDivider = %" B_PRIu32 "; postDivider = %" B_PRIu32
|
||||
"; dotClock = %" B_PRIu32 "\n", __func__, pixelClock, feedbackDivider,
|
||||
feedbackDividerFrac, referenceDivider, postDivider, *dotclockOut);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -235,30 +170,29 @@ PLLPower(uint8 pllIndex, int command)
|
||||
status_t
|
||||
pll_set(uint8 pll_id, uint32 pixelClock, uint8 crtc_id)
|
||||
{
|
||||
uint16 reference = 0;
|
||||
uint16 feedback = 0;
|
||||
uint16 post = 0;
|
||||
uint32 dotclock = 0;
|
||||
uint32 reference = 0;
|
||||
uint32 feedback = 0;
|
||||
uint32 feedbackFrac = 0;
|
||||
uint32 post = 0;
|
||||
|
||||
PLLCalculate(pixelClock, &reference, &feedback, &post);
|
||||
pll_compute(pixelClock, &dotclock, &reference, &feedback,
|
||||
&feedbackFrac, &post);
|
||||
|
||||
int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
|
||||
union set_pixel_clock args;
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
//uint8 frev;
|
||||
//uint8 crev;
|
||||
//atom_parse_cmd_header(gAtomContext, index, &frev, &crev);
|
||||
|
||||
uint8 frev = 1;
|
||||
uint8 crev = 1;
|
||||
uint8 frev;
|
||||
uint8 crev;
|
||||
atom_parse_cmd_header(gAtomContext, index, &frev, &crev);
|
||||
|
||||
switch (crev) {
|
||||
case 1:
|
||||
args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
|
||||
args.v1.usRefDiv = B_HOST_TO_LENDIAN_INT16(reference);
|
||||
args.v1.usFbDiv = B_HOST_TO_LENDIAN_INT16(feedback);
|
||||
// args.v1.ucFracFbDiv = frac_fb_div;
|
||||
args.v1.ucFracFbDiv = 0;
|
||||
args.v1.ucFracFbDiv = feedbackFrac;
|
||||
args.v1.ucPostDiv = post;
|
||||
args.v1.ucPpll = pll_id;
|
||||
args.v1.ucCRTC = crtc_id;
|
||||
@@ -268,419 +202,35 @@ pll_set(uint8 pll_id, uint32 pixelClock, uint8 crtc_id)
|
||||
args.v2.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
|
||||
args.v2.usRefDiv = B_HOST_TO_LENDIAN_INT16(reference);
|
||||
args.v2.usFbDiv = B_HOST_TO_LENDIAN_INT16(feedback);
|
||||
// args.v2.ucFracFbDiv = frac_fb_div;
|
||||
args.v2.ucFracFbDiv = feedbackFrac;
|
||||
args.v2.ucPostDiv = post;
|
||||
args.v2.ucPpll = pll_id;
|
||||
args.v2.ucCRTC = crtc_id;
|
||||
args.v2.ucRefDivSrc = 1;
|
||||
break;
|
||||
#if 0
|
||||
case 3:
|
||||
args.v3.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
|
||||
args.v3.usRefDiv = B_HOST_TO_LENDIAN_INT16(reference);
|
||||
args.v3.usFbDiv = B_HOST_TO_LENDIAN_INT16(feedback);
|
||||
// args.v3.ucFracFbDiv = frac_fb_div;
|
||||
args.v3.ucFracFbDiv = feedbackFrac;
|
||||
args.v3.ucPostDiv = post;
|
||||
args.v3.ucPpll = pll_id;
|
||||
args.v3.ucMiscInfo = (pll_id << 2);
|
||||
if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
|
||||
args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
|
||||
args.v3.ucTransmitterId = encoder_id;
|
||||
args.v3.ucEncoderMode = encoder_mode;
|
||||
// if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
|
||||
// args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
|
||||
args.v3.ucTransmitterId = crtc_id;
|
||||
// TODO : transmitter id is now CRTC id?
|
||||
args.v3.ucEncoderMode = gDisplay[crtc_id]->connection_type;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
TRACE("%s: TODO: table version %d %d\n", __func__, frev, crev);
|
||||
TRACE("%s: ERROR: table version %d.%d TODO\n", __func__,
|
||||
frev, crev);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("%s: setting pixel clock %" B_PRIu32 "\n", __func__, pixelClock);
|
||||
|
||||
atom_execute_table(gAtomContext, index, (uint32 *)&args);
|
||||
|
||||
#if 0
|
||||
if (info.device_chipset >= (RADEON_R600 | 0x20)) {
|
||||
TRACE("%s : setting pixel clock %d on r620+\n", __func__,
|
||||
(int)pixelClock);
|
||||
PLLSetLowR620(pllIndex, pixelClock, reference,
|
||||
feedback, post);
|
||||
} else if (info.device_chipset < (RADEON_R600 | 0x20)) {
|
||||
TRACE("%s : setting pixel clock %d on r600-r610\n", __func__,
|
||||
(int)pixelClock);
|
||||
PLLSetLowLegacy(pllIndex, pixelClock, reference,
|
||||
feedback, post);
|
||||
}
|
||||
#endif
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PLLSetLowLegacy(uint8 pllIndex, uint32 pixelClock, uint16 reference,
|
||||
uint16 feedback, uint16 post)
|
||||
{
|
||||
uint32 feedbackTemp = feedback << 16;
|
||||
uint32 referenceTemp = reference;
|
||||
|
||||
/* Internal PLL Registers */
|
||||
uint16 pllCntl = pllIndex == 1 ? P2PLL_CNTL : P1PLL_CNTL;
|
||||
uint16 pllIntSSCntl
|
||||
= pllIndex == 1 ? P2PLL_INT_SS_CNTL : P1PLL_INT_SS_CNTL;
|
||||
|
||||
/* External PLL Registers */
|
||||
uint16 pllExtCntl
|
||||
= pllIndex == 1 ? EXT2_PPLL_CNTL : EXT1_PPLL_CNTL;
|
||||
uint16 pllExtUpdateCntl
|
||||
= pllIndex == 1 ? EXT2_PPLL_UPDATE_CNTL : EXT1_PPLL_UPDATE_CNTL;
|
||||
uint16 pllExtUpdateLock
|
||||
= pllIndex == 1 ? EXT2_PPLL_UPDATE_LOCK : EXT1_PPLL_UPDATE_LOCK;
|
||||
uint16 pllExtPostDiv
|
||||
= pllIndex == 1 ? EXT2_PPLL_POST_DIV : EXT1_PPLL_POST_DIV;
|
||||
uint16 pllExtPostDivSrc
|
||||
= pllIndex == 1 ? EXT2_PPLL_POST_DIV_SRC : EXT1_PPLL_POST_DIV_SRC;
|
||||
uint16 pllExtFeedbackDiv
|
||||
= pllIndex == 1 ? EXT2_PPLL_FB_DIV : EXT1_PPLL_FB_DIV;
|
||||
uint16 pllExtRefDiv
|
||||
= pllIndex == 1 ? EXT2_PPLL_REF_DIV : EXT1_PPLL_REF_DIV;
|
||||
uint16 pllExtRefDivSrc
|
||||
= pllIndex == 1 ? EXT2_PPLL_REF_DIV_SRC : EXT1_PPLL_REF_DIV_SRC;
|
||||
|
||||
radeon_shared_info &info = *gInfo->shared_info;
|
||||
|
||||
if (info.device_chipset <= RADEON_R600)
|
||||
feedbackTemp |= 0x00000030;
|
||||
else {
|
||||
if (feedback <= 0x24)
|
||||
feedbackTemp |= 0x00000030;
|
||||
else if (feedback <= 0x3F)
|
||||
feedbackTemp |= 0x00000020;
|
||||
}
|
||||
|
||||
uint32 postTemp = Read32(PLL, pllExtPostDiv) & ~0x0000007F;
|
||||
postTemp |= post & 0x0000007F;
|
||||
|
||||
uint32 control;
|
||||
if (info.device_chipset == RADEON_R600)
|
||||
control = 0x01130704;
|
||||
else {
|
||||
control = PLLControlTable(RV610PLLControl, feedback);
|
||||
if (!control)
|
||||
control = Read32(PLL, pllExtCntl);
|
||||
}
|
||||
|
||||
Write32Mask(PLL, pllIntSSCntl, 0, 0x00000001);
|
||||
// Disable Spread Spectrum
|
||||
|
||||
Write32(PLL, pllExtRefDivSrc, 0x01); /* XTAL */
|
||||
Write32(PLL, pllExtPostDivSrc, 0x00); /* source = reference */
|
||||
|
||||
Write32(PLL, pllExtUpdateLock, 0x01); /* lock */
|
||||
|
||||
Write32(PLL, pllExtRefDiv, referenceTemp);
|
||||
Write32(PLL, pllExtFeedbackDiv, feedbackTemp);
|
||||
Write32(PLL, pllExtPostDiv, postTemp);
|
||||
Write32(PLL, pllExtCntl, control);
|
||||
|
||||
Write32Mask(PLL, pllExtUpdateCntl, 0x00010000, 0x00010000);
|
||||
// No autoreset
|
||||
Write32Mask(PLL, pllCntl, 0, 0x04);
|
||||
// Don't bypass calibration
|
||||
|
||||
/* We need to reset the anti glitch logic */
|
||||
Write32Mask(PLL, pllCntl, 0, 0x00000002);
|
||||
// Power up
|
||||
|
||||
/* reset anti glitch logic */
|
||||
Write32Mask(PLL, pllCntl, 0x00002000, 0x00002000);
|
||||
snooze(2);
|
||||
Write32Mask(PLL, pllCntl, 0, 0x00002000);
|
||||
|
||||
/* powerdown and reset */
|
||||
Write32Mask(PLL, pllCntl, 0x00000003, 0x00000003);
|
||||
snooze(2);
|
||||
|
||||
Write32(PLL, pllExtUpdateLock, 0);
|
||||
// Unlock
|
||||
Write32Mask(PLL, pllExtUpdateCntl, 0, 0x01);
|
||||
// Done updating
|
||||
|
||||
Write32Mask(PLL, pllCntl, 0, 0x02);
|
||||
// Power up PLL
|
||||
snooze(2);
|
||||
|
||||
PLLCalibrate(pllIndex);
|
||||
|
||||
Write32(PLL, pllExtPostDivSrc, 0x01);
|
||||
// Set source as PLL
|
||||
|
||||
// TODO : for now we assume crt 0, needs refactoring
|
||||
PLLCRTCGrab(pllIndex, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PLLSetLowR620(uint8 pllIndex, uint32 pixelClock, uint16 reference,
|
||||
uint16 feedback, uint16 post)
|
||||
{
|
||||
radeon_shared_info &info = *gInfo->shared_info;
|
||||
|
||||
bool hasDccg = DCCGCLKAvailable(pllIndex);
|
||||
|
||||
TRACE("%s: card has DCCG = %c\n", __func__, hasDccg ? 'y' : 'n');
|
||||
|
||||
if (hasDccg)
|
||||
DCCGCLKSet(pllIndex, RV620_DCCGCLK_RESET);
|
||||
|
||||
/* Internal PLL Registers */
|
||||
uint16 pllCntl = pllIndex == 1 ? P2PLL_CNTL : P1PLL_CNTL;
|
||||
uint16 pllIntSSCntl
|
||||
= pllIndex == 1 ? P2PLL_INT_SS_CNTL : P1PLL_INT_SS_CNTL;
|
||||
|
||||
/* External PLL Registers */
|
||||
uint16 pllExtCntl
|
||||
= pllIndex == 1 ? EXT2_PPLL_CNTL : EXT1_PPLL_CNTL;
|
||||
//uint16 pllExtUpdateCntl
|
||||
// = pllIndex == 1 ? EXT2_PPLL_UPDATE_CNTL : EXT1_PPLL_UPDATE_CNTL;
|
||||
uint16 pllExtUpdateLock
|
||||
= pllIndex == 1 ? EXT2_PPLL_UPDATE_LOCK : EXT1_PPLL_UPDATE_LOCK;
|
||||
uint16 pllExtPostDiv
|
||||
= pllIndex == 1 ? EXT2_PPLL_POST_DIV : EXT1_PPLL_POST_DIV;
|
||||
uint16 pllExtPostDivSrc
|
||||
= pllIndex == 1 ? EXT2_PPLL_POST_DIV_SRC : EXT1_PPLL_POST_DIV_SRC;
|
||||
uint16 pllExtPostDivSym
|
||||
= pllIndex == 1 ? EXT2_SYM_PPLL_POST_DIV : EXT1_SYM_PPLL_POST_DIV;
|
||||
uint16 pllExtFeedbackDiv
|
||||
= pllIndex == 1 ? EXT2_PPLL_FB_DIV : EXT1_PPLL_FB_DIV;
|
||||
uint16 pllExtRefDiv
|
||||
= pllIndex == 1 ? EXT2_PPLL_REF_DIV : EXT1_PPLL_REF_DIV;
|
||||
//uint16 pllExtRefDivSrc
|
||||
// = pllIndex == 1 ? EXT2_PPLL_REF_DIV_SRC : EXT1_PPLL_REF_DIV_SRC;
|
||||
uint16 pllExtDispClkCntl
|
||||
= pllIndex == 1 ? P2PLL_DISP_CLK_CNTL : P1PLL_DISP_CLK_CNTL;
|
||||
|
||||
Write32Mask(PLL, pllIntSSCntl, 0, 0x00000001);
|
||||
// Disable Spread Spectrum
|
||||
|
||||
uint32 referenceDivider = reference;
|
||||
|
||||
uint32 feedbackDivider = Read32(PLL, pllExtFeedbackDiv) & ~0x07FF003F;
|
||||
feedbackDivider |= ((feedback << 16) | 0x0030) & 0x07FF003F;
|
||||
|
||||
uint32 postDivider = Read32(PLL, pllExtPostDiv) & ~0x0000007F;
|
||||
postDivider |= post & 0x0000007F;
|
||||
|
||||
uint32 control;
|
||||
|
||||
if (info.device_chipset >= (RADEON_R600 | 0x70))
|
||||
control = PLLControlTable(RV670PLLControl, feedback);
|
||||
else
|
||||
control = PLLControlTable(RV610PLLControl, feedback);
|
||||
|
||||
uint8 symPostDiv = post & 0x0000007F;
|
||||
|
||||
/* switch to external */
|
||||
Write32(PLL, pllExtPostDivSrc, 0);
|
||||
Write32Mask(PLL, pllExtDispClkCntl, 0x00000200, 0x00000300);
|
||||
Write32Mask(PLL, pllExtPostDiv, 0, 0x00000100);
|
||||
|
||||
Write32Mask(PLL, pllCntl, 0x00000001, 0x00000001);
|
||||
// reset
|
||||
snooze(2);
|
||||
Write32Mask(PLL, pllCntl, 0x00000002, 0x00000002);
|
||||
// power down
|
||||
snooze(10);
|
||||
Write32Mask(PLL, pllCntl, 0x00002000, 0x00002000);
|
||||
// reset antiglitch
|
||||
|
||||
Write32(PLL, pllExtCntl, control);
|
||||
|
||||
Write32Mask(PLL, pllExtDispClkCntl, 2, 0x0000003F);
|
||||
// Scalar Divider 2
|
||||
|
||||
Write32(PLL, pllExtUpdateLock, 1);
|
||||
// Lock PLL
|
||||
|
||||
/* Write PLL clocks */
|
||||
Write32(PLL, pllExtPostDivSrc, 0x00000001);
|
||||
Write32(PLL, pllExtRefDiv, referenceDivider);
|
||||
Write32(PLL, pllExtFeedbackDiv, feedbackDivider);
|
||||
Write32Mask(PLL, pllExtPostDiv, postDivider, 0x0000007F);
|
||||
Write32Mask(PLL, pllExtPostDivSym, symPostDiv, 0x0000007F);
|
||||
|
||||
snooze(10);
|
||||
|
||||
Write32(PLL, pllExtUpdateLock, 0);
|
||||
// Unlock PLL
|
||||
|
||||
Write32Mask(PLL, pllCntl, 0, 0x00000002);
|
||||
// power up
|
||||
snooze(10);
|
||||
|
||||
Write32Mask(PLL, pllCntl, 0, 0x00002000);
|
||||
// undo reset antiglitch
|
||||
|
||||
PLLCalibrate(pllIndex);
|
||||
|
||||
/* Switch back to PLL */
|
||||
Write32Mask(PLL, pllExtDispClkCntl, 0, 0x00000300);
|
||||
Write32Mask(PLL, pllExtPostDivSym, 0x00000100, 0x00000100);
|
||||
Write32(PLL, pllExtPostDivSrc, 0x00000001);
|
||||
|
||||
Write32Mask(PLL, pllCntl, 0, 0x80000000);
|
||||
// needed and undocumented
|
||||
|
||||
// TODO : for now we assume crt 0, needs refactoring
|
||||
PLLCRTCGrab(pllIndex, 0);
|
||||
|
||||
if (hasDccg)
|
||||
DCCGCLKSet(pllIndex, RV620_DCCGCLK_GRAB);
|
||||
|
||||
TRACE("%s: PLLSet exit\n", __func__);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PLLCalibrate(uint8 pllIndex)
|
||||
{
|
||||
uint16 pllControlReg = pllIndex == 1 ? P2PLL_CNTL : P1PLL_CNTL;
|
||||
|
||||
Write32Mask(PLL, pllControlReg, 1, 0x01);
|
||||
// PLL Reset
|
||||
|
||||
snooze(2);
|
||||
|
||||
Write32Mask(PLL, pllControlReg, 0, 0x01);
|
||||
// PLL Set
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PLL_CALIBRATE_WAIT; i++) {
|
||||
if (((Read32(PLL, pllControlReg) >> 20) & 0x03) == 0x03)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= PLL_CALIBRATE_WAIT) {
|
||||
if (Read32(PLL, pllControlReg) & 0x00100000) /* Calibration done? */
|
||||
TRACE("%s: Calibration Failed\n", __func__);
|
||||
if (Read32(PLL, pllControlReg) & 0x00200000) /* PLL locked? */
|
||||
TRACE("%s: Locking Failed\n", __func__);
|
||||
TRACE("%s: We encountered a problem calibrating the PLL.\n", __func__);
|
||||
return B_ERROR;
|
||||
} else
|
||||
TRACE("%s: pll calibrated and locked in %d loops\n", __func__, i);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PLLCRTCGrab(uint8 pllIndex, uint8 crtid)
|
||||
{
|
||||
bool pll2IsCurrent;
|
||||
|
||||
if (crtid == 0) {
|
||||
pll2IsCurrent = Read32(PLL, PCLK_CRTC1_CNTL) & 0x00010000;
|
||||
|
||||
Write32Mask(PLL, PCLK_CRTC1_CNTL, pllIndex == 0 ? 0x00010000 : 0,
|
||||
0x00010000);
|
||||
} else {
|
||||
pll2IsCurrent = Read32(PLL, PCLK_CRTC2_CNTL) & 0x00010000;
|
||||
|
||||
Write32Mask(PLL, PCLK_CRTC2_CNTL, pllIndex == 0 ? 0x00010000 : 0,
|
||||
0x00010000);
|
||||
}
|
||||
|
||||
/* if the current pll is not active, then poke it just enough to flip
|
||||
* owners */
|
||||
if (!pll2IsCurrent) {
|
||||
uint32 stored = Read32(PLL, P1PLL_CNTL);
|
||||
|
||||
if (stored & 0x03) {
|
||||
Write32Mask(PLL, P1PLL_CNTL, 0, 0x03);
|
||||
snooze(10);
|
||||
Write32Mask(PLL, P1PLL_CNTL, stored, 0x03);
|
||||
}
|
||||
|
||||
} else {
|
||||
uint32 stored = Read32(PLL, P2PLL_CNTL);
|
||||
|
||||
if (stored & 0x03) {
|
||||
Write32Mask(PLL, P2PLL_CNTL, 0, 0x03);
|
||||
snooze(10);
|
||||
Write32Mask(PLL, P2PLL_CNTL, stored, 0x03);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// See if card has a DCCG available that we need to lock to
|
||||
// the PLL clock. No one seems really sure what DCCG is.
|
||||
bool
|
||||
DCCGCLKAvailable(uint8 pllIndex)
|
||||
{
|
||||
radeon_shared_info &info = *gInfo->shared_info;
|
||||
|
||||
if (info.device_chipset < (RADEON_R600 | 0x20))
|
||||
return false;
|
||||
|
||||
uint32 dccg = Read32(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03;
|
||||
|
||||
if (dccg & 0x02)
|
||||
return true;
|
||||
|
||||
if ((pllIndex == 0) && (dccg == 0))
|
||||
return true;
|
||||
if ((pllIndex == 1) && (dccg == 1))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DCCGCLKSet(uint8 pllIndex, int set)
|
||||
{
|
||||
uint32 buffer;
|
||||
|
||||
switch(set) {
|
||||
case RV620_DCCGCLK_GRAB:
|
||||
if (pllIndex == 0)
|
||||
Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 0, 0x00000003);
|
||||
else if (pllIndex == 1)
|
||||
Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 1, 0x00000003);
|
||||
else
|
||||
Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
|
||||
break;
|
||||
case RV620_DCCGCLK_RELEASE:
|
||||
buffer = Read32(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03;
|
||||
|
||||
if ((pllIndex == 0) && (buffer == 0)) {
|
||||
/* set to other PLL or external */
|
||||
buffer = Read32(PLL, P2PLL_CNTL);
|
||||
// if powered and not in reset, and calibrated and locked
|
||||
if (!(buffer & 0x03) && ((buffer & 0x00300000) == 0x00300000))
|
||||
Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 1, 0x00000003);
|
||||
else
|
||||
Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
|
||||
|
||||
} else if ((pllIndex == 1) && (buffer == 1)) {
|
||||
/* set to other PLL or external */
|
||||
buffer = Read32(PLL, P1PLL_CNTL);
|
||||
// if powered and not in reset, and calibrated and locked
|
||||
if (!(buffer & 0x03) && ((buffer & 0x00300000) == 0x00300000))
|
||||
Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 0, 0x00000003);
|
||||
else
|
||||
Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
|
||||
|
||||
} // no other action needed
|
||||
break;
|
||||
case RV620_DCCGCLK_RESET:
|
||||
buffer = Read32(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03;
|
||||
|
||||
if (((pllIndex == 0) && (buffer == 0))
|
||||
|| ((pllIndex == 1) && (buffer == 1)))
|
||||
Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,42 +9,25 @@
|
||||
#define RADEON_HD_PLL_H
|
||||
|
||||
|
||||
#define RHD_PLL_MIN_DEFAULT 16000
|
||||
#define RHD_PLL_MAX_DEFAULT 400000
|
||||
#define RHD_PLL_REFERENCE_DEFAULT 27000
|
||||
#define MAX_TOLERANCE 10
|
||||
|
||||
// xorg default is 0x100000 which seems a little much.
|
||||
#define PLL_CALIBRATE_WAIT 0x010000
|
||||
#define PLL_MIN_DEFAULT 16000
|
||||
#define PLL_MAX_DEFAULT 400000
|
||||
#define PLL_REFERENCE_DEFAULT 27000
|
||||
|
||||
/* limited by the number of bits available */
|
||||
#define FB_DIV_MIN 4
|
||||
#define FB_DIV_LIMIT 2048
|
||||
#define REF_DIV_MIN 2
|
||||
#define REF_DIV_LIMIT 1024
|
||||
#define POST_DIV_LIMIT 128
|
||||
|
||||
// DCCGClk Operation Modes
|
||||
#define RV620_DCCGCLK_RESET 0
|
||||
#define RV620_DCCGCLK_GRAB 1
|
||||
#define RV620_DCCGCLK_RELEASE 2
|
||||
#define POST_DIV_MIN 2
|
||||
#define POST_DIV_LIMIT 127
|
||||
|
||||
|
||||
struct PLL_Control {
|
||||
uint16 feedbackDivider; // 0xFFFF is the endmarker
|
||||
uint32 control;
|
||||
};
|
||||
|
||||
|
||||
status_t PLLCalculate(uint32 pixelClock, uint16 *reference, uint16 *feedback,
|
||||
uint16 *post);
|
||||
status_t pll_compute(uint32 pixelClock, uint32 *dotclockOut,
|
||||
uint32 *referenceOut, uint32 *feedbackOut, uint32 *feedbackFracOut,
|
||||
uint32 *postOut);
|
||||
status_t pll_set(uint8 pll_id, uint32 pixelClock, uint8 crtc_id);
|
||||
void PLLSetLowLegacy(uint8 pllIndex, uint32 pixelClock, uint16 reference,
|
||||
uint16 feedback, uint16 post);
|
||||
void PLLSetLowR620(uint8 pllIndex, uint32 pixelClock, uint16 reference,
|
||||
uint16 feedback, uint16 post);
|
||||
status_t PLLPower(uint8 pllIndex, int command);
|
||||
status_t PLLCalibrate(uint8 pllIndex);
|
||||
void PLLCRTCGrab(uint8 pllIndex, uint8 crtid);
|
||||
bool DCCGCLKAvailable(uint8 pllIndex);
|
||||
void DCCGCLKSet(uint8 pllIndex, int set);
|
||||
|
||||
|
||||
#endif /* RADEON_HD_PLL_H */
|
||||
|
||||
@@ -107,7 +107,7 @@ const struct supported_device {
|
||||
|
||||
// From here on AMD no longer used numeric identifiers
|
||||
|
||||
// R1000 series (HD54xx - HD59xx)
|
||||
// R1000 series (HD54xx - HD63xx)
|
||||
// Codename: Evergreen
|
||||
// Cedar
|
||||
{0x68e1, RADEON_R1000 | 0x00, false, "Radeon HD 5430"},
|
||||
@@ -128,6 +128,12 @@ const struct supported_device {
|
||||
{0x6898, RADEON_R1000 | 0x30, false, "Radeon HD 5870"},
|
||||
// Hemlock
|
||||
{0x689c, RADEON_R1000 | 0x40, false, "Radeon HD 5900"},
|
||||
// Fusion APUS
|
||||
// Palms
|
||||
{0x9804, RADEON_R1000 | 0x50, true, "Radeon HD 6250"},
|
||||
{0x9805, RADEON_R1000 | 0x50, true, "Radeon HD 6290"},
|
||||
{0x9802, RADEON_R1000 | 0x50, true, "Radeon HD 6310"},
|
||||
{0x9803, RADEON_R1000 | 0x50, true, "Radeon HD 6310"},
|
||||
|
||||
// R2000 series (HD64xx - HD69xx)
|
||||
// Codename: Nothern Islands
|
||||
|
||||
Reference in New Issue
Block a user