mirror of
https://github.com/KolibriOS/kolibrios.git
synced 2024-12-24 23:56:49 +03:00
07946bd629
git-svn-id: svn://kolibrios.org@1406 a494cfbc-eb01-0410-851d-a64ba20cac60
1270 lines
41 KiB
C
1270 lines
41 KiB
C
|
|
|
|
static Bool rhdMapMMIO(RHDPtr rhdPtr)
|
|
{
|
|
rhdPtr->MMIOMapSize = 1 << rhdPtr->memsize[RHD_MMIO_BAR];
|
|
rhdPtr->MMIOBase = MapIoMem(rhdPtr->memBase[RHD_MMIO_BAR],
|
|
rhdPtr->MMIOMapSize,PG_SW+PG_NOCACHE);
|
|
if( rhdPtr->MMIOBase==0)
|
|
return 0;
|
|
|
|
DBG(dbgprintf("Mapped IO at %x (size %x)\n", rhdPtr->MMIOBase, rhdPtr->MMIOMapSize));
|
|
return 1;
|
|
}
|
|
|
|
/* Read MC register */
|
|
unsigned INMC(RHDPtr info, int addr)
|
|
{
|
|
u32_t data;
|
|
|
|
if ((info->ChipFamily == CHIP_FAMILY_RS690) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS740)) {
|
|
OUTREG(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK));
|
|
data = INREG(RS690_MC_DATA);
|
|
} else if (info->ChipFamily == CHIP_FAMILY_RS600) {
|
|
OUTREG(RS600_MC_INDEX, (addr & RS600_MC_INDEX_MASK));
|
|
data = INREG(RS600_MC_DATA);
|
|
} else if (IS_AVIVO_VARIANT) {
|
|
OUTREG(AVIVO_MC_INDEX, (addr & 0xff) | 0x7f0000);
|
|
(void)INREG(AVIVO_MC_INDEX);
|
|
data = INREG(AVIVO_MC_DATA);
|
|
|
|
OUTREG(AVIVO_MC_INDEX, 0);
|
|
(void)INREG(AVIVO_MC_INDEX);
|
|
} else {
|
|
OUTREG(R300_MC_IND_INDEX, addr & 0x3f);
|
|
(void)INREG(R300_MC_IND_INDEX);
|
|
data = INREG(R300_MC_IND_DATA);
|
|
|
|
OUTREG(R300_MC_IND_INDEX, 0);
|
|
(void)INREG(R300_MC_IND_INDEX);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/* Write MC information */
|
|
void OUTMC(RHDPtr info, int addr, u32_t data)
|
|
{
|
|
if ((info->ChipFamily == CHIP_FAMILY_RS690) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS740)) {
|
|
OUTREG(RS690_MC_INDEX, ((addr & RS690_MC_INDEX_MASK) | RS690_MC_INDEX_WR_EN));
|
|
OUTREG(RS690_MC_DATA, data);
|
|
OUTREG(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK);
|
|
}
|
|
else if (info->ChipFamily == CHIP_FAMILY_RS600) {
|
|
OUTREG(RS600_MC_INDEX, ((addr & RS600_MC_INDEX_MASK) | RS600_MC_INDEX_WR_EN));
|
|
OUTREG(RS600_MC_DATA, data);
|
|
OUTREG(RS600_MC_INDEX, RS600_MC_INDEX_WR_ACK);
|
|
}
|
|
else if (IS_AVIVO_VARIANT) {
|
|
OUTREG(AVIVO_MC_INDEX, (addr & 0xff) | 0xff0000);
|
|
(void)INREG(AVIVO_MC_INDEX);
|
|
OUTREG(AVIVO_MC_DATA, data);
|
|
OUTREG(AVIVO_MC_INDEX, 0);
|
|
(void)INREG(AVIVO_MC_INDEX);
|
|
}
|
|
else {
|
|
OUTREG(R300_MC_IND_INDEX, (((addr) & 0x3f) | R300_MC_IND_WR_EN));
|
|
(void)INREG(R300_MC_IND_INDEX);
|
|
OUTREG(R300_MC_IND_DATA, data);
|
|
OUTREG(R300_MC_IND_INDEX, 0);
|
|
(void)INREG(R300_MC_IND_INDEX);
|
|
}
|
|
}
|
|
|
|
static Bool avivo_get_mc_idle(RHDPtr info)
|
|
{
|
|
|
|
if (info->ChipFamily >= CHIP_FAMILY_R600) {
|
|
/* no idea where this is on r600 yet */
|
|
return TRUE;
|
|
}
|
|
else if (info->ChipFamily == CHIP_FAMILY_RV515) {
|
|
if (INMC(info, RV515_MC_STATUS) & RV515_MC_STATUS_IDLE)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
else if (info->ChipFamily == CHIP_FAMILY_RS600)
|
|
{
|
|
if (INMC(info, RS600_MC_STATUS) & RS600_MC_STATUS_IDLE)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
else if ((info->ChipFamily == CHIP_FAMILY_RS690) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS740)) {
|
|
if (INMC(info, RS690_MC_STATUS) & RS690_MC_STATUS_IDLE)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
else {
|
|
if (INMC(info, R520_MC_STATUS) & R520_MC_STATUS_IDLE)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
#define LOC_FB 0x1
|
|
#define LOC_AGP 0x2
|
|
|
|
static void radeon_read_mc_fb_agp_location(RHDPtr info, int mask,
|
|
u32_t *fb_loc, u32_t *agp_loc, u32_t *agp_loc_hi)
|
|
{
|
|
|
|
if (info->ChipFamily >= CHIP_FAMILY_RV770)
|
|
{
|
|
if (mask & LOC_FB)
|
|
*fb_loc = INREG(R700_MC_VM_FB_LOCATION);
|
|
if (mask & LOC_AGP) {
|
|
*agp_loc = INREG(R600_MC_VM_AGP_BOT);
|
|
*agp_loc_hi = INREG(R600_MC_VM_AGP_TOP);
|
|
}
|
|
}
|
|
else if (info->ChipFamily >= CHIP_FAMILY_R600)
|
|
{
|
|
if (mask & LOC_FB)
|
|
*fb_loc = INREG(R600_MC_VM_FB_LOCATION);
|
|
if (mask & LOC_AGP) {
|
|
*agp_loc = INREG(R600_MC_VM_AGP_BOT);
|
|
*agp_loc_hi = INREG(R600_MC_VM_AGP_TOP);
|
|
}
|
|
}
|
|
else if (info->ChipFamily == CHIP_FAMILY_RV515)
|
|
{
|
|
if (mask & LOC_FB)
|
|
*fb_loc = INMC(info, RV515_MC_FB_LOCATION);
|
|
if (mask & LOC_AGP) {
|
|
*agp_loc = INMC(info, RV515_MC_AGP_LOCATION);
|
|
*agp_loc_hi = 0;
|
|
}
|
|
}
|
|
else if (info->ChipFamily == CHIP_FAMILY_RS600)
|
|
{
|
|
if (mask & LOC_FB)
|
|
*fb_loc = INMC(info, RS600_MC_FB_LOCATION);
|
|
if (mask & LOC_AGP) {
|
|
*agp_loc = 0;//INMC(pScrn, RS600_MC_AGP_LOCATION);
|
|
*agp_loc_hi = 0;
|
|
}
|
|
}
|
|
else if ((info->ChipFamily == CHIP_FAMILY_RS690) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS740))
|
|
{
|
|
if (mask & LOC_FB)
|
|
*fb_loc = INMC(info, RS690_MC_FB_LOCATION);
|
|
if (mask & LOC_AGP) {
|
|
*agp_loc = INMC(info, RS690_MC_AGP_LOCATION);
|
|
*agp_loc_hi = 0;
|
|
}
|
|
}
|
|
else if (info->ChipFamily >= CHIP_FAMILY_R520)
|
|
{
|
|
if (mask & LOC_FB)
|
|
*fb_loc = INMC(info, R520_MC_FB_LOCATION);
|
|
if (mask & LOC_AGP) {
|
|
*agp_loc = INMC(info, R520_MC_AGP_LOCATION);
|
|
*agp_loc_hi = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mask & LOC_FB)
|
|
*fb_loc = INREG(RADEON_MC_FB_LOCATION);
|
|
if (mask & LOC_AGP)
|
|
*agp_loc = INREG(RADEON_MC_AGP_LOCATION);
|
|
}
|
|
}
|
|
|
|
static void radeon_write_mc_fb_agp_location(RHDPtr info, int mask, u32_t fb_loc,
|
|
u32_t agp_loc, u32_t agp_loc_hi)
|
|
{
|
|
|
|
if (info->ChipFamily >= CHIP_FAMILY_RV770) {
|
|
if (mask & LOC_FB)
|
|
OUTREG(R700_MC_VM_FB_LOCATION, fb_loc);
|
|
if (mask & LOC_AGP) {
|
|
OUTREG(R600_MC_VM_AGP_BOT, agp_loc);
|
|
OUTREG(R600_MC_VM_AGP_TOP, agp_loc_hi);
|
|
}
|
|
}
|
|
else if (info->ChipFamily >= CHIP_FAMILY_R600)
|
|
{
|
|
if (mask & LOC_FB)
|
|
OUTREG(R600_MC_VM_FB_LOCATION, fb_loc);
|
|
if (mask & LOC_AGP) {
|
|
OUTREG(R600_MC_VM_AGP_BOT, agp_loc);
|
|
OUTREG(R600_MC_VM_AGP_TOP, agp_loc_hi);
|
|
}
|
|
}
|
|
else if (info->ChipFamily == CHIP_FAMILY_RV515)
|
|
{
|
|
if (mask & LOC_FB)
|
|
OUTMC(info, RV515_MC_FB_LOCATION, fb_loc);
|
|
if (mask & LOC_AGP)
|
|
OUTMC(info, RV515_MC_AGP_LOCATION, agp_loc);
|
|
(void)INMC(info, RV515_MC_AGP_LOCATION);
|
|
}
|
|
else if (info->ChipFamily == CHIP_FAMILY_RS600)
|
|
{
|
|
if (mask & LOC_FB)
|
|
OUTMC(info, RS600_MC_FB_LOCATION, fb_loc);
|
|
/* if (mask & LOC_AGP)
|
|
OUTMC(pScrn, RS600_MC_AGP_LOCATION, agp_loc);*/
|
|
}
|
|
else if ((info->ChipFamily == CHIP_FAMILY_RS690) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS740))
|
|
{
|
|
if (mask & LOC_FB)
|
|
OUTMC(info, RS690_MC_FB_LOCATION, fb_loc);
|
|
if (mask & LOC_AGP)
|
|
OUTMC(info, RS690_MC_AGP_LOCATION, agp_loc);
|
|
}
|
|
else if (info->ChipFamily >= CHIP_FAMILY_R520)
|
|
{
|
|
if (mask & LOC_FB)
|
|
OUTMC(info, R520_MC_FB_LOCATION, fb_loc);
|
|
if (mask & LOC_AGP)
|
|
OUTMC(info, R520_MC_AGP_LOCATION, agp_loc);
|
|
(void)INMC(info, R520_MC_FB_LOCATION);
|
|
}
|
|
else {
|
|
if (mask & LOC_FB)
|
|
OUTREG(RADEON_MC_FB_LOCATION, fb_loc);
|
|
if (mask & LOC_AGP)
|
|
OUTREG(RADEON_MC_AGP_LOCATION, agp_loc);
|
|
}
|
|
}
|
|
|
|
|
|
static void RADEONUpdateMemMapRegisters(RHDPtr info)
|
|
{
|
|
u32_t timeout;
|
|
|
|
u32_t mc_fb_loc, mc_agp_loc, mc_agp_loc_hi;
|
|
|
|
radeon_read_mc_fb_agp_location(info, LOC_FB | LOC_AGP, &mc_fb_loc,
|
|
&mc_agp_loc, &mc_agp_loc_hi);
|
|
|
|
if (IS_AVIVO_VARIANT)
|
|
{
|
|
|
|
if (mc_fb_loc != info->mc_fb_location ||
|
|
mc_agp_loc != info->mc_agp_location)
|
|
{
|
|
u32_t d1crtc, d2crtc;
|
|
u32_t tmp;
|
|
// RADEONWaitForIdleMMIO(pScrn);
|
|
|
|
OUTREG(AVIVO_D1VGA_CONTROL, INREG(AVIVO_D1VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE);
|
|
OUTREG(AVIVO_D2VGA_CONTROL, INREG(AVIVO_D2VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE);
|
|
|
|
/* Stop display & memory access */
|
|
d1crtc = INREG(AVIVO_D1CRTC_CONTROL);
|
|
OUTREG(AVIVO_D1CRTC_CONTROL, d1crtc & ~AVIVO_CRTC_EN);
|
|
|
|
d2crtc = INREG(AVIVO_D2CRTC_CONTROL);
|
|
OUTREG(AVIVO_D2CRTC_CONTROL, d2crtc & ~AVIVO_CRTC_EN);
|
|
|
|
tmp = INREG(AVIVO_D2CRTC_CONTROL);
|
|
|
|
usleep(1000);
|
|
timeout = 0;
|
|
while (!(avivo_get_mc_idle(info)))
|
|
{
|
|
if (++timeout > 1000000)
|
|
{
|
|
dbgprintf("Timeout trying to update memory controller settings !\n");
|
|
dbgprintf("You will probably crash now ... \n");
|
|
/* Nothing we can do except maybe try to kill the server,
|
|
* let's wait 2 seconds to leave the above message a chance
|
|
* to maybe hit the disk and continue trying to setup despite
|
|
* the MC being non-idle
|
|
*/
|
|
usleep(20000);
|
|
}
|
|
usleep(10);
|
|
}
|
|
|
|
radeon_write_mc_fb_agp_location(info, LOC_FB | LOC_AGP,
|
|
info->mc_fb_location,
|
|
info->mc_agp_location,
|
|
info->mc_agp_location_hi);
|
|
|
|
if (info->ChipFamily < CHIP_FAMILY_R600) {
|
|
OUTREG(AVIVO_HDP_FB_LOCATION, info->mc_fb_location);
|
|
}
|
|
else {
|
|
OUTREG(R600_HDP_NONSURFACE_BASE, (info->mc_fb_location << 16) & 0xff0000);
|
|
}
|
|
|
|
OUTREG(AVIVO_D1CRTC_CONTROL, d1crtc );
|
|
|
|
OUTREG(AVIVO_D2CRTC_CONTROL, d2crtc );
|
|
|
|
tmp = INREG(AVIVO_D2CRTC_CONTROL);
|
|
|
|
/* Reset the engine and HDP */
|
|
// RADEONEngineReset(pScrn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
/* Write memory mapping registers only if their value change
|
|
* since we must ensure no access is done while they are
|
|
* reprogrammed
|
|
*/
|
|
if ( mc_fb_loc != info->mc_fb_location ||
|
|
mc_agp_loc != info->mc_agp_location)
|
|
{
|
|
u32_t crtc_ext_cntl, crtc_gen_cntl, crtc2_gen_cntl=0, ov0_scale_cntl;
|
|
u32_t old_mc_status, status_idle;
|
|
|
|
dbgprintf(" Map Changed ! Applying ...\n");
|
|
|
|
/* Make sure engine is idle. We assume the CCE is stopped
|
|
* at this point
|
|
*/
|
|
// RADEONWaitForIdleMMIO(info);
|
|
|
|
if (info->IsIGP)
|
|
goto igp_no_mcfb;
|
|
|
|
/* Capture MC_STATUS in case things go wrong ... */
|
|
old_mc_status = INREG(RADEON_MC_STATUS);
|
|
|
|
/* Stop display & memory access */
|
|
ov0_scale_cntl = INREG(RADEON_OV0_SCALE_CNTL);
|
|
OUTREG(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl & ~RADEON_SCALER_ENABLE);
|
|
crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL);
|
|
OUTREG(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl | RADEON_CRTC_DISPLAY_DIS);
|
|
crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL);
|
|
// RADEONWaitForVerticalSync(pScrn);
|
|
OUTREG(RADEON_CRTC_GEN_CNTL,
|
|
(crtc_gen_cntl & ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_ICON_EN))
|
|
| RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_EXT_DISP_EN);
|
|
|
|
if (info->HasCRTC2)
|
|
{
|
|
crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL);
|
|
// RADEONWaitForVerticalSync2(pScrn);
|
|
OUTREG(RADEON_CRTC2_GEN_CNTL, (crtc2_gen_cntl
|
|
& ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_ICON_EN))
|
|
| RADEON_CRTC2_DISP_REQ_EN_B);
|
|
}
|
|
|
|
/* Make sure the chip settles down (paranoid !) */
|
|
usleep(1000);
|
|
|
|
/* Wait for MC idle */
|
|
if (IS_R300_VARIANT)
|
|
status_idle = R300_MC_IDLE;
|
|
else
|
|
status_idle = RADEON_MC_IDLE;
|
|
|
|
timeout = 0;
|
|
while (!(INREG(RADEON_MC_STATUS) & status_idle))
|
|
{
|
|
if (++timeout > 1000000)
|
|
{
|
|
dbgprintf("Timeout trying to update memory controller settings !\n");
|
|
dbgprintf("MC_STATUS = 0x%08x (on entry = 0x%08x)\n",
|
|
INREG(RADEON_MC_STATUS), old_mc_status);
|
|
dbgprintf("You will probably crash now ... \n");
|
|
/* Nothing we can do except maybe try to kill the server,
|
|
* let's wait 2 seconds to leave the above message a chance
|
|
* to maybe hit the disk and continue trying to setup despite
|
|
* the MC being non-idle
|
|
*/
|
|
usleep(20000);
|
|
}
|
|
usleep(10);
|
|
}
|
|
|
|
/* Update maps, first clearing out AGP to make sure we don't get
|
|
* a temporary overlap
|
|
*/
|
|
OUTREG(RADEON_MC_AGP_LOCATION, 0xfffffffc);
|
|
OUTREG(RADEON_MC_FB_LOCATION, info->mc_fb_location);
|
|
radeon_write_mc_fb_agp_location(info, LOC_FB | LOC_AGP, info->mc_fb_location,
|
|
0xfffffffc, 0);
|
|
|
|
OUTREG(RADEON_CRTC_GEN_CNTL,crtc_gen_cntl );
|
|
OUTREG(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
|
|
OUTREG(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl );
|
|
|
|
|
|
igp_no_mcfb:
|
|
radeon_write_mc_fb_agp_location(info, LOC_AGP, 0,
|
|
info->mc_agp_location, 0);
|
|
/* Make sure map fully reached the chip */
|
|
(void)INREG(RADEON_MC_FB_LOCATION);
|
|
|
|
dbgprintf(" Map applied, resetting engine ...\n");
|
|
|
|
/* Reset the engine and HDP */
|
|
// RADEONEngineReset(pScrn);
|
|
|
|
/* Make sure we have sane offsets before re-enabling the CRTCs, disable
|
|
* stereo, clear offsets, and wait for offsets to catch up with hw
|
|
*/
|
|
|
|
OUTREG(RADEON_CRTC_OFFSET_CNTL, RADEON_CRTC_OFFSET_FLIP_CNTL);
|
|
OUTREG(RADEON_CRTC_OFFSET, 0);
|
|
OUTREG(RADEON_CUR_OFFSET, 0);
|
|
timeout = 0;
|
|
while(INREG(RADEON_CRTC_OFFSET) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET)
|
|
{
|
|
if (timeout++ > 1000000) {
|
|
dbgprintf("Timeout waiting for CRTC offset to update !\n");
|
|
break;
|
|
}
|
|
usleep(1000);
|
|
}
|
|
if (info->HasCRTC2)
|
|
{
|
|
OUTREG(RADEON_CRTC2_OFFSET_CNTL, RADEON_CRTC2_OFFSET_FLIP_CNTL);
|
|
OUTREG(RADEON_CRTC2_OFFSET, 0);
|
|
OUTREG(RADEON_CUR2_OFFSET, 0);
|
|
timeout = 0;
|
|
while(INREG(RADEON_CRTC2_OFFSET) & RADEON_CRTC2_OFFSET__GUI_TRIG_OFFSET)
|
|
{
|
|
if (timeout++ > 1000000) {
|
|
dbgprintf("Timeout waiting for CRTC2 offset to update !\n");
|
|
break;
|
|
}
|
|
usleep(1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
dbgprintf("Updating display base addresses...\n");
|
|
|
|
OUTREG(RADEON_DISPLAY_BASE_ADDR, info->fbLocation);
|
|
if (info->HasCRTC2)
|
|
OUTREG(RADEON_DISPLAY2_BASE_ADDR, info->fbLocation);
|
|
OUTREG(RADEON_OV0_BASE_ADDR, info->fbLocation);
|
|
(void)INREG(RADEON_OV0_BASE_ADDR);
|
|
|
|
/* More paranoia delays, wait 100ms */
|
|
usleep(1000);
|
|
|
|
dbgprintf("Memory map updated.\n");
|
|
};
|
|
};
|
|
|
|
|
|
static void RADEONInitMemoryMap(RHDPtr info)
|
|
{
|
|
u32_t mem_size;
|
|
u32_t aper_size;
|
|
|
|
radeon_read_mc_fb_agp_location(info, LOC_FB | LOC_AGP, &info->mc_fb_location,
|
|
&info->mc_agp_location, &info->mc_agp_location_hi);
|
|
|
|
dbgprintf(" MC_FB_LOCATION : 0x%08x\n", (unsigned)info->mc_fb_location);
|
|
dbgprintf(" MC_AGP_LOCATION : 0x%08x\n", (unsigned)info->mc_agp_location);
|
|
|
|
|
|
/* We shouldn't use info->videoRam here which might have been clipped
|
|
* but the real video RAM instead
|
|
*/
|
|
if (info->ChipFamily >= CHIP_FAMILY_R600){
|
|
mem_size = INREG(R600_CONFIG_MEMSIZE);
|
|
aper_size = INREG(R600_CONFIG_APER_SIZE);
|
|
}
|
|
else {
|
|
mem_size = INREG(RADEON_CONFIG_MEMSIZE);
|
|
aper_size = INREG(RADEON_CONFIG_APER_SIZE);
|
|
}
|
|
|
|
if (mem_size == 0)
|
|
mem_size = 0x800000;
|
|
|
|
/* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM -
|
|
Novell bug 204882 + along with lots of ubuntu ones */
|
|
if (aper_size > mem_size)
|
|
mem_size = aper_size;
|
|
|
|
|
|
if ( (info->ChipFamily != CHIP_FAMILY_RS600) &&
|
|
(info->ChipFamily != CHIP_FAMILY_RS690) &&
|
|
(info->ChipFamily != CHIP_FAMILY_RS740))
|
|
{
|
|
if (info->IsIGP)
|
|
info->mc_fb_location = INREG(RADEON_NB_TOM);
|
|
else
|
|
{
|
|
u32_t aper0_base;
|
|
|
|
if (info->ChipFamily >= CHIP_FAMILY_R600) {
|
|
aper0_base = INREG(R600_CONFIG_F0_BASE);
|
|
}
|
|
else {
|
|
aper0_base = INREG(RADEON_CONFIG_APER_0_BASE);
|
|
}
|
|
dbgprintf("aper0 base %x\n", aper0_base );
|
|
|
|
/* Recent chips have an "issue" with the memory controller, the
|
|
* location must be aligned to the size. We just align it down,
|
|
* too bad if we walk over the top of system memory, we don't
|
|
* use DMA without a remapped anyway.
|
|
* Affected chips are rv280, all r3xx, and all r4xx, but not IGP
|
|
*/
|
|
if ( info->ChipFamily == CHIP_FAMILY_RV280 ||
|
|
info->ChipFamily == CHIP_FAMILY_R300 ||
|
|
info->ChipFamily == CHIP_FAMILY_R350 ||
|
|
info->ChipFamily == CHIP_FAMILY_RV350 ||
|
|
info->ChipFamily == CHIP_FAMILY_RV380 ||
|
|
info->ChipFamily == CHIP_FAMILY_R420 ||
|
|
info->ChipFamily == CHIP_FAMILY_RV410)
|
|
aper0_base &= ~(mem_size - 1);
|
|
|
|
if ( info->ChipFamily >= CHIP_FAMILY_R600) {
|
|
info->mc_fb_location = (aper0_base >> 24) |
|
|
(((aper0_base + mem_size - 1) & 0xff000000U) >> 8);
|
|
dbgprintf("mc fb loc is %08x\n", (unsigned int)info->mc_fb_location);
|
|
}
|
|
else {
|
|
info->mc_fb_location = (aper0_base >> 16) |
|
|
((aper0_base + mem_size - 1) & 0xffff0000U);
|
|
dbgprintf("mc fb loc is %08x\n", (unsigned int)info->mc_fb_location);
|
|
}
|
|
}
|
|
}
|
|
if (info->ChipFamily >= CHIP_FAMILY_R600) {
|
|
info->fbLocation = (info->mc_fb_location & 0xffff) << 24;
|
|
}
|
|
else {
|
|
info->fbLocation = (info->mc_fb_location & 0xffff) << 16;
|
|
}
|
|
/* Just disable the damn AGP apertures for now, it may be
|
|
* re-enabled later by the DRM
|
|
*/
|
|
|
|
if (IS_AVIVO_VARIANT) {
|
|
if (info->ChipFamily >= CHIP_FAMILY_R600) {
|
|
OUTREG(R600_HDP_NONSURFACE_BASE, (info->mc_fb_location << 16) & 0xff0000);
|
|
}
|
|
else {
|
|
OUTREG(AVIVO_HDP_FB_LOCATION, info->mc_fb_location);
|
|
}
|
|
info->mc_agp_location = 0x003f0000;
|
|
}
|
|
else
|
|
info->mc_agp_location = 0xffffffc0;
|
|
|
|
dbgprintf("RADEONInitMemoryMap() : \n");
|
|
dbgprintf(" mem_size : 0x%08x\n", (u32_t)mem_size);
|
|
dbgprintf(" MC_FB_LOCATION : 0x%08x\n", (unsigned)info->mc_fb_location);
|
|
dbgprintf(" MC_AGP_LOCATION : 0x%08x\n", (unsigned)info->mc_agp_location);
|
|
dbgprintf(" FB_LOCATION : 0x%08x\n", (unsigned)info->fbLocation);
|
|
|
|
|
|
RADEONUpdateMemMapRegisters(info);
|
|
|
|
|
|
}
|
|
|
|
static void RADEONGetVRamType(RHDPtr info)
|
|
{
|
|
u32_t tmp;
|
|
|
|
if (info->IsIGP || (info->ChipFamily >= CHIP_FAMILY_R300))
|
|
info->IsDDR = TRUE;
|
|
else if (INREG(RADEON_MEM_SDRAM_MODE_REG) & RADEON_MEM_CFG_TYPE_DDR)
|
|
info->IsDDR = TRUE;
|
|
else
|
|
info->IsDDR = FALSE;
|
|
|
|
if ( (info->ChipFamily >= CHIP_FAMILY_R600) &&
|
|
(info->ChipFamily <= CHIP_FAMILY_RV635))
|
|
{
|
|
int chansize;
|
|
/* r6xx */
|
|
tmp = INREG(R600_RAMCFG);
|
|
if (tmp & R600_CHANSIZE_OVERRIDE)
|
|
chansize = 16;
|
|
else if (tmp & R600_CHANSIZE)
|
|
chansize = 64;
|
|
else
|
|
chansize = 32;
|
|
if (info->ChipFamily == CHIP_FAMILY_R600)
|
|
info->RamWidth = 8 * chansize;
|
|
else if (info->ChipFamily == CHIP_FAMILY_RV670)
|
|
info->RamWidth = 4 * chansize;
|
|
else if ((info->ChipFamily == CHIP_FAMILY_RV610) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV620))
|
|
info->RamWidth = chansize;
|
|
else if ((info->ChipFamily == CHIP_FAMILY_RV630) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RV635))
|
|
info->RamWidth = 2 * chansize;
|
|
}
|
|
else if (info->ChipFamily == CHIP_FAMILY_RV515) {
|
|
/* rv515/rv550 */
|
|
tmp = INMC(info, RV515_MC_CNTL);
|
|
tmp &= RV515_MEM_NUM_CHANNELS_MASK;
|
|
switch (tmp) {
|
|
case 0: info->RamWidth = 64; break;
|
|
case 1: info->RamWidth = 128; break;
|
|
default: info->RamWidth = 128; break;
|
|
}
|
|
}
|
|
else if ((info->ChipFamily >= CHIP_FAMILY_R520) &&
|
|
(info->ChipFamily <= CHIP_FAMILY_RV570)){
|
|
/* r520/rv530/rv560/rv570/r580 */
|
|
tmp = INMC(info, R520_MC_CNTL0);
|
|
switch ((tmp & R520_MEM_NUM_CHANNELS_MASK) >> R520_MEM_NUM_CHANNELS_SHIFT) {
|
|
case 0: info->RamWidth = 32; break;
|
|
case 1: info->RamWidth = 64; break;
|
|
case 2: info->RamWidth = 128; break;
|
|
case 3: info->RamWidth = 256; break;
|
|
default: info->RamWidth = 64; break;
|
|
}
|
|
if (tmp & R520_MC_CHANNEL_SIZE) {
|
|
info->RamWidth *= 2;
|
|
}
|
|
}
|
|
else if ((info->ChipFamily >= CHIP_FAMILY_R300) &&
|
|
(info->ChipFamily <= CHIP_FAMILY_RV410)) {
|
|
/* r3xx, r4xx */
|
|
tmp = INREG(RADEON_MEM_CNTL);
|
|
tmp &= R300_MEM_NUM_CHANNELS_MASK;
|
|
switch (tmp) {
|
|
case 0: info->RamWidth = 64; break;
|
|
case 1: info->RamWidth = 128; break;
|
|
case 2: info->RamWidth = 256; break;
|
|
default: info->RamWidth = 128; break;
|
|
}
|
|
}
|
|
else if ((info->ChipFamily == CHIP_FAMILY_RV100) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS100) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS200)){
|
|
tmp = INREG(RADEON_MEM_CNTL);
|
|
if (tmp & RV100_HALF_MODE)
|
|
info->RamWidth = 32;
|
|
else
|
|
info->RamWidth = 64;
|
|
|
|
if (!info->HasCRTC2) {
|
|
info->RamWidth /= 4;
|
|
info->IsDDR = TRUE;
|
|
}
|
|
}
|
|
else if (info->ChipFamily <= CHIP_FAMILY_RV280) {
|
|
tmp = INREG(RADEON_MEM_CNTL);
|
|
if (tmp & RADEON_MEM_NUM_CHANNELS_MASK)
|
|
info->RamWidth = 128;
|
|
else
|
|
info->RamWidth = 64;
|
|
} else {
|
|
/* newer IGPs */
|
|
info->RamWidth = 128;
|
|
}
|
|
|
|
/* This may not be correct, as some cards can have half of channel disabled
|
|
* ToDo: identify these cases
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* Depending on card genertation, chipset bugs, etc... the amount of vram
|
|
* accessible to the CPU can vary. This function is our best shot at figuring
|
|
* it out. Returns a value in KB.
|
|
*/
|
|
static u32_t RADEONGetAccessibleVRAM(RHDPtr info)
|
|
{
|
|
u32_t aper_size;
|
|
unsigned char byte;
|
|
|
|
if (info->ChipFamily >= CHIP_FAMILY_R600)
|
|
aper_size = INREG(R600_CONFIG_APER_SIZE) / 1024;
|
|
else
|
|
aper_size = INREG(RADEON_CONFIG_APER_SIZE) / 1024;
|
|
|
|
|
|
/* Set HDP_APER_CNTL only on cards that are known not to be broken,
|
|
* that is has the 2nd generation multifunction PCI interface
|
|
*/
|
|
if (info->ChipFamily == CHIP_FAMILY_RV280 ||
|
|
info->ChipFamily == CHIP_FAMILY_RV350 ||
|
|
info->ChipFamily == CHIP_FAMILY_RV380 ||
|
|
info->ChipFamily == CHIP_FAMILY_R420 ||
|
|
info->ChipFamily == CHIP_FAMILY_RV410 ||
|
|
IS_AVIVO_VARIANT) {
|
|
MASKREG (RADEON_HOST_PATH_CNTL, RADEON_HDP_APER_CNTL,
|
|
~RADEON_HDP_APER_CNTL);
|
|
dbgprintf("Generation 2 PCI interface, using max accessible memory\n");
|
|
return aper_size * 2;
|
|
}
|
|
|
|
/* Older cards have all sorts of funny issues to deal with. First
|
|
* check if it's a multifunction card by reading the PCI config
|
|
* header type... Limit those to one aperture size
|
|
*/
|
|
byte = pciReadByte(info->PciTag, 0xe);
|
|
if (byte & 0x80) {
|
|
dbgprintf("Generation 1 PCI interface in multifunction mode, "
|
|
"accessible memory limited to one aperture\n");
|
|
return aper_size;
|
|
}
|
|
|
|
/* Single function older card. We read HDP_APER_CNTL to see how the BIOS
|
|
* have set it up. We don't write this as it's broken on some ASICs but
|
|
* we expect the BIOS to have done the right thing (might be too optimistic...)
|
|
*/
|
|
if (INREG(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL)
|
|
return aper_size * 2;
|
|
|
|
return aper_size;
|
|
}
|
|
|
|
int RADEONDRIGetPciAperTableSize(RHDPtr info)
|
|
{
|
|
int ret_size;
|
|
int num_pages;
|
|
|
|
num_pages = (info->pciAperSize * 1024 * 1024) / 4096;
|
|
|
|
ret_size = num_pages * sizeof(unsigned int);
|
|
|
|
return ret_size;
|
|
}
|
|
|
|
static Bool RADEONPreInitVRAM(RHDPtr info)
|
|
{
|
|
u32_t accessible, bar_size;
|
|
|
|
if ((!IS_AVIVO_VARIANT) && info->IsIGP)
|
|
{
|
|
u32_t tom = INREG(RADEON_NB_TOM);
|
|
|
|
info->videoRam = (((tom >> 16) -
|
|
(tom & 0xffff) + 1) << 6);
|
|
|
|
OUTREG(RADEON_CONFIG_MEMSIZE, info->videoRam * 1024);
|
|
}
|
|
else
|
|
{
|
|
if (info->ChipFamily >= CHIP_FAMILY_R600)
|
|
info->videoRam = INREG(R600_CONFIG_MEMSIZE) / 1024;
|
|
else
|
|
{
|
|
/* Read VRAM size from card */
|
|
info->videoRam = INREG(RADEON_CONFIG_MEMSIZE) / 1024;
|
|
|
|
/* Some production boards of m6 will return 0 if it's 8 MB */
|
|
if (info->videoRam == 0)
|
|
{
|
|
info->videoRam = 8192;
|
|
OUTREG(RADEON_CONFIG_MEMSIZE, 0x800000);
|
|
}
|
|
}
|
|
}
|
|
|
|
RADEONGetVRamType(info);
|
|
|
|
/* Get accessible memory */
|
|
accessible = RADEONGetAccessibleVRAM(info);
|
|
|
|
/* Crop it to the size of the PCI BAR */
|
|
// bar_size = PCI_REGION_SIZE(info->PciInfo, 0) / 1024;
|
|
|
|
bar_size = 1 << (info->memsize[RHD_FB_BAR] - 10);
|
|
|
|
if (bar_size == 0)
|
|
bar_size = 0x20000;
|
|
if (accessible > bar_size)
|
|
accessible = bar_size;
|
|
|
|
dbgprintf("Detected total video RAM=%dK width=%dbit,"
|
|
"accessible=%uK (PCI BAR=%uK)\n",
|
|
info->videoRam, info->RamWidth,
|
|
(unsigned)accessible, (unsigned)bar_size);
|
|
|
|
if (info->videoRam > accessible)
|
|
info->videoRam = accessible;
|
|
|
|
if (!IS_AVIVO_VARIANT)
|
|
info->MemCntl = INREG(RADEON_SDRAM_MODE_REG);
|
|
info->BusCntl = INREG(RADEON_BUS_CNTL);
|
|
|
|
info->videoRam &= ~1023;
|
|
info->FbMapSize = info->videoRam * 1024;
|
|
|
|
// info->gartSize = RADEON_DEFAULT_GART_SIZE;
|
|
info->ringSize = RADEON_DEFAULT_RING_SIZE;
|
|
info->bufSize = RADEON_DEFAULT_BUFFER_SIZE;
|
|
|
|
// info->gartTexSize = info->gartSize - (info->ringSize + info->bufSize);
|
|
|
|
info->pciAperSize = RADEON_DEFAULT_PCI_APER_SIZE;
|
|
info->CPusecTimeout = RADEON_DEFAULT_CP_TIMEOUT;
|
|
|
|
|
|
|
|
/* if the card is PCI Express reserve the last 32k for the gart table */
|
|
|
|
// if (info->cardType == CARD_PCIE )
|
|
// /* work out the size of pcie aperture */
|
|
// info->FbSecureSize = RADEONDRIGetPciAperTableSize(info);
|
|
// else
|
|
// info->FbSecureSize = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static Bool RADEONPreInitChipType(RHDPtr rhdPtr)
|
|
{
|
|
u32_t cmd_stat;
|
|
|
|
rhdPtr->ChipErrata = 0;
|
|
|
|
if ( (rhdPtr->ChipFamily == CHIP_FAMILY_R300) &&
|
|
((_RHDRegRead(rhdPtr,RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK)
|
|
== RADEON_CFG_ATI_REV_A11))
|
|
rhdPtr->ChipErrata |= CHIP_ERRATA_R300_CG;
|
|
|
|
if ( (rhdPtr->ChipFamily == CHIP_FAMILY_RV200) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS200) )
|
|
rhdPtr->ChipErrata |= CHIP_ERRATA_PLL_DUMMYREADS;
|
|
|
|
if ( (rhdPtr->ChipFamily == CHIP_FAMILY_RV100) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS100) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS200) )
|
|
rhdPtr->ChipErrata |= CHIP_ERRATA_PLL_DELAY;
|
|
|
|
rhdPtr->cardType = CARD_PCI;
|
|
|
|
|
|
cmd_stat = pciReadLong(rhdPtr->PciTag, PCI_CMD_STAT_REG);
|
|
|
|
if (cmd_stat & RADEON_CAP_LIST)
|
|
{
|
|
u32_t cap_ptr, cap_id;
|
|
|
|
cap_ptr = pciReadLong(rhdPtr->PciTag, RADEON_CAPABILITIES_PTR_PCI_CONFIG);
|
|
cap_ptr &= RADEON_CAP_PTR_MASK;
|
|
|
|
while(cap_ptr != RADEON_CAP_ID_NULL)
|
|
{
|
|
cap_id = pciReadLong(rhdPtr->PciTag, cap_ptr);
|
|
if ((cap_id & 0xff)== RADEON_CAP_ID_AGP) {
|
|
rhdPtr->cardType = CARD_AGP;
|
|
break;
|
|
}
|
|
if ((cap_id & 0xff)== RADEON_CAP_ID_EXP) {
|
|
rhdPtr->cardType = CARD_PCIE;
|
|
break;
|
|
}
|
|
cap_ptr = (cap_id >> 8) & RADEON_CAP_PTR_MASK;
|
|
}
|
|
}
|
|
|
|
dbgprintf("%s card detected\n",(rhdPtr->cardType==CARD_PCI) ? "PCI" :
|
|
(rhdPtr->cardType==CARD_PCIE) ? "PCIE" : "AGP");
|
|
|
|
/* treat PCIE IGP cards as PCI */
|
|
if (rhdPtr->cardType == CARD_PCIE && rhdPtr->IsIGP)
|
|
rhdPtr->cardType = CARD_PCI;
|
|
|
|
if ( (rhdPtr->ChipFamily == CHIP_FAMILY_RS100) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS200) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS300) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS400) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS480) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS600) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS690) ||
|
|
(rhdPtr->ChipFamily == CHIP_FAMILY_RS740))
|
|
rhdPtr->has_tcl = FALSE;
|
|
else {
|
|
rhdPtr->has_tcl = TRUE;
|
|
}
|
|
|
|
// rhdPtr->LinearAddr = rhdPtr->memBase[RHD_FB_BAR];
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#if 0
|
|
static Bool RADEONSetAgpMode(RADEONInfoPtr info, ScreenPtr pScreen)
|
|
{
|
|
unsigned char *RADEONMMIO = info->MMIO;
|
|
// unsigned long mode = drmAgpGetMode(info->dri->drmFD); /* Default mode */
|
|
// unsigned int vendor = drmAgpVendorId(info->dri->drmFD);
|
|
// unsigned int device = drmAgpDeviceId(info->dri->drmFD);
|
|
/* ignore agp 3.0 mode bit from the chip as it's buggy on some cards with
|
|
pcie-agp rialto bridge chip - use the one from bridge which must match */
|
|
uint32_t agp_status = (INREG(RADEON_AGP_STATUS) ); // & RADEON_AGP_MODE_MASK;
|
|
Bool is_v3 = (agp_status & RADEON_AGPv3_MODE);
|
|
unsigned int defaultMode;
|
|
|
|
if (is_v3) {
|
|
defaultMode = (agp_status & RADEON_AGPv3_8X_MODE) ? 8 : 4;
|
|
} else {
|
|
if (agp_status & RADEON_AGP_4X_MODE) defaultMode = 4;
|
|
else if (agp_status & RADEON_AGP_2X_MODE) defaultMode = 2;
|
|
else defaultMode = 1;
|
|
}
|
|
|
|
// agpMode = defaultMode;
|
|
|
|
dbgprintf(pScreen->myNum, from, "Using AGP %dx\n", dbgprintf);
|
|
|
|
mode &= ~RADEON_AGP_MODE_MASK;
|
|
if (is_v3) {
|
|
/* only set one mode bit for AGPv3 */
|
|
switch (defaultMode) {
|
|
case 8: mode |= RADEON_AGPv3_8X_MODE; break;
|
|
case 4: default: mode |= RADEON_AGPv3_4X_MODE;
|
|
}
|
|
/*TODO: need to take care of other bits valid for v3 mode
|
|
* currently these bits are not used in all tested cards.
|
|
*/
|
|
} else {
|
|
switch (defaultMode) {
|
|
case 4: mode |= RADEON_AGP_4X_MODE;
|
|
case 2: mode |= RADEON_AGP_2X_MODE;
|
|
case 1: default: mode |= RADEON_AGP_1X_MODE;
|
|
}
|
|
}
|
|
|
|
/* AGP Fast Writes.
|
|
* TODO: take into account that certain agp modes don't support fast
|
|
* writes at all */
|
|
mode &= ~RADEON_AGP_FW_MODE; /* Disable per default */
|
|
|
|
dbgprintf("AGP Mode 0x%08lx\n", mode);
|
|
|
|
if (drmAgpEnable(info->dri->drmFD, mode) < 0) {
|
|
xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n");
|
|
drmAgpRelease(info->dri->drmFD);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Workaround for some hardware bugs */
|
|
if (info->ChipFamily < CHIP_FAMILY_R200)
|
|
OUTREG(RADEON_AGP_CNTL, INREG(RADEON_AGP_CNTL) | 0x000e0000);
|
|
|
|
/* Modify the mode if the default mode
|
|
* is not appropriate for this
|
|
* particular combination of graphics
|
|
* card and AGP chipset.
|
|
*/
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
Bool RHDPreInit()
|
|
{
|
|
RHDPtr info;
|
|
|
|
/* We need access to IO space already */
|
|
if ( !rhdMapMMIO(&rhd) ) {
|
|
dbgprintf("Failed to map MMIO.\n");
|
|
return FALSE;
|
|
};
|
|
|
|
if( !RADEONPreInitChipType(&rhd))
|
|
return FALSE;
|
|
|
|
if (!RADEONPreInitVRAM(&rhd))
|
|
return FALSE;
|
|
|
|
RADEONInitMemoryMap(&rhd);
|
|
|
|
if (!rhd.videoRam)
|
|
{
|
|
dbgprintf("No Video RAM detected.\n");
|
|
goto error1;
|
|
}
|
|
dbgprintf("VideoRAM: %d kByte\n",rhd.videoRam);
|
|
|
|
/* setup the raster pipes */
|
|
init_pipes(&rhd);
|
|
|
|
init_gart(&rhd);
|
|
|
|
rhd.FbFreeSize = rhd.videoRam << 10;
|
|
|
|
rhd.FbFreeStart = 10*1024*1024;
|
|
rhd.FbFreeSize = rhd.FbMapSize - rhd.FbFreeStart - rhd.FbSecureSize;
|
|
|
|
rhdInitHeap(&rhd);
|
|
|
|
info = &rhd;
|
|
|
|
return TRUE;
|
|
|
|
error1:
|
|
|
|
return FALSE;
|
|
};
|
|
|
|
static void RADEONPllErrataAfterIndex()
|
|
{
|
|
if (!(rhd.ChipErrata & CHIP_ERRATA_PLL_DUMMYREADS))
|
|
return;
|
|
|
|
/* This workaround is necessary on rv200 and RS200 or PLL
|
|
* reads may return garbage (among others...)
|
|
*/
|
|
(void)INREG(RADEON_CLOCK_CNTL_DATA);
|
|
(void)INREG(RADEON_CRTC_GEN_CNTL);
|
|
}
|
|
|
|
|
|
static void RADEONPllErrataAfterData()
|
|
{
|
|
|
|
/* 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 (rhd.ChipFamily <= CHIP_FAMILY_RV380)
|
|
{
|
|
u32_t save, tmp;
|
|
|
|
save = INREG(RADEON_CLOCK_CNTL_INDEX);
|
|
tmp = save & ~(0x3f | RADEON_PLL_WR_EN);
|
|
OUTREG(RADEON_CLOCK_CNTL_INDEX, tmp);
|
|
tmp = INREG(RADEON_CLOCK_CNTL_DATA);
|
|
OUTREG(RADEON_CLOCK_CNTL_INDEX, save);
|
|
}
|
|
}
|
|
|
|
|
|
/* Read PLL register */
|
|
static u32_t RADEONINPLL(int addr)
|
|
{
|
|
u32_t data;
|
|
|
|
OUTREG8(RADEON_CLOCK_CNTL_INDEX, addr & 0x3f);
|
|
RADEONPllErrataAfterIndex();
|
|
data = INREG(RADEON_CLOCK_CNTL_DATA);
|
|
RADEONPllErrataAfterData();
|
|
|
|
return data;
|
|
};
|
|
|
|
/* Write PLL information */
|
|
static void RADEONOUTPLL(int addr, u32_t data)
|
|
{
|
|
OUTREG8(RADEON_CLOCK_CNTL_INDEX, (((addr) & 0x3f) |
|
|
RADEON_PLL_WR_EN));
|
|
RADEONPllErrataAfterIndex();
|
|
OUTREG(RADEON_CLOCK_CNTL_DATA, data);
|
|
RADEONPllErrataAfterData();
|
|
}
|
|
|
|
static void init_pipes(RHDPtr info)
|
|
{
|
|
u32_t gb_tile_config = 0;
|
|
|
|
if ( (info->ChipFamily == CHIP_FAMILY_RV410) ||
|
|
(info->ChipFamily == CHIP_FAMILY_R420) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS600) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS690) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS740) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS400) ||
|
|
(info->ChipFamily == CHIP_FAMILY_RS480) || IS_R500_3D)
|
|
{
|
|
u32_t gb_pipe_sel = INREG(R400_GB_PIPE_SELECT);
|
|
|
|
info->num_gb_pipes = ((gb_pipe_sel >> 12) & 0x3) + 1;
|
|
if (IS_R500_3D)
|
|
OUTPLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4));
|
|
}
|
|
else
|
|
{
|
|
if ((info->ChipFamily == CHIP_FAMILY_R300) ||
|
|
(info->ChipFamily == CHIP_FAMILY_R350))
|
|
{
|
|
/* R3xx chips */
|
|
info->num_gb_pipes = 2;
|
|
}
|
|
else {
|
|
/* RV3xx chips */
|
|
info->num_gb_pipes = 1;
|
|
}
|
|
}
|
|
|
|
if (IS_R300_3D || IS_R500_3D)
|
|
{
|
|
|
|
dbgprintf("num quad-pipes is %d\n", info->num_gb_pipes);
|
|
|
|
switch(info->num_gb_pipes) {
|
|
case 2: gb_tile_config |= R300_PIPE_COUNT_R300; break;
|
|
case 3: gb_tile_config |= R300_PIPE_COUNT_R420_3P; break;
|
|
case 4: gb_tile_config |= R300_PIPE_COUNT_R420; break;
|
|
default:
|
|
case 1: gb_tile_config |= R300_PIPE_COUNT_RV350; break;
|
|
}
|
|
|
|
OUTREG(R300_GB_TILE_CONFIG, gb_tile_config);
|
|
OUTREG(RADEON_WAIT_UNTIL, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN);
|
|
OUTREG(R300_DST_PIPE_CONFIG, INREG(R300_DST_PIPE_CONFIG) | R300_PIPE_AUTO_CONFIG);
|
|
OUTREG(R300_RB2D_DSTCACHE_MODE, (INREG(R300_RB2D_DSTCACHE_MODE) |
|
|
R300_DC_AUTOFLUSH_ENABLE |
|
|
R300_DC_DC_DISABLE_IGNORE_PE));
|
|
}
|
|
else
|
|
OUTREG(RADEON_RB3D_CNTL, 0);
|
|
};
|
|
|
|
#define RADEON_AIC_PT_BASE 0x01d8
|
|
#define RADEON_AIC_LO_ADDR 0x01dc
|
|
#define RADEON_AIC_HI_ADDR 0x01e0
|
|
#define RADEON_AIC_TLB_ADDR 0x01e4
|
|
#define RADEON_AIC_TLB_DATA 0x01e8
|
|
|
|
#define RADEON_PCIE_INDEX 0x0030
|
|
#define RADEON_PCIE_DATA 0x0034
|
|
#define RADEON_PCIE_TX_GART_CNTL 0x10
|
|
# define RADEON_PCIE_TX_GART_EN (1 << 0)
|
|
# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_PASS_THRU (0 << 1)
|
|
# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_CLAMP_LO (1 << 1)
|
|
# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD (3 << 1)
|
|
# define RADEON_PCIE_TX_GART_MODE_32_128_CACHE (0 << 3)
|
|
# define RADEON_PCIE_TX_GART_MODE_8_4_128_CACHE (1 << 3)
|
|
# define RADEON_PCIE_TX_GART_CHK_RW_VALID_EN (1 << 5)
|
|
# define RADEON_PCIE_TX_GART_INVALIDATE_TLB (1 << 8)
|
|
#define RADEON_PCIE_TX_DISCARD_RD_ADDR_LO 0x11
|
|
#define RADEON_PCIE_TX_DISCARD_RD_ADDR_HI 0x12
|
|
#define RADEON_PCIE_TX_GART_BASE 0x13
|
|
#define RADEON_PCIE_TX_GART_START_LO 0x14
|
|
#define RADEON_PCIE_TX_GART_START_HI 0x15
|
|
#define RADEON_PCIE_TX_GART_END_LO 0x16
|
|
#define RADEON_PCIE_TX_GART_END_HI 0x17
|
|
|
|
|
|
#define RADEON_WRITE8(offset, val) \
|
|
*(volatile u8_t*)((addr_t)rhd.MMIOBase + (offset)) = val
|
|
|
|
#define RADEON_WRITE_PCIE( addr, val ) \
|
|
do { \
|
|
RADEON_WRITE8( RADEON_PCIE_INDEX, \
|
|
((addr) & 0xff)); \
|
|
OUTREG( RADEON_PCIE_DATA, (val) ); \
|
|
} while (0)
|
|
|
|
static u32_t RADEON_READ_PCIE(int addr)
|
|
{
|
|
RADEON_WRITE8(RADEON_PCIE_INDEX, addr & 0xff);
|
|
return INREG(RADEON_PCIE_DATA);
|
|
}
|
|
|
|
static void radeon_set_pciegart(RHDPtr info, int on)
|
|
{
|
|
u32_t tmp = RADEON_READ_PCIE(RADEON_PCIE_TX_GART_CNTL);
|
|
if (on)
|
|
{
|
|
RADEON_WRITE_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO,
|
|
info->gart_vm_start);
|
|
RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_BASE,
|
|
info->gart_table_dma);
|
|
RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_START_LO,
|
|
info->gart_vm_start);
|
|
RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_END_LO,
|
|
info->gart_vm_start + info->gart_size - 1);
|
|
|
|
// radeon_write_agp_location(dev_priv, 0xffffffc0); /* ?? */
|
|
OUTREG(RADEON_AGP_COMMAND, 0); /* clear AGP_COMMAND */
|
|
|
|
RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
|
|
RADEON_PCIE_TX_GART_EN);
|
|
} else {
|
|
RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL,
|
|
tmp & ~RADEON_PCIE_TX_GART_EN);
|
|
}
|
|
}
|
|
|
|
|
|
static void radeon_set_pcigart(RHDPtr info, int on)
|
|
{
|
|
u32_t tmp;
|
|
|
|
tmp = INREG(RADEON_AIC_CNTL);
|
|
|
|
if( on )
|
|
{
|
|
OUTREG(RADEON_AIC_CNTL, tmp | RADEON_PCIGART_TRANSLATE_EN);
|
|
|
|
/* set PCI GART page-table base address
|
|
*/
|
|
OUTREG(RADEON_AIC_PT_BASE, info->gart_table_dma);
|
|
|
|
/* set address range for PCI address translate
|
|
*/
|
|
OUTREG(RADEON_AIC_LO_ADDR, info->gart_vm_start);
|
|
OUTREG(RADEON_AIC_HI_ADDR, info->gart_vm_start
|
|
+ info->gart_size - 1);
|
|
|
|
/* Turn off AGP aperture -- is this required for PCI GART?
|
|
*/
|
|
// radeon_write_agp_location(dev_priv, 0xffffffc0);
|
|
OUTREG(RADEON_AGP_COMMAND, 0); /* clear AGP_COMMAND */
|
|
}
|
|
else OUTREG(RADEON_AIC_CNTL, tmp & ~RADEON_PCIGART_TRANSLATE_EN);
|
|
|
|
}
|
|
|
|
|
|
void init_gart(RHDPtr info)
|
|
{
|
|
u32_t *pci_gart;
|
|
count_t pages;
|
|
|
|
info->gart_size = 16*1024*1024;
|
|
|
|
info->gart_vm_start = info->fbLocation + (info->videoRam << 10);
|
|
|
|
|
|
if( info->gart_type == RADEON_IS_PCIE)
|
|
info->gart_table_dma = info->gart_vm_start
|
|
- RADEON_PCIGART_TABLE_SIZE;
|
|
else
|
|
info->gart_table_dma = AllocPages(RADEON_PCIGART_TABLE_SIZE >> 12);
|
|
|
|
if ( ! info->gart_table_dma) {
|
|
dbgprintf("cannot allocate PCI GART page!\n");
|
|
return;
|
|
}
|
|
|
|
info->gart_table = (u32_t*)MapIoMem(info->gart_table_dma,
|
|
RADEON_PCIGART_TABLE_SIZE,
|
|
PG_SW | PG_NOCACHE);
|
|
|
|
if ( ! info->gart_table) {
|
|
dbgprintf("cannot map PCI GART page!\n");
|
|
return;
|
|
}
|
|
|
|
pci_gart = info->gart_table;
|
|
|
|
memset(pci_gart, 0, RADEON_PCIGART_TABLE_SIZE);
|
|
|
|
__asm__ __volatile(
|
|
"wbinvd"
|
|
:::"memory");
|
|
|
|
if( info->gart_type == RADEON_IS_PCIE)
|
|
radeon_set_pciegart(info, 1);
|
|
else
|
|
radeon_set_pcigart(info, 1);
|
|
|
|
dbgprintf("gart size 0x%x\n", info->gart_size);
|
|
dbgprintf("gart base 0x%x\n", info->gart_vm_start);
|
|
dbgprintf("gart table 0x%x\n", info->gart_table);
|
|
dbgprintf("gart table dma 0x%x\n", info->gart_table_dma);
|
|
|
|
}
|