/* Copyright (c) 2002/03, Thomas Kurschel Part of Radeon driver and accelerant Basic access of PLL registers */ #include "radeon_interface.h" #include "pll_access.h" #include "pll_regs.h" #include "crtc_regs.h" #include "utils.h" void RADEONPllErrataAfterIndex( vuint8 *regs, radeon_type asic ) { if (! ((asic == rt_rv200) || (asic == rt_rs200))) return; /* This workaround is necessary on rv200 and RS200 or PLL * reads may return garbage (among others...) */ INREG( regs, RADEON_CLOCK_CNTL_DATA); INREG( regs, RADEON_CRTC_GEN_CNTL); } void RADEONPllErrataAfterData( vuint8 *regs, radeon_type asic ) { uint32 save, tmp; /* This workarounds is necessary on RV100, RS100 and RS200 chips * or the chip could hang on a subsequent access */ if ((asic == rt_rv100) || (asic == rt_rs100) || (asic == rt_rs200)) { /* we can't deal with posted writes here ... */ snooze(5000); } /* This function is required to workaround a hardware bug in some (all?) * revisions of the R300. This workaround should be called after every * CLOCK_CNTL_INDEX register access. If not, register reads afterward * may not be correct. */ if( asic != rt_r300 ) return; save = INREG( regs, RADEON_CLOCK_CNTL_INDEX ); tmp = save & ~(0x3f | RADEON_PLL_WR_EN); OUTREG( regs, RADEON_CLOCK_CNTL_INDEX, tmp ); tmp = INREG( regs, RADEON_CLOCK_CNTL_DATA ); OUTREG( regs, RADEON_CLOCK_CNTL_INDEX, save ); } // read value "val" from PLL-register "addr" uint32 Radeon_INPLL( vuint8 *regs, radeon_type asic, int addr ) { uint32 res; OUTREG8( regs, RADEON_CLOCK_CNTL_INDEX, addr & 0x3f ); RADEONPllErrataAfterIndex(regs, asic); res = INREG( regs, RADEON_CLOCK_CNTL_DATA ); RADEONPllErrataAfterData(regs, asic); return res; } // write value "val" to PLL-register "addr" void Radeon_OUTPLL( vuint8 *regs, radeon_type asic, uint8 addr, uint32 val ) { (void)asic; OUTREG8( regs, RADEON_CLOCK_CNTL_INDEX, ((addr & 0x3f ) | RADEON_PLL_WR_EN)); RADEONPllErrataAfterIndex(regs, asic); OUTREG( regs, RADEON_CLOCK_CNTL_DATA, val ); RADEONPllErrataAfterData(regs, asic); } // write "val" to PLL-register "addr" keeping bits "mask" void Radeon_OUTPLLP( vuint8 *regs, radeon_type asic, uint8 addr, uint32 val, uint32 mask ) { uint32 tmp = Radeon_INPLL( regs, asic, addr ); tmp &= mask; tmp |= val; Radeon_OUTPLL( regs, asic, addr, tmp ); }