From d3e8b64208159ab71ca24f58ec7e56f1aa4bb5e6 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Fri, 19 Aug 2011 23:07:45 +0000 Subject: [PATCH] * 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 --- .../private/graphics/radeon_hd/radeon_hd.h | 48 +- .../accelerants/radeon_hd/accelerant.cpp | 12 +- .../accelerants/radeon_hd/accelerant.h | 93 ++- src/add-ons/accelerants/radeon_hd/bios.cpp | 61 +- src/add-ons/accelerants/radeon_hd/bios.h | 1 + src/add-ons/accelerants/radeon_hd/display.cpp | 57 +- src/add-ons/accelerants/radeon_hd/gpu.cpp | 75 +- src/add-ons/accelerants/radeon_hd/gpu.h | 7 +- src/add-ons/accelerants/radeon_hd/mode.cpp | 30 +- src/add-ons/accelerants/radeon_hd/pll.cpp | 692 +++--------------- src/add-ons/accelerants/radeon_hd/pll.h | 39 +- .../drivers/graphics/radeon_hd/driver.cpp | 8 +- 12 files changed, 423 insertions(+), 700 deletions(-) diff --git a/headers/private/graphics/radeon_hd/radeon_hd.h b/headers/private/graphics/radeon_hd/radeon_hd.h index 33c6634921..32f7f4ccf0 100644 --- a/headers/private/graphics/radeon_hd/radeon_hd.h +++ b/headers/private/graphics/radeon_hd/radeon_hd.h @@ -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 // +#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 diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.cpp b/src/add-ons/accelerants/radeon_hd/accelerant.cpp index 97f022e5f7..294365745f 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.cpp +++ b/src/add-ons/accelerants/radeon_hd/accelerant.cpp @@ -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); } diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h b/src/add-ons/accelerants/radeon_hd/accelerant.h index 98f9c3393c..ffb9152e8f 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.h +++ b/src/add-ons/accelerants/radeon_hd/accelerant.h @@ -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; }; } diff --git a/src/add-ons/accelerants/radeon_hd/bios.cpp b/src/add-ons/accelerants/radeon_hd/bios.cpp index 1c60c18e97..242e487e4e 100644 --- a/src/add-ons/accelerants/radeon_hd/bios.cpp +++ b/src/add-ons/accelerants/radeon_hd/bios.cpp @@ -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; } diff --git a/src/add-ons/accelerants/radeon_hd/bios.h b/src/add-ons/accelerants/radeon_hd/bios.h index f686de1425..9d32c54d91 100644 --- a/src/add-ons/accelerants/radeon_hd/bios.h +++ b/src/add-ons/accelerants/radeon_hd/bios.h @@ -15,6 +15,7 @@ status_t radeon_init_bios(uint8* bios); +bool radeon_bios_isposted(); status_t radeon_dump_bios(); diff --git a/src/add-ons/accelerants/radeon_hd/display.cpp b/src/add-ons/accelerants/radeon_hd/display.cpp index 4bae5adabf..616318f5b3 100644 --- a/src/add-ons/accelerants/radeon_hd/display.cpp +++ b/src/add-ons/accelerants/radeon_hd/display.cpp @@ -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); diff --git a/src/add-ons/accelerants/radeon_hd/gpu.cpp b/src/add-ons/accelerants/radeon_hd/gpu.cpp index 2a37354cd3..249fa0e285 100644 --- a/src/add-ons/accelerants/radeon_hd/gpu.cpp +++ b/src/add-ons/accelerants/radeon_hd/gpu.cpp @@ -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; } diff --git a/src/add-ons/accelerants/radeon_hd/gpu.h b/src/add-ons/accelerants/radeon_hd/gpu.h index e8311e4694..b0779c748a 100644 --- a/src/add-ons/accelerants/radeon_hd/gpu.h +++ b/src/add-ons/accelerants/radeon_hd/gpu.h @@ -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(); diff --git a/src/add-ons/accelerants/radeon_hd/mode.cpp b/src/add-ons/accelerants/radeon_hd/mode.cpp index e3a84bc97e..c48420a011 100644 --- a/src/add-ons/accelerants/radeon_hd/mode.cpp +++ b/src/add-ons/accelerants/radeon_hd/mode.cpp @@ -17,6 +17,7 @@ #include "utility.h" #include "mode.h" #include "display.h" +#include "pll.h" #include #include @@ -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; diff --git a/src/add-ons/accelerants/radeon_hd/pll.cpp b/src/add-ons/accelerants/radeon_hd/pll.cpp index 6f2c1c3b5c..e912d1828c 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.cpp +++ b/src/add-ons/accelerants/radeon_hd/pll.cpp @@ -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; - } -} diff --git a/src/add-ons/accelerants/radeon_hd/pll.h b/src/add-ons/accelerants/radeon_hd/pll.h index 8817994911..144ab1adc6 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.h +++ b/src/add-ons/accelerants/radeon_hd/pll.h @@ -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 */ diff --git a/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp b/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp index 5d5fa8b7c1..c7dddb1690 100644 --- a/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp +++ b/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp @@ -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