From d1d65a79cbba5eb871c2763824839ee56930a557 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Wed, 15 Jun 2011 18:22:06 +0000 Subject: [PATCH] * malloc an array of pointers to hold active crt info, mode, limits, etc. Plan to move gRegister into the crt struct at some point. * Few style fixes * Added function to probe edid of attached monitors and populate CRT info * Disable VGA control modifications temporarly while I hammer out some issues. * Fix radeon card model checks (bitwise & is not |) * Finally fix? blanking start / end calculations using porch * Use mask for setting sync polarity * Add overscan (8 pixels is default?) * Disable PLLSet/Power for the moment as it seems to muck things up. * is_mode_supported now validates if a mode line is with the monitors h/v sync frequencies (how does is_mode_supported know what crt the os wants?) * PLL Write/Read don't actually use the PLL Write/Read functions (thanks AMD!) * Added better PLL legacy (r600-r610) support * Consistantly give no DCCG on legacy cards. * Tracing! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42191 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../accelerants/radeon_hd/accelerant.cpp | 15 +- .../accelerants/radeon_hd/accelerant.h | 42 +++-- src/add-ons/accelerants/radeon_hd/mode.cpp | 122 +++++++++++--- src/add-ons/accelerants/radeon_hd/mode.h | 3 + src/add-ons/accelerants/radeon_hd/pll.cpp | 156 +++++++++++++++--- src/add-ons/accelerants/radeon_hd/pll.h | 4 + 6 files changed, 278 insertions(+), 64 deletions(-) diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.cpp b/src/add-ons/accelerants/radeon_hd/accelerant.cpp index 8c03f19c77..28fc9c0bf9 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.cpp +++ b/src/add-ons/accelerants/radeon_hd/accelerant.cpp @@ -34,6 +34,7 @@ extern "C" void _sPrintf(const char *format, ...); struct accelerant_info *gInfo; struct register_info *gRegister; +crt_info *gCRT[MAX_CRT]; class AreaCloner { @@ -100,9 +101,18 @@ init_common(int device, bool isClone) if (gInfo == NULL || gRegister == NULL) return B_NO_MEMORY; + for (uint32 id = 0; id < MAX_CRT; id++) { + gCRT[id] = (crt_info *)malloc(sizeof(crt_info)); + if (gCRT[id] == NULL) + return B_NO_MEMORY; + } + memset(gInfo, 0, sizeof(accelerant_info)); memset(gRegister, 0, sizeof(register_info)); + for (uint32 id = 0; id < MAX_CRT; id++) + memset(gCRT[id], 0, sizeof(crt_info)); + gInfo->is_clone = isClone; gInfo->device = device; @@ -167,6 +177,9 @@ uninit_common(void) free(gInfo); free(gRegister); + + for (uint32 id = 0; id < MAX_CRT; id++) + free(gCRT[id]); } @@ -177,7 +190,7 @@ init_registers(uint8 crtid) radeon_shared_info &info = *gInfo->shared_info; if (info.device_chipset >= RADEON_R800) { - uint16_t offset = 0; + uint32 offset = 0; // AMD Eyefinity on Evergreen GPUs if (crtid == 1) { diff --git a/src/add-ons/accelerants/radeon_hd/accelerant.h b/src/add-ons/accelerants/radeon_hd/accelerant.h index 2b23b08169..1c3c64834f 100644 --- a/src/add-ons/accelerants/radeon_hd/accelerant.h +++ b/src/add-ons/accelerants/radeon_hd/accelerant.h @@ -18,6 +18,10 @@ #include +#define MAX_CRT 6 + // eyefinity limit + + struct accelerant_info { vuint8 *regs; area_id regs_area; @@ -77,6 +81,14 @@ struct register_info { }; +typedef struct { + uint32 vfreq_max; + uint32 vfreq_min; + uint32 hfreq_max; + uint32 hfreq_min; +} crt_info; + + #define HEAD_MODE_A_ANALOG 0x01 #define HEAD_MODE_B_DIGITAL 0x02 #define HEAD_MODE_CLONE 0x03 @@ -89,8 +101,10 @@ struct register_info { #define PLL 0x4 // PLL calls #define MC 0x5 // Memory Controler calls + extern accelerant_info *gInfo; extern register_info *gRegister; +extern crt_info *gCRT[MAX_CRT]; status_t init_registers(uint8 crtid); @@ -121,12 +135,12 @@ _read32MC(uint32 offset) _write32(RS600_MC_INDEX, ((offset & RS600_MC_INDEX_ADDR_MASK) | RS600_MC_INDEX_CITF_ARB0)); return _read32(RS600_MC_DATA); - } else if (info.device_chipset == (RADEON_R600 & 0x90) - || info.device_chipset == (RADEON_R700 & 0x40)) { + } else if (info.device_chipset == (RADEON_R600 | 0x90) + || info.device_chipset == (RADEON_R700 | 0x40)) { _write32(RS690_MC_INDEX, (offset & RS690_MC_INDEX_ADDR_MASK)); return _read32(RS690_MC_DATA); - } else if (info.device_chipset == (RADEON_R700 & 0x80) - || info.device_chipset == (RADEON_R800 & 0x80)) { + } else if (info.device_chipset == (RADEON_R700 | 0x80) + || info.device_chipset == (RADEON_R800 | 0x80)) { _write32(RS780_MC_INDEX, offset & RS780_MC_INDEX_ADDR_MASK); return _read32(RS780_MC_DATA); } @@ -145,14 +159,14 @@ _write32MC(uint32 offset, uint32 data) _write32(RS600_MC_INDEX, ((offset & RS600_MC_INDEX_ADDR_MASK) | RS600_MC_INDEX_CITF_ARB0 | RS600_MC_INDEX_WR_EN)); _write32(RS600_MC_DATA, data); - } else if (info.device_chipset == (RADEON_R600 & 0x90) - || info.device_chipset == (RADEON_R700 & 0x40)) { + } else if (info.device_chipset == (RADEON_R600 | 0x90) + || info.device_chipset == (RADEON_R700 | 0x40)) { _write32(RS690_MC_INDEX, ((offset & RS690_MC_INDEX_ADDR_MASK) | RS690_MC_INDEX_WR_EN)); _write32(RS690_MC_DATA, data); _write32(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); - } else if (info.device_chipset == (RADEON_R700 & 0x80) - || info.device_chipset == (RADEON_R800 & 0x80)) { + } else if (info.device_chipset == (RADEON_R700 | 0x80) + || info.device_chipset == (RADEON_R800 | 0x80)) { _write32(RS780_MC_INDEX, ((offset & RS780_MC_INDEX_ADDR_MASK) | RS780_MC_INDEX_WR_EN)); _write32(RS780_MC_DATA, data); @@ -187,7 +201,8 @@ Read32(uint32 subsystem, uint32 offset) case CRT: return _read32(offset); case PLL: - return _read32PLL(offset); + return _read32(offset); + //return _read32PLL(offset); case MC: return _read32MC(offset); }; @@ -207,7 +222,8 @@ Write32(uint32 subsystem, uint32 offset, uint32 value) _write32(offset, value); return; case PLL: - _write32PLL(offset, value); + _write32(offset, value); + //_write32PLL(offset, value); return; case MC: _write32MC(offset, value); @@ -230,7 +246,8 @@ Write32Mask(uint32 subsystem, uint32 offset, uint32 value, uint32 mask) temp = _read32(offset); break; case PLL: - temp = _read32PLL(offset); + temp = _read32(offset); + //temp = _read32PLL(offset); break; case MC: temp = _read32MC(offset); @@ -251,7 +268,8 @@ Write32Mask(uint32 subsystem, uint32 offset, uint32 value, uint32 mask) _write32(offset, temp); return; case PLL: - _write32PLL(offset, temp); + _write32(offset, temp); + //_write32PLL(offset, temp); return; case MC: _write32MC(offset, temp); diff --git a/src/add-ons/accelerants/radeon_hd/mode.cpp b/src/add-ons/accelerants/radeon_hd/mode.cpp index 5aeb2ccabc..3dc8ca3926 100644 --- a/src/add-ons/accelerants/radeon_hd/mode.cpp +++ b/src/add-ons/accelerants/radeon_hd/mode.cpp @@ -38,6 +38,8 @@ create_mode_list(void) const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE, B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8}; + detect_crt_ranges(); + gInfo->mode_list_area = create_display_modes("radeon HD modes", gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL, NULL, 0, kRadeonHDSpaces, @@ -148,12 +150,14 @@ CardFBSet(display_mode *mode) get_color_space_format(*mode, colorMode, bytesPerRow, bitsPerPixel); + #if 0 // Disable VGA mode to enable Radeon extended registers Write32Mask(VGA, VGA_RENDER_CONTROL, 0, 0x00030000); Write32Mask(VGA, VGA_MODE_CONTROL, 0, 0x00000030); Write32Mask(VGA, VGA_HDP_CONTROL, 0x00010010, 0x00010010); Write32Mask(VGA, gRegister->vgaControl, 0, D1VGA_MODE_ENABLE | D1VGA_TIMING_SELECT | D1VGA_SYNC_POLARITY_SELECT); + #endif // disable R/B swap, disable tiling, disable 16bit alpha, etc. Write32Mask(CRT, gRegister->grphEnable, 1, 0x00000001); @@ -190,7 +194,7 @@ CardFBSet(display_mode *mode) uint64_t fbAddress = gInfo->shared_info->frame_buffer_phys; // Tell GPU which frame buffer address to draw from - if (gInfo->shared_info->device_chipset >= (uint16)(RADEON_R700 & 0x70)) { + if (gInfo->shared_info->device_chipset >= (RADEON_R700 | 0x70)) { Write32(CRT, gRegister->grphPrimarySurfaceAddrHigh, (fbAddress >> 32) & 0xf); Write32(CRT, gRegister->grphSecondarySurfaceAddrHigh, @@ -235,14 +239,15 @@ CardModeSet(display_mode *mode) Write32(CRT, gRegister->crtHTotal, displayTiming.h_total - 1); - #if 0 - // determine blanking based on passed modeline - uint16 blankStart = displayTiming.h_display; - uint16 blankEnd = displayTiming.h_total; + // Calculate blanking + uint16 frontPorch = displayTiming.h_sync_start - displayTiming.h_display; + uint16 backPorch = displayTiming.h_total - displayTiming.h_sync_end; + + uint16 blankStart = frontPorch - OVERSCAN; + uint16 blankEnd = backPorch; Write32(CRT, gRegister->crtHBlank, blankStart | (blankEnd << 16)); - #endif Write32(CRT, gRegister->crtHSync, (displayTiming.h_sync_end - displayTiming.h_sync_start) << 16); @@ -255,13 +260,14 @@ CardModeSet(display_mode *mode) Write32(CRT, gRegister->crtVTotal, displayTiming.v_total - 1); - #if 0 - blankStart = displayTiming.v_display; - blankEnd = displayTiming.v_total; + frontPorch = displayTiming.v_sync_start - displayTiming.v_display; + backPorch = displayTiming.v_total - displayTiming.v_sync_end; + + blankStart = frontPorch - OVERSCAN; + blankEnd = backPorch; Write32(CRT, gRegister->crtVBlank, blankStart | (blankEnd << 16)); - #endif // Set Interlace if specified within mode line if (displayTiming.flags & B_TIMING_INTERLACED) { @@ -276,9 +282,8 @@ CardModeSet(display_mode *mode) (displayTiming.v_sync_end - displayTiming.v_sync_start) << 16); // set flag for neg. V sync. M76 Register Reference Guide 2-258 - // we don't need a mask here as this is the only param for Vertical - Write32(CRT, gRegister->crtVPolarity, - displayTiming.flags & B_POSITIVE_VSYNC ? 0 : 1); + Write32Mask(CRT, gRegister->crtVPolarity, + displayTiming.flags & B_POSITIVE_VSYNC ? 0 : 1, 0x1); /* set D1CRTC_HORZ_COUNT_BY2_EN to 0; should only be set to 1 on 30bpp DVI modes @@ -296,9 +301,9 @@ CardModeScale(display_mode *mode) // For now, no overscan support Write32(CRT, D1MODE_EXT_OVERSCAN_LEFT_RIGHT, - (0 << 16) | 0); // LEFT | RIGHT + (OVERSCAN << 16) | OVERSCAN); // LEFT | RIGHT Write32(CRT, D1MODE_EXT_OVERSCAN_TOP_BOTTOM, - (0 << 16) | 0); // TOP | BOTTOM + (OVERSCAN << 16) | OVERSCAN); // TOP | BOTTOM // No scaling Write32(CRT, gRegister->sclUpdate, (1<<16));// Lock @@ -336,12 +341,21 @@ radeon_set_display_mode(display_mode *mode) CardBlankSet(true); CardFBSet(mode); + CardBlankSet(false); CardModeSet(mode); CardModeScale(mode); + + #if 0 PLLSet(0, mode->timing.pixel_clock); PLLPower(0, RHD_POWER_ON); DACPower(0, RHD_POWER_ON); - CardBlankSet(false); + #endif + + // ensure graphics are enabled and powered on + Write32Mask(CRT, D1GRPH_ENABLE, 0x00000001, 0x00000001); + snooze(2); + Write32Mask(CRT, D1CRTC_CONTROL, 0, 0x01000000); /* enable read requests */ + Write32Mask(CRT, D1CRTC_CONTROL, 1, 1); int32 crtstatus = Read32(CRT, D1CRTC_STATUS); TRACE("CRT0 Status: 0x%X\n", crtstatus); @@ -405,22 +419,47 @@ radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high) bool is_mode_supported(display_mode *mode) { + TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d\n", + mode->timing.pixel_clock, mode->timing.h_display, + mode->timing.h_sync_start, mode->timing.h_sync_end, + mode->timing.h_total, mode->timing.v_display, + mode->timing.v_sync_start, mode->timing.v_sync_end, + mode->timing.v_total); + // Validate modeline is within a sane range if (is_mode_sane(mode) != B_OK) return false; - // TODO : Look at min and max monitor freqs and verify selected - // mode is within tolerances. - #if 0 - int crtid = 0; + uint32 crtid = 0; - edid1_detailed_monitor *monitor - = &gInfo->shared_info->edid_info.detailed_monitor[crtid + 1]; - edid1_monitor_range& range = monitor->data.monitor_range; + // if we have edid info, check frequency adginst crt reported valid ranges + if (gInfo->shared_info->has_edid) { - TRACE("%s CRT Min/Max H %d/%d; CRT Min/Max V %d/%d\n", __func__, - range.min_h, range.max_h, range.min_v, range.max_v); - #endif + uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total; + if (hfreq > gCRT[crtid]->hfreq_max + 1 + || hfreq < gCRT[crtid]->hfreq_min - 1) { + TRACE("!!! hfreq : %d , hfreq_min : %d, hfreq_max : %d\n", + hfreq, gCRT[crtid]->hfreq_min, gCRT[crtid]->hfreq_max); + TRACE("!!! %dx%d falls outside of CRT %d's valid " + "horizontal range.\n", mode->timing.h_display, + mode->timing.v_display, crtid); + return false; + } + + uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total + * mode->timing.h_total) / 1000); + + if (vfreq > gCRT[crtid]->vfreq_max + 1 + || vfreq < gCRT[crtid]->vfreq_min - 1) { + TRACE("!!! vfreq : %d , vfreq_min : %d, vfreq_max : %d\n", + vfreq, gCRT[crtid]->vfreq_min, gCRT[crtid]->vfreq_max); + TRACE("!!! %dx%d falls outside of CRT %d's valid vertical range\n", + mode->timing.h_display, mode->timing.v_display, crtid); + return false; + } + TRACE("%dx%d is within CRT %d's valid frequency range\n", + mode->timing.h_display, mode->timing.v_display, crtid); + } return true; } @@ -478,3 +517,34 @@ is_mode_sane(display_mode *mode) return B_OK; } + +// TODO : Move to a new "monitors.c" file +status_t +detect_crt_ranges() +{ + edid1_info *edid = &gInfo->shared_info->edid_info; + + int crtid = 0; + // edid indexes are not in order + + for (uint32 index = 0; index < MAX_CRT; index++) { + + edid1_detailed_monitor *monitor + = &edid->detailed_monitor[index]; + + if (monitor->monitor_desc_type + == EDID1_MONITOR_RANGES) { + edid1_monitor_range range = monitor->data.monitor_range; + gCRT[crtid]->vfreq_min = range.min_v; /* in Hz */ + gCRT[crtid]->vfreq_max = range.max_v; + gCRT[crtid]->hfreq_min = range.min_h; /* in kHz */ + gCRT[crtid]->hfreq_max = range.max_h; + TRACE("CRT %d : v_min %d : v_max %d : h_min %d : h_max %d\n", + crtid, gCRT[crtid]->vfreq_min, gCRT[crtid]->vfreq_max, + gCRT[crtid]->hfreq_min, gCRT[crtid]->hfreq_max); + crtid++; + } + + } + return B_OK; +} diff --git a/src/add-ons/accelerants/radeon_hd/mode.h b/src/add-ons/accelerants/radeon_hd/mode.h index 0709af2277..2a4e67aad2 100644 --- a/src/add-ons/accelerants/radeon_hd/mode.h +++ b/src/add-ons/accelerants/radeon_hd/mode.h @@ -21,7 +21,10 @@ #define FMT1_REG_OFFSET 0x0000 #define FMT2_REG_OFFSET 0x800 +#define OVERSCAN 8 + // default overscan? Applied to all sides +status_t detect_crt_ranges(); status_t create_mode_list(void); bool is_mode_supported(display_mode* mode); status_t is_mode_sane(display_mode *mode); diff --git a/src/add-ons/accelerants/radeon_hd/pll.cpp b/src/add-ons/accelerants/radeon_hd/pll.cpp index 373847e396..e50c5771b3 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.cpp +++ b/src/add-ons/accelerants/radeon_hd/pll.cpp @@ -134,7 +134,6 @@ PLLCalculate(uint32 pixelClock, uint16 *reference, uint16 *feedback, status_t PLLPower(uint8 pllIndex, int command) { - uint16 pllControlReg = (pllIndex == 1) ? P2PLL_CNTL : P1PLL_CNTL; bool hasDccg = DCCGCLKAvailable(pllIndex); @@ -179,6 +178,8 @@ PLLPower(uint8 pllIndex, int command) default: TRACE("%s: PLL Power Shutdown\n", __func__); + radeon_shared_info &info = *gInfo->shared_info; + if (hasDccg) DCCGCLKSet(pllIndex, RV620_DCCGCLK_RELEASE); @@ -186,20 +187,22 @@ PLLPower(uint8 pllIndex, int command) // Reset snooze(2); - // Sometimes we have to keep an unused PLL running. Xorg Bug #18016 - if ((Read32(PLL, RV620_EXT1_DIFF_POST_DIV_CNTL) - & RV62_EXT1_DIFF_DRIVER_ENABLE) == 0) { - Write32Mask(PLL, pllControlReg, 0x02, 0x02); - // Power Down - } else { - TRACE("%s: PHYA differential clock driver not disabled\n", - __func__); + if (info.device_chipset >= (RADEON_R600 | 0x20)) { + // Sometimes we have to keep an unused PLL running. X Bug #18016 + if ((Read32(PLL, RV620_EXT1_DIFF_POST_DIV_CNTL) + & RV62_EXT1_DIFF_DRIVER_ENABLE) == 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? } - - snooze(200); - - Write32Mask(PLL, pllControlReg, 0x2000, 0x2000); - // Reset anti-glitch? } return B_OK; @@ -209,22 +212,121 @@ PLLPower(uint8 pllIndex, int command) status_t PLLSet(uint8 pllIndex, uint32 pixelClock) { - - TRACE("%s: enter to set pixel clock %d\n", __func__, - (int)pixelClock); - radeon_shared_info &info = *gInfo->shared_info; - bool hasDccg = DCCGCLKAvailable(pllIndex); - - TRACE("%s: card has DCCG = %c\n", __func__, hasDccg ? 'y' : 'n'); - uint16 reference = 0; uint16 feedback = 0; uint16 post = 0; PLLCalculate(pixelClock, &reference, &feedback, &post); + 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); + } + + return B_OK; +} + + +void +PLLSetLowLegacy(uint8 pllIndex, uint32 pixelClock, uint16 reference, + uint16 feedback, uint16 post) +{ + uint32 feedbackTemp = feedback << 16; + uint32 referenceTemp = reference; + + radeon_shared_info &info = *gInfo->shared_info; + + if (info.device_chipset == RADEON_R600) + feedbackTemp |= 0x00000030; + else if (info.device_chipset > RADEON_R600) { + if (feedback <= 0x24) + feedbackTemp |= 0x00000030; + else if (feedback <= 0x3F) + feedbackTemp |= 0x00000020; + } else + feedbackTemp |= Read32(PLL, EXT1_PPLL_FB_DIV) & 0x00000030; + + uint32 postTemp = Read32(PLL, EXT1_PPLL_POST_DIV) & ~0x0000007F; + postTemp |= post & 0x0000007F; + + uint32 control; + if (info.device_chipset == RADEON_R600) + control = 0x01130704; + else + PLLControlTable(RV610PLLControl, feedback); + + if (!control) + control = Read32(PLL, EXT1_PPLL_CNTL); + + Write32Mask(PLL, P1PLL_INT_SS_CNTL, 0, 0x00000001); + // Disable Spread Spectrum + + Write32(PLL, EXT1_PPLL_REF_DIV_SRC, 0x01); /* XTAL */ + Write32(PLL, EXT1_PPLL_POST_DIV_SRC, 0x00); /* source = reference */ + + Write32(PLL, EXT1_PPLL_UPDATE_LOCK, 0x01); /* lock */ + + Write32(PLL, EXT1_PPLL_REF_DIV, referenceTemp); + Write32(PLL, EXT1_PPLL_FB_DIV, feedbackTemp); + Write32(PLL, EXT1_PPLL_POST_DIV, postTemp); + Write32(PLL, EXT1_PPLL_CNTL, control); + + Write32Mask(PLL, EXT1_PPLL_UPDATE_CNTL, 0x00010000, 0x00010000); + // No autoreset + Write32Mask(PLL, P1PLL_CNTL, 0, 0x04); + // Don't bypass calibration + + /* We need to reset the anti glitch logic */ + Write32Mask(PLL, P1PLL_CNTL, 0, 0x00000002); + // Power up + + /* reset anti glitch logic */ + Write32Mask(PLL, P1PLL_CNTL, 0x00002000, 0x00002000); + snooze(2); + Write32Mask(PLL, P1PLL_CNTL, 0, 0x00002000); + + /* powerdown and reset */ + Write32Mask(PLL, P1PLL_CNTL, 0x00000003, 0x00000003); + snooze(2); + + Write32(PLL, EXT1_PPLL_UPDATE_LOCK, 0); + // Unlock + Write32Mask(PLL, EXT1_PPLL_UPDATE_CNTL, 0, 0x01); + // Done updating + + Write32Mask(PLL, P1PLL_CNTL, 0, 0x02); + // Power up PLL + snooze(2); + + PLLCalibrate(pllIndex); + + Write32(PLL, EXT1_PPLL_POST_DIV_SRC, 0x01); + // Set source as PLL + + // TODO : If CRT2 ah-la R500PLLCRTCGrab + PLLCRTCGrab(pllIndex, false); +} + + +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); @@ -259,7 +361,8 @@ PLLSet(uint8 pllIndex, uint32 pixelClock) postDivider |= post & 0x0000007F; uint32 control; - if (info.device_chipset >= (RADEON_R600 & 0x70)) + + if (info.device_chipset >= (RADEON_R600 | 0x70)) control = PLLControlTable(RV670PLLControl, feedback); else control = PLLControlTable(RV610PLLControl, feedback); @@ -324,14 +427,12 @@ PLLSet(uint8 pllIndex, uint32 pixelClock) DCCGCLKSet(pllIndex, RV620_DCCGCLK_GRAB); TRACE("%s: PLLSet exit\n", __func__); - return B_OK; } status_t PLLCalibrate(uint8 pllIndex) { - uint16 pllControlReg = (pllIndex == 1) ? P2PLL_CNTL : P1PLL_CNTL; Write32Mask(PLL, pllControlReg, 1, 0x01); @@ -407,6 +508,11 @@ PLLCRTCGrab(uint8 pllIndex, bool crt2) 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) diff --git a/src/add-ons/accelerants/radeon_hd/pll.h b/src/add-ons/accelerants/radeon_hd/pll.h index b94ad43c08..6604707fc4 100644 --- a/src/add-ons/accelerants/radeon_hd/pll.h +++ b/src/add-ons/accelerants/radeon_hd/pll.h @@ -42,6 +42,10 @@ struct PLL_Control { status_t PLLCalculate(uint32 pixelClock, uint16 *reference, uint16 *feedback, uint16 *post); status_t PLLSet(uint8 pllIndex, uint32 pixelClock); +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, bool crt2);