init.c 5.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Set up paging and the MMU.
 *
 * Copyright (C) 2000-2003, Axis Communications AB.
 *
 * Authors:   Bjorn Wesen <bjornw@axis.com>
 *            Tobias Anderberg <tobiasa@axis.com>, CRISv32 port.
 */
#include <linux/mmzone.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/mm.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/types.h>
#include <asm/mmu.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
19 20
#include <arch/hwregs/asm/mmu_defs_asm.h>
#include <arch/hwregs/supp_reg.h>
21 22 23 24 25 26 27 28 29

extern void tlb_init(void);

/*
 * The kernel is already mapped with linear mapping at kseg_c so there's no
 * need to map it with a page table. However, head.S also temporarily mapped it
 * at kseg_4 thus the ksegs are set up again. Also clear the TLB and do various
 * other paging stuff.
 */
J
Jesper Nilsson 已提交
30
void __init cris_mmu_init(void)
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
{
	unsigned long mmu_config;
	unsigned long mmu_kbase_hi;
	unsigned long mmu_kbase_lo;
	unsigned short mmu_page_id;

	/*
	 * Make sure the current pgd table points to something sane, even if it
	 * is most probably not used until the next switch_mm.
	 */
	per_cpu(current_pgd, smp_processor_id()) = init_mm.pgd;

	/* Initialise the TLB. Function found in tlb.c. */
	tlb_init();

J
Jesper Nilsson 已提交
46 47 48 49
	/*
	 * Enable exceptions and initialize the kernel segments.
	 * See head.S for differences between ARTPEC-3 and ETRAX FS.
	 */
50 51 52 53
	mmu_config = ( REG_STATE(mmu, rw_mm_cfg, we, on)        |
		       REG_STATE(mmu, rw_mm_cfg, acc, on)       |
		       REG_STATE(mmu, rw_mm_cfg, ex, on)        |
		       REG_STATE(mmu, rw_mm_cfg, inv, on)       |
J
Jesper Nilsson 已提交
54 55 56 57 58
#ifdef CONFIG_CRIS_MACH_ARTPEC3
		       REG_STATE(mmu, rw_mm_cfg, seg_f, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_e, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_d, linear) |
#else
59 60 61
		       REG_STATE(mmu, rw_mm_cfg, seg_f, linear) |
		       REG_STATE(mmu, rw_mm_cfg, seg_e, linear) |
		       REG_STATE(mmu, rw_mm_cfg, seg_d, page)   |
J
Jesper Nilsson 已提交
62
#endif
63 64 65 66 67 68 69 70 71 72 73 74 75 76
		       REG_STATE(mmu, rw_mm_cfg, seg_c, linear) |
		       REG_STATE(mmu, rw_mm_cfg, seg_b, linear) |
                       REG_STATE(mmu, rw_mm_cfg, seg_a, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_9, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_8, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_7, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_6, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_5, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_4, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_3, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_2, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_1, page)   |
		       REG_STATE(mmu, rw_mm_cfg, seg_0, page));

J
Jesper Nilsson 已提交
77
	/* See head.S for differences between ARTPEC-3 and ETRAX FS. */
78
	mmu_kbase_hi = ( REG_FIELD(mmu, rw_mm_kbase_hi, base_f, 0x0) |
J
Jesper Nilsson 已提交
79 80 81 82
#ifdef CONFIG_CRIS_MACH_ARTPEC3
			 REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x5) |
#else
83 84
			 REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x8) |
			 REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x0) |
J
Jesper Nilsson 已提交
85
#endif
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
                         REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) |
			 REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) |
			 REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_hi, base_9, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_hi, base_8, 0x0));

	mmu_kbase_lo = ( REG_FIELD(mmu, rw_mm_kbase_lo, base_7, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_lo, base_6, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_lo, base_5, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_lo, base_3, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_lo, base_2, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_lo, base_1, 0x0) |
			 REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0x0));

	mmu_page_id = REG_FIELD(mmu, rw_mm_tlb_hi, pid, 0);

	/* Update the instruction MMU. */
	SUPP_BANK_SEL(BANK_IM);
	SUPP_REG_WR(RW_MM_CFG, mmu_config);
	SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi);
	SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo);
	SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id);

	/* Update the data MMU. */
	SUPP_BANK_SEL(BANK_DM);
	SUPP_REG_WR(RW_MM_CFG, mmu_config);
	SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi);
	SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo);
	SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id);

	SPEC_REG_WR(SPEC_REG_PID, 0);

	/*
	 * The MMU has been enabled ever since head.S but just to make it
	 * totally obvious enable it here as well.
	 */
	SUPP_BANK_SEL(BANK_GC);
	SUPP_REG_WR(RW_GC_CFG, 0xf); /* IMMU, DMMU, ICache, DCache on */
}

J
Jesper Nilsson 已提交
127
void __init paging_init(void)
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
{
	int i;
	unsigned long zones_size[MAX_NR_ZONES];

	printk("Setting up paging and the MMU.\n");

	/* Clear out the init_mm.pgd that will contain the kernel's mappings. */
	for(i = 0; i < PTRS_PER_PGD; i++)
		swapper_pg_dir[i] = __pgd(0);

	cris_mmu_init();

	/*
	 * Initialize the bad page table and bad page to point to a couple of
	 * allocated pages.
	 */
	empty_zero_page = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
	memset((void *) empty_zero_page, 0, PAGE_SIZE);

	/* All pages are DMA'able in Etrax, so put all in the DMA'able zone. */
	zones_size[0] = ((unsigned long) high_memory - PAGE_OFFSET) >> PAGE_SHIFT;

	for (i = 1; i < MAX_NR_ZONES; i++)
		zones_size[i] = 0;

	/*
	 * Use free_area_init_node instead of free_area_init, because it is
	 * designed for systems where the DRAM starts at an address
	 * substantially higher than 0, like us (we start at PAGE_OFFSET). This
	 * saves space in the mem_map page array.
	 */
159
	free_area_init_node(0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
160 161 162

	mem_map = contig_page_data.node_mem_map;
}