[LinuxBIOS] CAR for Geode GX1 / GX2
Marc Jones
marc.jones at amd.com
Mon May 7 21:37:56 CEST 2007
Juergen Beisert wrote:
> 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
>
This looks like a good example of scratchpad setup. The only part I
thought missing is the size setting of the GCR register.
(from the GX1 databook)
Bit Name Description
Index B8h GCR Register (R/W) Default Value = 00h
7:4 RSVD Reserved: Set to 0.
3:2 SP Scratchpad Size: Specifies the size of the scratchpad cache.
00 = 0 KB; Graphics instruction disabled (see Section 5.1.5 "Display
Driver Instructions" on page 97).
01 = 2 KB
10 = 3 KB
11 = 4 KB
1:0 GX GX1 Base Address: Specifies the physical address for the base
(GX_BASE) of the scratchpad RAM, the
graphics memory (frame buffer, compression buffer, etc.) and the other
memory mapped registers.
00 = Scratchpad RAM, Graphics Subsystem, and memory-mapped configuration
registers are disabled.
01 = Scratchpad RAM and control registers start at GX_BASE = 40000000h.
10 = Scratchpad RAM and control registers start at GX_BASE = 80000000h.
11 = Scratchpad RAM and control registers start at GX_BASE = C0000000h.
(intel asm)
GXM_GCR EQU 0B8h
SCRATCHPAD_SIZE EQU 0Ch ; GCR[3:2]
mov al, GXM_GCR ; Set ScratchPad size
out 22h, al
in al, 23h
or al, SCRATCHPAD_SIZE
out 23h, al
Marc
--
Marc Jones
Senior Software Engineer
(970) 226-9684 Office
mailto:Marc.Jones at amd.com
http://www.amd.com/embeddedprocessors
More information about the coreboot
mailing list