forked from KolibriOS/kolibrios
80c71dc52a
git-svn-id: svn://kolibrios.org@1002 a494cfbc-eb01-0410-851d-a64ba20cac60
397 lines
13 KiB
C
397 lines
13 KiB
C
#define RADEON_SCRATCH_REG0 0x15e0
|
|
#define RADEON_SCRATCH_REG1 0x15e4
|
|
#define RADEON_SCRATCH_REG2 0x15e8
|
|
#define RADEON_SCRATCH_REG3 0x15ec
|
|
#define RADEON_SCRATCH_REG4 0x15f0
|
|
#define RADEON_SCRATCH_REG5 0x15f4
|
|
#define RADEON_SCRATCH_UMSK 0x0770
|
|
#define RADEON_SCRATCH_ADDR 0x0774
|
|
|
|
# define RS400_BUS_MASTER_DIS (1 << 14)
|
|
//# define RADEON_BUS_MASTER_DIS (1 << 6)
|
|
|
|
#define RADEON_ISYNC_CNTL 0x1724
|
|
# define RADEON_ISYNC_ANY2D_IDLE3D (1 << 0)
|
|
# define RADEON_ISYNC_ANY3D_IDLE2D (1 << 1)
|
|
# define RADEON_ISYNC_TRIG2D_IDLE3D (1 << 2)
|
|
# define RADEON_ISYNC_TRIG3D_IDLE2D (1 << 3)
|
|
# define RADEON_ISYNC_WAIT_IDLEGUI (1 << 4)
|
|
# define RADEON_ISYNC_CPSCRATCH_IDLEGUI (1 << 5)
|
|
|
|
|
|
#define RADEON_IDLE_RETRY 16 /* Fall out of idle loops after this count */
|
|
#define RADEON_TIMEOUT 4000000 /* Fall out of wait loops after this count */
|
|
|
|
|
|
|
|
void RADEONEngineFlush(RHDPtr info)
|
|
{
|
|
int i;
|
|
|
|
if (info->ChipFamily <= CHIP_FAMILY_RV280)
|
|
{
|
|
MASKREG(RADEON_RB3D_DSTCACHE_CTLSTAT,RADEON_RB3D_DC_FLUSH_ALL,
|
|
~RADEON_RB3D_DC_FLUSH_ALL);
|
|
for (i = 0; i < RADEON_TIMEOUT; i++) {
|
|
if (!(INREG(RADEON_RB3D_DSTCACHE_CTLSTAT) & RADEON_RB3D_DC_BUSY))
|
|
break;
|
|
}
|
|
if (i == RADEON_TIMEOUT) {
|
|
dbgprintf("DC flush timeout: %x\n",
|
|
(u32_t)INREG(RADEON_RB3D_DSTCACHE_CTLSTAT));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// MASKREG(R300_DSTCACHE_CTLSTAT,R300_RB2D_DC_FLUSH_ALL,
|
|
// ~R300_RB2D_DC_FLUSH_ALL);
|
|
// for (i = 0; i < RADEON_TIMEOUT; i++) {
|
|
// if (!(INREG(R300_DSTCACHE_CTLSTAT) & R300_RB2D_DC_BUSY))
|
|
// break;
|
|
// }
|
|
// if (i == RADEON_TIMEOUT) {
|
|
// dbgprintf("DC flush timeout: %x\n",
|
|
// (u32_t)INREG(R300_DSTCACHE_CTLSTAT));
|
|
// }
|
|
}
|
|
}
|
|
|
|
static Bool R5xxFIFOWaitLocal(u32_t required) //R100-R500
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < RADEON_TIMEOUT; i++)
|
|
if (required <= (INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK))
|
|
return TRUE;
|
|
|
|
dbgprintf("%s: Timeout 0x%08X.\n", __func__, (u32_t) INREG(RADEON_RBBM_STATUS));
|
|
return FALSE;
|
|
}
|
|
|
|
static int radeon_do_wait_for_idle()
|
|
{
|
|
int i, ret;
|
|
|
|
ret = R5xxFIFOWaitLocal(64);
|
|
if (ret)
|
|
return ret;
|
|
|
|
for (i = 0; i < RADEON_TIMEOUT; i++)
|
|
{
|
|
if (!(INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE)) {
|
|
RADEONEngineFlush(&rhd);
|
|
return 0;
|
|
}
|
|
usleep(1);
|
|
}
|
|
dbgprintf("wait idle failed status : 0x%08X 0x%08X\n",
|
|
INREG(RADEON_RBBM_STATUS),
|
|
INREG(R300_VAP_CNTL_STATUS));
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/* ================================================================
|
|
* CP control, initialization
|
|
*/
|
|
|
|
/* Load the microcode for the CP */
|
|
|
|
#include "radeon_microcode.h"
|
|
|
|
static void load_microcode(RHDPtr info)
|
|
{
|
|
int i;
|
|
const u32_t (*microcode)[2];
|
|
|
|
OUTREG(RADEON_CP_ME_RAM_ADDR, 0);
|
|
|
|
if ( (info->ChipFamily == CHIP_FAMILY_LEGACY ) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RADEON ) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV100 ) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV200 ) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS100 ) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS200 ))
|
|
{
|
|
microcode = R100_cp_microcode;
|
|
dbgprintf("Loading R100 Microcode\n");
|
|
}
|
|
else if ((info->ChipFamily == CHIP_FAMILY_R200 ) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV250) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV280) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS300))
|
|
{
|
|
microcode = R200_cp_microcode;
|
|
dbgprintf("Loading R200 Microcode\n");
|
|
}
|
|
else if ((info->ChipFamily == CHIP_FAMILY_R300) ||
|
|
(info->ChipFamily == CHIP_FAMILY_R350) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV350) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV380) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS400) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS480))
|
|
{
|
|
dbgprintf("Loading R300 Microcode\n");
|
|
microcode = R300_cp_microcode;
|
|
}
|
|
else if ((info->ChipFamily == CHIP_FAMILY_R420) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV410))
|
|
{
|
|
dbgprintf("Loading R400 Microcode\n");
|
|
microcode = R420_cp_microcode;
|
|
|
|
}
|
|
else if ((info->ChipFamily == CHIP_FAMILY_RS600) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS690) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS740))
|
|
{
|
|
dbgprintf("Loading RS690/RS740 Microcode\n");
|
|
microcode = RS690_cp_microcode;
|
|
}
|
|
else if ((info->ChipFamily == CHIP_FAMILY_RV515) ||
|
|
(info->ChipFamily == CHIP_FAMILY_R520) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV530) ||
|
|
(info->ChipFamily == CHIP_FAMILY_R580) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV560) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV570))
|
|
{
|
|
dbgprintf("Loading R500 Microcode\n");
|
|
microcode = R520_cp_microcode;
|
|
}
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
OUTREG(RADEON_CP_ME_RAM_DATAH, microcode[i][1]);
|
|
OUTREG(RADEON_CP_ME_RAM_DATAL, microcode[i][0]);
|
|
}
|
|
}
|
|
|
|
|
|
void init_ring_buffer(RHDPtr info)
|
|
{
|
|
u32_t ring_base;
|
|
u32_t tmp;
|
|
|
|
info->ringBase = CreateRingBuffer( 64*1024, PG_SW);
|
|
|
|
dbgprintf("create cp ring buffer %x\n", rhd.ringBase);
|
|
ring_base = GetPgAddr(rhd.ringBase);
|
|
dbgprintf("ring base %x\n", ring_base);
|
|
|
|
OUTREG(RADEON_CP_RB_BASE, ring_base);
|
|
|
|
info->ring_avail = 64*1024/4 ;
|
|
|
|
/* Set the write pointer delay */
|
|
OUTREG(RADEON_CP_RB_WPTR_DELAY, 0);
|
|
|
|
/* Initialize the ring buffer's read and write pointers */
|
|
rhd.ring_rp = rhd.ring_wp = INREG(RADEON_CP_RB_RPTR);
|
|
rhd.host_rp = rhd.ring_rp;
|
|
|
|
OUTREG(RADEON_CP_RB_WPTR,rhd.ring_rp);
|
|
|
|
tmp = (((u32_t)&rhd.host_rp) & 4095) + GetPgAddr((void*)&rhd.host_rp);
|
|
|
|
OUTREG(RADEON_CP_RB_RPTR_ADDR, tmp); // ring buffer read pointer
|
|
|
|
/* Set ring buffer size */
|
|
OUTREG(RADEON_CP_RB_CNTL, (1<<27)|(0<<18)|(10<<8)|13);
|
|
|
|
/* Initialize the scratch register pointer. This will cause
|
|
* the scratch register values to be written out to memory
|
|
* whenever they are updated.
|
|
*
|
|
* We simply put this behind the ring read pointer, this works
|
|
* with PCI GART as well as (whatever kind of) AGP GART
|
|
*/
|
|
|
|
tmp = (((u32_t)&rhd.scratch0) & 4095) + GetPgAddr((void*)&rhd.scratch0);
|
|
OUTREG(RADEON_SCRATCH_ADDR, tmp);
|
|
|
|
OUTREG(RADEON_SCRATCH_UMSK, 0x0);
|
|
//OUTREG(0x778, 1);
|
|
|
|
/* Turn on bus mastering */
|
|
if ( (info->ChipFamily == CHIP_FAMILY_RS400) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS690) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS740) )
|
|
{
|
|
/* rs400, rs690/rs740 */
|
|
tmp = INREG(RADEON_BUS_CNTL) & ~RS400_BUS_MASTER_DIS;
|
|
OUTREG(RADEON_BUS_CNTL, tmp);
|
|
}
|
|
else if (!((info->ChipFamily == CHIP_FAMILY_RV380) ||
|
|
(info->ChipFamily >= CHIP_FAMILY_R420)))
|
|
{
|
|
/* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */
|
|
tmp = INREG(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
|
|
OUTREG(RADEON_BUS_CNTL, tmp);
|
|
} /* PCIE cards appears to not need this */
|
|
|
|
tmp = INREG(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
|
|
OUTREG(RADEON_BUS_CNTL, tmp);
|
|
|
|
radeon_do_wait_for_idle();
|
|
|
|
/* Sync everything up */
|
|
OUTREG(RADEON_ISYNC_CNTL,
|
|
(RADEON_ISYNC_ANY2D_IDLE3D |
|
|
RADEON_ISYNC_ANY3D_IDLE2D |
|
|
RADEON_ISYNC_WAIT_IDLEGUI |
|
|
RADEON_ISYNC_CPSCRATCH_IDLEGUI));
|
|
}
|
|
|
|
|
|
void radeon_engine_reset(RHDPtr info)
|
|
{
|
|
u32_t clock_cntl_index;
|
|
u32_t mclk_cntl;
|
|
u32_t rbbm_soft_reset;
|
|
u32_t host_path_cntl;
|
|
|
|
if (info->ChipFamily <= CHIP_FAMILY_RV410)
|
|
{
|
|
/* may need something similar for newer chips */
|
|
clock_cntl_index = INREG(RADEON_CLOCK_CNTL_INDEX);
|
|
mclk_cntl = INPLL( RADEON_MCLK_CNTL);
|
|
|
|
OUTPLL(RADEON_MCLK_CNTL, (mclk_cntl |
|
|
RADEON_FORCEON_MCLKA |
|
|
RADEON_FORCEON_MCLKB |
|
|
RADEON_FORCEON_YCLKA |
|
|
RADEON_FORCEON_YCLKB |
|
|
RADEON_FORCEON_MC |
|
|
RADEON_FORCEON_AIC));
|
|
}
|
|
|
|
rbbm_soft_reset = INREG(RADEON_RBBM_SOFT_RESET);
|
|
|
|
OUTREG(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
|
|
RADEON_SOFT_RESET_CP |
|
|
RADEON_SOFT_RESET_HI |
|
|
RADEON_SOFT_RESET_SE |
|
|
RADEON_SOFT_RESET_RE |
|
|
RADEON_SOFT_RESET_PP |
|
|
RADEON_SOFT_RESET_E2 |
|
|
RADEON_SOFT_RESET_RB));
|
|
INREG(RADEON_RBBM_SOFT_RESET);
|
|
OUTREG(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
|
|
~(RADEON_SOFT_RESET_CP |
|
|
RADEON_SOFT_RESET_HI |
|
|
RADEON_SOFT_RESET_SE |
|
|
RADEON_SOFT_RESET_RE |
|
|
RADEON_SOFT_RESET_PP |
|
|
RADEON_SOFT_RESET_E2 |
|
|
RADEON_SOFT_RESET_RB)));
|
|
INREG(RADEON_RBBM_SOFT_RESET);
|
|
|
|
if (info->ChipFamily <= CHIP_FAMILY_RV410) {
|
|
OUTPLL(RADEON_MCLK_CNTL, mclk_cntl);
|
|
OUTREG(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index);
|
|
OUTREG(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
|
|
}
|
|
};
|
|
|
|
#define RADEON_WAIT_UNTIL_IDLE() do { \
|
|
OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 1 ) ); \
|
|
OUT_RING( (RADEON_WAIT_2D_IDLECLEAN | \
|
|
RADEON_WAIT_3D_IDLECLEAN | \
|
|
RADEON_WAIT_HOST_IDLECLEAN) ); \
|
|
} while (0)
|
|
|
|
#define R300_ZB_ZCACHE_CTLSTAT 0x4f18
|
|
# define RADEON_RB3D_ZC_FLUSH (1 << 0)
|
|
# define RADEON_RB3D_ZC_FREE (1 << 2)
|
|
# define RADEON_RB3D_ZC_FLUSH_ALL 0x5
|
|
# define RADEON_RB3D_ZC_BUSY (1 << 31)
|
|
# define R300_ZC_FLUSH (1 << 0)
|
|
# define R300_ZC_FREE (1 << 1)
|
|
# define R300_ZC_BUSY (1 << 31)
|
|
# define RADEON_RB3D_DC_FLUSH (3 << 0)
|
|
# define RADEON_RB3D_DC_FREE (3 << 2)
|
|
# define RADEON_RB3D_DC_FLUSH_ALL 0xf
|
|
# define RADEON_RB3D_DC_BUSY (1 << 31)
|
|
# define R300_RB3D_DC_FLUSH (2 << 0)
|
|
# define R300_RB3D_DC_FREE (2 << 2)
|
|
#
|
|
#define RADEON_PURGE_CACHE() do { \
|
|
if ( rhd.ChipFamily <= CHIP_FAMILY_RV280) { \
|
|
OUT_RING(CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 1)); \
|
|
OUT_RING(RADEON_RB3D_DC_FLUSH | RADEON_RB3D_DC_FREE); \
|
|
} else { \
|
|
OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 1)); \
|
|
OUT_RING(R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE ); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define RADEON_FLUSH_ZCACHE() do { \
|
|
if ( rhd.ChipFamily <= CHIP_FAMILY_RV280) { \
|
|
OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 1 ) ); \
|
|
OUT_RING( RADEON_RB3D_ZC_FLUSH ); \
|
|
} else { \
|
|
OUT_RING( CP_PACKET0( R300_ZB_ZCACHE_CTLSTAT, 1 ) ); \
|
|
OUT_RING( R300_ZC_FLUSH ); \
|
|
} \
|
|
} while (0)
|
|
#define RADEON_PURGE_ZCACHE() do { \
|
|
if (rhd.ChipFamily <= CHIP_FAMILY_RV280) { \
|
|
OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 1)); \
|
|
OUT_RING(RADEON_RB3D_ZC_FLUSH | RADEON_RB3D_ZC_FREE); \
|
|
} else { \
|
|
OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 1)); \
|
|
OUT_RING(R300_ZC_FLUSH | R300_ZC_FREE); \
|
|
} \
|
|
} while (0)
|
|
|
|
static int radeon_cp_start(RHDPtr info)
|
|
{
|
|
u32_t *ring, write;
|
|
u32_t ifl;
|
|
radeon_do_wait_for_idle(64);
|
|
|
|
OUTREG(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM);
|
|
|
|
ifl = safe_cli();
|
|
|
|
BEGIN_RING(8);
|
|
/* isync can only be written through cp on r5xx write it here */
|
|
OUT_RING(CP_PACKET0(RADEON_ISYNC_CNTL, 1));
|
|
OUT_RING(RADEON_ISYNC_ANY2D_IDLE3D |
|
|
RADEON_ISYNC_ANY3D_IDLE2D |
|
|
RADEON_ISYNC_WAIT_IDLEGUI |
|
|
RADEON_ISYNC_CPSCRATCH_IDLEGUI);
|
|
RADEON_PURGE_CACHE();
|
|
RADEON_PURGE_ZCACHE();
|
|
RADEON_WAIT_UNTIL_IDLE();
|
|
ADVANCE_RING();
|
|
COMMIT_RING();
|
|
|
|
safe_sti(ifl);
|
|
|
|
radeon_do_wait_for_idle();
|
|
};
|
|
|
|
|
|
Bool init_cp(RHDPtr info)
|
|
{
|
|
load_microcode(&rhd);
|
|
|
|
init_ring_buffer(&rhd);
|
|
|
|
radeon_engine_reset(&rhd);
|
|
|
|
/* setup the raster pipes */
|
|
init_pipes(&rhd);
|
|
|
|
rhd.ring_rp = rhd.ring_wp = INREG(RADEON_CP_RB_RPTR);
|
|
OUTREG(RADEON_CP_RB_WPTR, rhd.ring_rp);
|
|
|
|
radeon_cp_start(&rhd);
|
|
|
|
return TRUE;
|
|
};
|
|
|
|
|