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); }