root/src/add-ons/kernel/drivers/graphics/radeon/pll_access.c
/*
        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 );
}