[LinuxBIOS] CAR for Geode GX1 / GX2
Juergen Beisert
juergen127 at kreuzholzen.de
Mon May 7 17:15:05 CEST 2007
Hi Peter,
On Monday 07 May 2007 15:41, Peter Stuge wrote:
> On Mon, May 07, 2007 at 09:43:06AM +0200, Juergen Beisert wrote:
> > I could provide some code to map the Geode GX1 cache anywhere you
> > like. It simply uses the tr3, tr4 and tr5 registers to map each
> > cache line to a physical address. I'm currently using it to map the
> > scratch pad RAM to enable and use the video acceleration. Its
> > written in C, but its very easy to rewrite it in assembler.
> > Maybe it achieves LinuxBIOS's requirements, but I'm not sure.
>
> I would love to see the code.
>
> If we can keep it in C that's a lot better than rewriting it in
> assembly, too!
Hmmm, I think we must rewrite it in Assembler as I think it should
prepare some RAM to be used to setup the SDRAM in C. Or am I wrong?
Here is the code. Runs on my Geode GX1 based system to map a part of
the cache to a specific address. It maps always the set 0 of the cache
due to this part can be used as Scratch Pad RAM. But it should be not
a big problem to expand it, to map all sets of the cache (16 kiB in
this case).
/* ---------------------------------------------------------- */
static inline void write_tr3(u32 tr3)
{
asm volatile ("movl %0, %%tr3" : : "r" (tr3));
}
static inline void write_tr4(u32 tr4)
{
asm volatile ("movl %0, %%tr4" : : "r" (tr4));
}
static inline void write_tr5(u32 tr5)
{
asm volatile ("movl %0, %%tr5" : : "r" (tr5));
}
#define invalidate_cache() __asm__ __volatile__ ("invd": : :"memory")
/*
* Disable and write back the cache
*
* Call this function with interrupts disabled!
*/
static void disable_cache(void)
{
unsigned long cr0;
wbinvd();
cr0 = read_cr0();
cr0 |= 0x40000000;
write_cr0(cr0);
wbinvd();
}
/*
* Enable the cache
*
* Call this function with interrupts disabled!
*/
static void enable_cache(void)
{
unsigned long cr0;
cr0 = read_cr0();
cr0 &= 0x9fffffff;
write_cr0(cr0);
}
/*
* write 16 bytes into cache' fill buffer
*
* This data will be cacheline's content after mapping
*/
static void setup_fill_buffer(u32 value)
{
write_tr5(0x0);
write_tr3(value);
write_tr5(0x4);
write_tr3(value);
write_tr5(0x8);
write_tr3(value);
write_tr5(0xc);
write_tr3(value);
}
/*
* map_cache_line - map a cachline of set 0 to a specific address
* @mapping_address: physical address to map this line to
*
* Always set 0 will be mapped due to this set is used
* as a scratch pad ram only
*
* Note: Call this function only when cache is disabled
*/
static void map_cache_line(u32 mapping_address)
{
write_tr4((mapping_address & 0xFFFFF000) | 0x400);
write_tr5((mapping_address & 0xFF0) | 0x00 << 2 | 0x1);
}
/*
* init_scratch_pad_size
* @info hardware info
* @size: new size of the scratch pad ram
*
* Note: Called with size = 0 will disable the scratch pad ram.
*/
static int geode_gx1_init_scratch_pad_size(struct geode_gx1_info * info,u32 size)
{
int i;
u32 base;
unsigned long flags;
if (size > 4096)
return -1;
if ((size != 0) && (size < 2048))
return -1;
if (size < 3072)
size=2048;
else if (size < 4096)
size=3072;
/*
* The mapping uses always the base
* address of the internal chipset
* registers
*/
info->scratch_pad_phys = info->physical_base;
base = info->physical_base+(4096-size);
spin_lock_irqsave(&geode_gx1_memory_lock, flags);
/*
* first disable and invalidate the remaining cache
*/
disable_cache();
invalidate_cache();
/*
* now free the _whole_ RAM for cache and invalidate
* it again to unmap currently used scratch pad ram
*/
set_scratch_pad_size(info,0);
invalidate_cache();
/*
* remap the cache lines again
*/
for (i=0; i<size; i+=16,base+=16) {
setup_fill_buffer(0xdeadbeef);
map_cache_line(base);
}
/*
* freeze the mapped cache lines
*/
set_scratch_pad_size(info,size);
/*
* and again use the remaining
* cache lines as usual
*/
enable_cache();
spin_unlock_irqrestore(&geode_gx1_memory_lock, flags);
return 0;
}
/* ---------------------------------------------------------- */
setup_fill_buffer() and map_cache_line() are the most important functions
and map_cache_line() must be extended to also support the other three cache
sets -> ...| 0x00 << 2 |... stands for set 0, ...| 0x01 << 2 |... would be
set 1 and so on.
The functions above do their work in my LinuxBIOS based Geode GX1 system,
with a special Xorg driver and graphics acceleration.
Hope it helps,
Juergen
More information about the coreboot
mailing list