/*
	Copyright (c) 2002, Thomas Kurschel
	
 
	Part of Radeon kernel driver
		
	Memory controller setup.
	
	The memory controller of the Radeon provides a universal mapping
	from addresses generated by the different DMA units within the
	graphics chip to addresses in local/PCI/AGP memory. Here, we
	set this mapping up.
	
	Further we initialize some bus controller registers here (where bus
	means non-local memory interface).
*/
 
#include "radeon_driver.h"
#include "buscntrl_regs.h"
#include "config_regs.h"
#include "mmio.h"
#include "memcntrl_regs.h"
 
 
// get last RAM address + 1, i.e. first unused physical address
static uint32 getTopOfRam()
{
	system_info info;
 
	// there is no function to really get this info;
	// as a hack, we ask for number of physical RAM pages and hope
	// they are contigous, starting at address 0	
	get_system_info( &info );
	
	return info.max_pages * 4096;
}
 
// graphics card addresses correspond to physical CPU addresses as much as possible
static void Radeon_SetupMCAddresses_Direct( device_info *di )
{
	shared_info *si = di->si;
	uint32 aper0 = INREG( di->regs, RADEON_CONFIG_APER_0_BASE );
	
	// bug in asics mean memory must be aligned to memory size... 
	if ( IS_DI_R300_VARIANT || di->asic == rt_rv280 ) {
		aper0 &= ~( di->local_mem_size - 1 );
	}
	
	// set address range of video memory;
	// use the same addresses the CPU sees
	si->memory[mt_local].virtual_addr_start = aper0;
	si->memory[mt_local].virtual_size = di->local_mem_size;
 
	// PCI GART has no corresponding CPU address space, so we must find an unused
	// one; we assume that the addresses directly after physical RAM are
	// not in use as the BIOS should have allocated address for PCI devices
	// starting with highest address possible. 
	// no problem in terms of alignment: it must be a multiple 4K only
	si->memory[mt_PCI].virtual_addr_start = (getTopOfRam() + 4095) & ~4095;
	si->memory[mt_PCI].virtual_size = ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
 
	// similar problem with AGP: though there _is_ a corresponding CPU address space,
	// we don't know it (this would require finding the AGP bridge and
	// getting info from there, which would be a dangerous hack);
	// solution is to locate AGP aperture directly after PCI GART;
	// we define a 4 MB aperture to meet any possible alignment restrictions
	si->memory[mt_AGP].virtual_addr_start = 
		(si->memory[mt_PCI].virtual_addr_start + si->memory[mt_PCI].virtual_size
		+ 0x3fffff) & ~0x3fffff;
	si->memory[mt_AGP].virtual_size = 0x400000;
 
}
 
 
#if 0
// graphics card addresses are mapped in a way to restrict direct main memory access
static void Radeon_SetupMCAddresses_Safe( device_info *di )
{
	shared_info *si = di->si;
 
	// any address not covered by frame buffer, PCI GART or AGP aperture
	// leads to a direct memory access
	// -> this is dangerous, so we make sure entire address space is mapped
	
	// locate PCI GART at top of address space
	// warning about size: there are quite strong alignment restrictions,
	// so we better obey!
	si->memory[mt_PCI].virtual_size = ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
	si->memory[mt_PCI].virtual_addr_start = 0 - si->memory[mt_PCI].virtual_size;	
 
	// let AGP range overlap with frame buffer to hide it;
	// according to spec, frame buffer should win but we better
	// choose an unused-area to avoid trouble
	// (specs don't talk about overlapping area, let's hope
	// the memory controller won't choke if we ever access it)
	si->memory[mt_AGP].virtual_size = 0x400000;
	si->memory[mt_AGP].virtual_addr_start = 
		si->memory[mt_PCI].virtual_addr_start - 
		si->memory[mt_AGP].virtual_size;
 
	// set address range of video memory
	// let it cover all remaining addresses; 
	// addresses are wrapped 
	si->memory[mt_local].virtual_addr_start = 0;
	si->memory[mt_local].virtual_size = 
		si->memory[mt_AGP].virtual_addr_start -
		si->memory[mt_local].virtual_addr_start;
}
#endif
 
// graphics cards addresses are mapped IGP compliantly
static void Radeon_SetupMCAddresses_IGP( device_info *di )
{
	shared_info *si = di->si;
	uint32 tom;
	
	// the frame buffer memory address range is read from TOM register
	// it located at end of physical RAM (at least it seems so)
	tom = INREG( di->regs, RADEON_NB_TOM );
	si->memory[mt_local].virtual_addr_start = (tom & 0xffff) << 16;
	si->memory[mt_local].virtual_size =
		(((tom >> 16) + 1) << 16) -
		si->memory[mt_local].virtual_addr_start;
 
	// after the frame buffer, physical memory should end and unused
	// physical addresses start - good location to put the PCI GART to
	si->memory[mt_PCI].virtual_addr_start = ((((tom >> 16) + 1) << 16) + 4095) & ~4095;
	si->memory[mt_PCI].virtual_size = ATI_MAX_PCIGART_PAGES * ATI_PCIGART_PAGE_SIZE;
 
	// locate AGP aperture after PCI GART
	si->memory[mt_AGP].virtual_addr_start = 
		(si->memory[mt_PCI].virtual_addr_start + 
		si->memory[mt_PCI].virtual_size + 0x3fffff) & ~0x3fffff;
	si->memory[mt_AGP].virtual_size = 0x400000;
 
}
 
void Radeon_InitMemController( device_info *di )
{
	vuint8 *regs = di->regs;
	shared_info *si = di->si;
 
	if( di->is_igp )
		Radeon_SetupMCAddresses_IGP( di );
	else
		Radeon_SetupMCAddresses_Direct/*Radeon_SetupMCAddresses_Safe*/( di );
 
	SHOW_INFO0( 3, "Graphics card address mapping:" );
	SHOW_INFO( 3, " local memory 0x%lx@0x%lx", 
		si->memory[mt_local].virtual_size, si->memory[mt_local].virtual_addr_start );
	SHOW_INFO( 3, " PCI GART 0x%lx@0x%lx", 
		si->memory[mt_PCI].virtual_size, si->memory[mt_PCI].virtual_addr_start );
	SHOW_INFO( 3, " disabled AGP GART 0x%lx@0x%lx", 
		si->memory[mt_AGP].virtual_size, si->memory[mt_AGP].virtual_addr_start );
	
	//si->nonlocal_mem = di->DMABuffer.ptr;
	
	// Turn on PCI GART
	OUTREGP( regs, RADEON_AIC_CNTL, RADEON_PCIGART_TRANSLATE_EN, 
		~RADEON_PCIGART_TRANSLATE_EN );
		
	// set PCI GART page-table base address
	OUTREG( regs, RADEON_AIC_PT_BASE, di->pci_gart.GATT.phys );
 
	// set address range for PCI address translation
	// we must restrict range to the actually used GART size here!
	OUTREG( regs, RADEON_AIC_LO_ADDR, si->memory[mt_PCI].virtual_addr_start );
	OUTREG( regs, RADEON_AIC_HI_ADDR, si->memory[mt_PCI].virtual_addr_start + 
		si->memory[mt_PCI].virtual_size/*di->pci_gart.buffer.size*/ - 1 );
 
	// set AGP address range
	OUTREG( regs, RADEON_MC_AGP_LOCATION, 0xffffffc0 /* EK magic numbers from X.org
		(si->memory[mt_AGP].virtual_addr_start >> 16) |
		((si->memory[mt_AGP].virtual_addr_start + si->memory[mt_AGP].virtual_size - 1) & 0xffff0000 )*/);
 
	// disable AGP
	OUTREG( regs, RADEON_AGP_COMMAND, 0 );
	
	// set address range of video memory
	// (lower word = begin >> 16
	//  upper word = end >> 16)
	OUTREG( regs, RADEON_MC_FB_LOCATION,
		((si->memory[mt_local].virtual_addr_start + si->memory[mt_local].virtual_size - 1) & 0xffff0000) |
		 (si->memory[mt_local].virtual_addr_start >> 16) );
		 
	// base address of CRTC and others must be same as frame buffer address
	// (we could specify any address too, but local memory is of course first choice)
	OUTREG( regs, RADEON_DISPLAY_BASE_ADDRESS, si->memory[mt_local].virtual_addr_start );
	OUTREG( regs, RADEON_CRTC2_DISPLAY_BASE_ADDRESS, si->memory[mt_local].virtual_addr_start );
	OUTREG( regs, RADEON_OV0_BASE_ADDRESS, si->memory[mt_local].virtual_addr_start );
		 
	// fix some bus controller setting
	// I reckon this takes care of discarding data unnecessarily read 
	// during a burst; let's hope this will fix the nasty CP crashing problem
	// EK this seems unecessary. OUTREGP( regs, RADEON_BUS_CNTL, RADEON_BUS_RD_DISCARD_EN, ~RADEON_BUS_RD_DISCARD_EN );
	
//	SHOW_FLOW0( 3, "done" );
}
 

V576 Incorrect format. Consider checking the fifth actual argument of the 'dprintf' function. The memsize type argument is expected.

V576 Incorrect format. Consider checking the fourth actual argument of the 'dprintf' function. The memsize type argument is expected.

V576 Incorrect format. Consider checking the fifth actual argument of the 'dprintf' function. The memsize type argument is expected.

V576 Incorrect format. Consider checking the fourth actual argument of the 'dprintf' function. The memsize type argument is expected.

V576 Incorrect format. Consider checking the fourth actual argument of the 'dprintf' function. The memsize type argument is expected.

V576 Incorrect format. Consider checking the fifth actual argument of the 'dprintf' function. The memsize type argument is expected.