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

-- 
linuxbios mailing list
[email protected]
http://www.linuxbios.org/mailman/listinfo/linuxbios

Reply via email to