1 |
3 |
xianfeng |
/*
|
2 |
|
|
* Set up paging and the MMU.
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 2000-2003, Axis Communications AB.
|
5 |
|
|
*
|
6 |
|
|
* Authors: Bjorn Wesen <bjornw@axis.com>
|
7 |
|
|
* Tobias Anderberg <tobiasa@axis.com>, CRISv32 port.
|
8 |
|
|
*/
|
9 |
|
|
#include <linux/mmzone.h>
|
10 |
|
|
#include <linux/init.h>
|
11 |
|
|
#include <linux/bootmem.h>
|
12 |
|
|
#include <linux/mm.h>
|
13 |
|
|
#include <asm/pgtable.h>
|
14 |
|
|
#include <asm/page.h>
|
15 |
|
|
#include <asm/types.h>
|
16 |
|
|
#include <asm/mmu.h>
|
17 |
|
|
#include <asm/io.h>
|
18 |
|
|
#include <asm/mmu_context.h>
|
19 |
|
|
#include <asm/arch/hwregs/asm/mmu_defs_asm.h>
|
20 |
|
|
#include <asm/arch/hwregs/supp_reg.h>
|
21 |
|
|
|
22 |
|
|
extern void tlb_init(void);
|
23 |
|
|
|
24 |
|
|
/*
|
25 |
|
|
* The kernel is already mapped with linear mapping at kseg_c so there's no
|
26 |
|
|
* need to map it with a page table. However, head.S also temporarily mapped it
|
27 |
|
|
* at kseg_4 thus the ksegs are set up again. Also clear the TLB and do various
|
28 |
|
|
* other paging stuff.
|
29 |
|
|
*/
|
30 |
|
|
void __init
|
31 |
|
|
cris_mmu_init(void)
|
32 |
|
|
{
|
33 |
|
|
unsigned long mmu_config;
|
34 |
|
|
unsigned long mmu_kbase_hi;
|
35 |
|
|
unsigned long mmu_kbase_lo;
|
36 |
|
|
unsigned short mmu_page_id;
|
37 |
|
|
|
38 |
|
|
/*
|
39 |
|
|
* Make sure the current pgd table points to something sane, even if it
|
40 |
|
|
* is most probably not used until the next switch_mm.
|
41 |
|
|
*/
|
42 |
|
|
per_cpu(current_pgd, smp_processor_id()) = init_mm.pgd;
|
43 |
|
|
|
44 |
|
|
#ifdef CONFIG_SMP
|
45 |
|
|
{
|
46 |
|
|
pgd_t **pgd;
|
47 |
|
|
pgd = (pgd_t**)&per_cpu(current_pgd, smp_processor_id());
|
48 |
|
|
SUPP_BANK_SEL(1);
|
49 |
|
|
SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
|
50 |
|
|
SUPP_BANK_SEL(2);
|
51 |
|
|
SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
|
52 |
|
|
}
|
53 |
|
|
#endif
|
54 |
|
|
|
55 |
|
|
/* Initialise the TLB. Function found in tlb.c. */
|
56 |
|
|
tlb_init();
|
57 |
|
|
|
58 |
|
|
/* Enable exceptions and initialize the kernel segments. */
|
59 |
|
|
mmu_config = ( REG_STATE(mmu, rw_mm_cfg, we, on) |
|
60 |
|
|
REG_STATE(mmu, rw_mm_cfg, acc, on) |
|
61 |
|
|
REG_STATE(mmu, rw_mm_cfg, ex, on) |
|
62 |
|
|
REG_STATE(mmu, rw_mm_cfg, inv, on) |
|
63 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_f, linear) |
|
64 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_e, linear) |
|
65 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_d, page) |
|
66 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_c, linear) |
|
67 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_b, linear) |
|
68 |
|
|
#ifndef CONFIG_ETRAXFS_SIM
|
69 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_a, page) |
|
70 |
|
|
#else
|
71 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_a, linear) |
|
72 |
|
|
#endif
|
73 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_9, page) |
|
74 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_8, page) |
|
75 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_7, page) |
|
76 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_6, page) |
|
77 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_5, page) |
|
78 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_4, page) |
|
79 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_3, page) |
|
80 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_2, page) |
|
81 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_1, page) |
|
82 |
|
|
REG_STATE(mmu, rw_mm_cfg, seg_0, page));
|
83 |
|
|
|
84 |
|
|
mmu_kbase_hi = ( REG_FIELD(mmu, rw_mm_kbase_hi, base_f, 0x0) |
|
85 |
|
|
REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x8) |
|
86 |
|
|
REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x0) |
|
87 |
|
|
#ifndef CONFIG_ETRAXFS_SIM
|
88 |
|
|
REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) |
|
89 |
|
|
#else
|
90 |
|
|
REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x0) |
|
91 |
|
|
#endif
|
92 |
|
|
REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) |
|
93 |
|
|
#ifndef CONFIG_ETRAXFS_SIM
|
94 |
|
|
REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) |
|
95 |
|
|
#else
|
96 |
|
|
REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa) |
|
97 |
|
|
#endif
|
98 |
|
|
REG_FIELD(mmu, rw_mm_kbase_hi, base_9, 0x0) |
|
99 |
|
|
REG_FIELD(mmu, rw_mm_kbase_hi, base_8, 0x0));
|
100 |
|
|
|
101 |
|
|
mmu_kbase_lo = ( REG_FIELD(mmu, rw_mm_kbase_lo, base_7, 0x0) |
|
102 |
|
|
REG_FIELD(mmu, rw_mm_kbase_lo, base_6, 0x0) |
|
103 |
|
|
REG_FIELD(mmu, rw_mm_kbase_lo, base_5, 0x0) |
|
104 |
|
|
REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 0x0) |
|
105 |
|
|
REG_FIELD(mmu, rw_mm_kbase_lo, base_3, 0x0) |
|
106 |
|
|
REG_FIELD(mmu, rw_mm_kbase_lo, base_2, 0x0) |
|
107 |
|
|
REG_FIELD(mmu, rw_mm_kbase_lo, base_1, 0x0) |
|
108 |
|
|
REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0x0));
|
109 |
|
|
|
110 |
|
|
mmu_page_id = REG_FIELD(mmu, rw_mm_tlb_hi, pid, 0);
|
111 |
|
|
|
112 |
|
|
/* Update the instruction MMU. */
|
113 |
|
|
SUPP_BANK_SEL(BANK_IM);
|
114 |
|
|
SUPP_REG_WR(RW_MM_CFG, mmu_config);
|
115 |
|
|
SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi);
|
116 |
|
|
SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo);
|
117 |
|
|
SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id);
|
118 |
|
|
|
119 |
|
|
/* Update the data MMU. */
|
120 |
|
|
SUPP_BANK_SEL(BANK_DM);
|
121 |
|
|
SUPP_REG_WR(RW_MM_CFG, mmu_config);
|
122 |
|
|
SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi);
|
123 |
|
|
SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo);
|
124 |
|
|
SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id);
|
125 |
|
|
|
126 |
|
|
SPEC_REG_WR(SPEC_REG_PID, 0);
|
127 |
|
|
|
128 |
|
|
/*
|
129 |
|
|
* The MMU has been enabled ever since head.S but just to make it
|
130 |
|
|
* totally obvious enable it here as well.
|
131 |
|
|
*/
|
132 |
|
|
SUPP_BANK_SEL(BANK_GC);
|
133 |
|
|
SUPP_REG_WR(RW_GC_CFG, 0xf); /* IMMU, DMMU, ICache, DCache on */
|
134 |
|
|
}
|
135 |
|
|
|
136 |
|
|
void __init
|
137 |
|
|
paging_init(void)
|
138 |
|
|
{
|
139 |
|
|
int i;
|
140 |
|
|
unsigned long zones_size[MAX_NR_ZONES];
|
141 |
|
|
|
142 |
|
|
printk("Setting up paging and the MMU.\n");
|
143 |
|
|
|
144 |
|
|
/* Clear out the init_mm.pgd that will contain the kernel's mappings. */
|
145 |
|
|
for(i = 0; i < PTRS_PER_PGD; i++)
|
146 |
|
|
swapper_pg_dir[i] = __pgd(0);
|
147 |
|
|
|
148 |
|
|
cris_mmu_init();
|
149 |
|
|
|
150 |
|
|
/*
|
151 |
|
|
* Initialize the bad page table and bad page to point to a couple of
|
152 |
|
|
* allocated pages.
|
153 |
|
|
*/
|
154 |
|
|
empty_zero_page = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
|
155 |
|
|
memset((void *) empty_zero_page, 0, PAGE_SIZE);
|
156 |
|
|
|
157 |
|
|
/* All pages are DMA'able in Etrax, so put all in the DMA'able zone. */
|
158 |
|
|
zones_size[0] = ((unsigned long) high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
|
159 |
|
|
|
160 |
|
|
for (i = 1; i < MAX_NR_ZONES; i++)
|
161 |
|
|
zones_size[i] = 0;
|
162 |
|
|
|
163 |
|
|
/*
|
164 |
|
|
* Use free_area_init_node instead of free_area_init, because it is
|
165 |
|
|
* designed for systems where the DRAM starts at an address
|
166 |
|
|
* substantially higher than 0, like us (we start at PAGE_OFFSET). This
|
167 |
|
|
* saves space in the mem_map page array.
|
168 |
|
|
*/
|
169 |
|
|
free_area_init_node(0, &contig_page_data, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
|
170 |
|
|
|
171 |
|
|
mem_map = contig_page_data.node_mem_map;
|
172 |
|
|
}
|