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