www.pudn.com > mizi_vivi.rar > mmu.c


/*
 * Copyright (C) 2002 MIZI Reserach, Inc.
 *
 * Author: Janghoon Lyu 
 * Date  : $Date: 2002/08/29 03:04:55 $
 *
 * $Revision: 1.6 $
 *
 * We just set up a linear virtual -> physical mapping
 * After evacuating the vivi from Flash, we will use
 * the fourth to last 1MB of DRAM to hold a cache-enabled image 
 * of the first 1MB Flash
 *
 * Note:
 *   - mmu_init()¿¡¼­ putstr()°ú °°Àº Ãâ·Â¹®À» »ç¿ëÇÏÁö ¸¶¼¼¿ä.
 *
 * History
 *
 * 2002-06-19: Janghoon Lyu 
 *    - Based on linux/arch/arm/mm/proc-sa110.S
 *    - Based on bootldr/mmu_strongarm.c
 *
 * 2002-07-12: Janghoon Lyu 
 *    - cpu_sa1100_cache_clean_invalidate_all() »õ·Î ÀÛ¼º. ¸Â³ª ¸ð¸£°Ú³×¿ä.
 *
 */

#include "config.h"
#include "machine.h"
#include "mmu.h"
#include "vivi_string.h"

static unsigned long *mmu_tlb_base = (unsigned long *)MMU_TABLE_BASE;

#define DCACHELINESIZE		32
#define FLUSH_OFFSET		32768
#define FLUSH_BASE		0x08000000
#define FLUSH_BASE_MINICACHE	0x08800000

/*
 * cpu_sa110_cache_clean_invalidate_all (void)
 *
 * clean and invalidate all cache lines
 *
 * Note:
 *  1. we should preserve r0 at all times
 */
static inline void cpu_sa1100_cache_clean_invalidate_all(void)
{
	unsigned long a0 = FLUSH_BASE;
	unsigned long a1 = FLUSH_BASE_MINICACHE;

	__asm__(
		"mov	r0, %0\n"	/* load flush base address */
		"add	r1, r0, #8192\n"	/* only necessary for 8k */
	"1001:	 ldr	r2, [r0], #32\n"	/* Dcache line size = 32 bytes */
		"teq	r1, r0\n"
		"bne	1001b\n"
		"mov	r0, %1\n"	/* load mini cache flush base address */
		"add	r1, r0, #512\n"	/* only necessary for 512 bytes */
	"1002:	 ldr	r2, [r0], #32\n"	/* Dcache line size = 32 bytes */
		"teq	r1, r0\n"
		"bne	1002b\n"
		"mov	r0, #0\n"
		"mcr	p15, 0, r0, c7, c5, 0\n"	/* invalidate I cache  */
		"mcr	p15, 0, r1, c9, c0, 0\n"	/* invalidate RB */
		"mcr	p15, 0, r0, c7, c10, 4\n"	/* drain WB */
		: /* no outputs */
		: "r" (a0), "r" (a1) );
}

void cache_clean_invalidate(void)
{
	cpu_sa1100_cache_clean_invalidate_all();
}

/*
 * cpu_sa110_tlb_invalidate_all()
 *
 * Invalidate all TLB entries 
 */
static inline void cpu_sa1100_tlb_invalidate_all(void)
{
__asm__(
	"mov	r0, #0\n"
	"mcr	p15, 0, r0, c7, c10, 4\n"	/* drain WB */
	"mcr	p15, 0, r0, c8, c7, 0\n"	/* invalidate I & D TLBs */
	);
}

void tlb_invalidate(void)
{
	cpu_sa1100_tlb_invalidate_all();
}

static inline void sa1100_setup(void)
{
	unsigned long ttb = MMU_TABLE_BASE;
__asm__(
	/* Invalidate caches */
	"mov	r10, #0\n"
	"mcr	p15, 0, r10, c7, c7\n"		/* invalidate I,D caches on v4 */
	"mcr	p15, 0, r10, c7, c10, 4\n"	/* drain write buffer on v4 */
	"mcr	p15, 0, r10, c8, c7\n"		/* invalidate I,D TLBs on v4 */
	/* Load page table pointer */
	"mov	r4, %0\n"
	"mcr	p15, 0, r4, c2, c0\n"		/* load page table pointer */
	/* Write cp15_r3, domain id */
	"mvn	r10, #0\n"			/* Domains 0, 1 = client */
	"mcr	p15, 0, r10, c3, c0\n"		/* load domain access register */
	/* Set control register v4 */
	"mrc	p15, 0, r0, c1, c0\n"		/* get control register v4 */
	/* Clear out 'unwantd bits (then put them in if we need them) */
	"bic	r0, r0, #0x0e00\n"		/* ..VI --RS BLDP WCAM */
	"bic	r0, r0, #0x000f\n"		/* .... 000. .... 0000 */
	"bic	r0, r0, #0x3000\n"		/* ..00 000. .... 0000 */
	/* Turn on what we want */
	"orr	r0, r0, #0x0170\n"		/* .... ...1 .111 .... */
#ifdef CONFIG_CPU_D_CACHE_ON
	"orr	r0, r0, #0x000c\n"		/* .... .... .... 11.. */
#endif
#ifdef CONFIG_CPU_I_CACHE_ON
	"orr	r0, r0, #0x1000\n"		/* ...1 .... .... .... */
#endif	
	"orr	r0, r0, #0x0001\n"		/* .... .... .... ...1 */
	"mcr	p15, 0, r0, c1, c0, 0\n"	/* write ctrl register */
	: : "r" (ttb) );
}

void mmu_init(void)
{
	sa1100_setup();
}

static inline void mem_mapping_linear(void)
{
	unsigned long pageoffset, sectionNumber;

	putstr_hex("MMU table base address = 0x", (unsigned long)mmu_tlb_base);
	/* 4G ¿µ¿ªÀ» 1:1·Î ¸ÅÇÎ. not cacacheable, not bufferable */
	for (sectionNumber = 0; sectionNumber < 4096; sectionNumber++) {
		pageoffset = (sectionNumber << 20);
		*(mmu_tlb_base + (pageoffset >> 20)) = pageoffset | MMU_SECDESC;
	}

	/* make dram cacheable */
	for (pageoffset = DRAM_BASE; pageoffset < (DRAM_BASE+DRAM_SIZE); pageoffset += SZ_1M) {
		//DPRINTK(3, "Make DRAM section cacheable: 0x%08lx\n", pageoffset);
		*(mmu_tlb_base + (pageoffset >> 20)) = pageoffset | MMU_SECDESC | MMU_CACHEABLE; 
	}
}

static inline void nor_flash_mapping(void)
{
	unsigned long offset, cached_addr, uncached_addr;

	cached_addr = FLASH_BASE;
	uncached_addr = FLASH_UNCACHED_BASE;

	for (offset = 0; offset < FLASH_SIZE; offset += MMU_SECTION_SIZE) {
		cached_addr += offset;
		uncached_addr += offset;
		*(mmu_tlb_base + (cached_addr >> 20)) = \
					(cached_addr | MMU_SECDESC | MMU_CACHEABLE);
		*(mmu_tlb_base + (uncached_addr >> 20)) = \
					(cached_addr | MMU_SECDESC);
	}
}

static void nor_flash_remapping(void)
{
	putstr_hex("Map flash virtual section to DRAM at 0x", VIVI_RAM_BASE);
	/* point first 1MB of flash virtual addresses to its cacheable image in DRAM */
#if 0
	*(mmu_tlb_base + (FLASH_UNCACHED_BASE >> 20)) = \
				(VIVI_ROM_BASE | MMU_SECDESC);
#endif
	*(mmu_tlb_base + (VIVI_ROM_BASE >> 20)) = \
				(VIVI_RAM_BASE | MMU_SECDESC | MMU_CACHEABLE);
}

static void copy_vivi_to_ram(void)
{
	putstr_hex("Evacuating 1MB of flash to ram at 0x", VIVI_RAM_BASE);
	memcpy((void *)VIVI_RAM_BASE, (void *)VIVI_ROM_BASE, VIVI_RAM_SIZE);
}

void mem_map_init(void)
{
	copy_vivi_to_ram();
	mem_mapping_linear();
	nor_flash_mapping();
	nor_flash_remapping();
	cache_clean_invalidate();
	tlb_invalidate();
}