Commit | Line | Data |
---|---|---|
a372acfa CL |
1 | /* |
2 | * This file contains the routines for initializing the MMU | |
3 | * on the 8xx series of chips. | |
4 | * -- christophe | |
5 | * | |
6 | * Derived from arch/powerpc/mm/40x_mmu.c: | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License | |
10 | * as published by the Free Software Foundation; either version | |
11 | * 2 of the License, or (at your option) any later version. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <linux/memblock.h> | |
16 | ||
17 | #include "mmu_decl.h" | |
18 | ||
19 | extern int __map_without_ltlbs; | |
20 | /* | |
21 | * MMU_init_hw does the chip-specific initialization of the MMU hardware. | |
22 | */ | |
23 | void __init MMU_init_hw(void) | |
24 | { | |
25 | /* Nothing to do for the time being but keep it similar to other PPC */ | |
26 | } | |
27 | ||
28 | #define LARGE_PAGE_SIZE_4M (1<<22) | |
29 | #define LARGE_PAGE_SIZE_8M (1<<23) | |
30 | #define LARGE_PAGE_SIZE_64M (1<<26) | |
31 | ||
32 | unsigned long __init mmu_mapin_ram(unsigned long top) | |
33 | { | |
34 | unsigned long v, s, mapped; | |
35 | phys_addr_t p; | |
36 | ||
37 | v = KERNELBASE; | |
38 | p = 0; | |
39 | s = top; | |
40 | ||
41 | if (__map_without_ltlbs) | |
42 | return 0; | |
43 | ||
44 | #ifdef CONFIG_PPC_4K_PAGES | |
45 | while (s >= LARGE_PAGE_SIZE_8M) { | |
46 | pmd_t *pmdp; | |
47 | unsigned long val = p | MD_PS8MEG; | |
48 | ||
49 | pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v); | |
50 | *pmdp++ = __pmd(val); | |
51 | *pmdp++ = __pmd(val + LARGE_PAGE_SIZE_4M); | |
52 | ||
53 | v += LARGE_PAGE_SIZE_8M; | |
54 | p += LARGE_PAGE_SIZE_8M; | |
55 | s -= LARGE_PAGE_SIZE_8M; | |
56 | } | |
57 | #else /* CONFIG_PPC_16K_PAGES */ | |
58 | while (s >= LARGE_PAGE_SIZE_64M) { | |
59 | pmd_t *pmdp; | |
60 | unsigned long val = p | MD_PS8MEG; | |
61 | ||
62 | pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v); | |
63 | *pmdp++ = __pmd(val); | |
64 | ||
65 | v += LARGE_PAGE_SIZE_64M; | |
66 | p += LARGE_PAGE_SIZE_64M; | |
67 | s -= LARGE_PAGE_SIZE_64M; | |
68 | } | |
69 | #endif | |
70 | ||
71 | mapped = top - s; | |
72 | ||
73 | /* If the size of RAM is not an exact power of two, we may not | |
74 | * have covered RAM in its entirety with 8 MiB | |
75 | * pages. Consequently, restrict the top end of RAM currently | |
76 | * allocable so that calls to the MEMBLOCK to allocate PTEs for "tail" | |
77 | * coverage with normal-sized pages (or other reasons) do not | |
78 | * attempt to allocate outside the allowed range. | |
79 | */ | |
80 | memblock_set_current_limit(mapped); | |
81 | ||
82 | return mapped; | |
83 | } | |
516d9189 CL |
84 | |
85 | void setup_initial_memory_limit(phys_addr_t first_memblock_base, | |
86 | phys_addr_t first_memblock_size) | |
87 | { | |
88 | /* We don't currently support the first MEMBLOCK not mapping 0 | |
89 | * physical on those processors | |
90 | */ | |
91 | BUG_ON(first_memblock_base != 0); | |
92 | ||
93 | #ifdef CONFIG_PIN_TLB | |
94 | /* 8xx can only access 24MB at the moment */ | |
95 | memblock_set_current_limit(min_t(u64, first_memblock_size, 0x01800000)); | |
96 | #else | |
97 | /* 8xx can only access 8MB at the moment */ | |
98 | memblock_set_current_limit(min_t(u64, first_memblock_size, 0x00800000)); | |
99 | #endif | |
100 | } | |
a7761fe4 CL |
101 | |
102 | /* | |
103 | * Set up to use a given MMU context. | |
104 | * id is context number, pgd is PGD pointer. | |
105 | * | |
106 | * We place the physical address of the new task page directory loaded | |
107 | * into the MMU base register, and set the ASID compare register with | |
108 | * the new "context." | |
109 | */ | |
110 | void set_context(unsigned long id, pgd_t *pgd) | |
111 | { | |
112 | s16 offset = (s16)(__pa(swapper_pg_dir)); | |
113 | ||
114 | #ifdef CONFIG_BDI_SWITCH | |
115 | pgd_t **ptr = *(pgd_t ***)(KERNELBASE + 0xf0); | |
116 | ||
117 | /* Context switch the PTE pointer for the Abatron BDI2000. | |
118 | * The PGDIR is passed as second argument. | |
119 | */ | |
120 | *(ptr + 1) = pgd; | |
121 | #endif | |
122 | ||
123 | /* Register M_TW will contain base address of level 1 table minus the | |
124 | * lower part of the kernel PGDIR base address, so that all accesses to | |
125 | * level 1 table are done relative to lower part of kernel PGDIR base | |
126 | * address. | |
127 | */ | |
128 | mtspr(SPRN_M_TW, __pa(pgd) - offset); | |
129 | ||
130 | /* Update context */ | |
131 | mtspr(SPRN_M_CASID, id); | |
132 | /* sync */ | |
133 | mb(); | |
134 | } | |
766d45cb CL |
135 | |
136 | void flush_instruction_cache(void) | |
137 | { | |
138 | isync(); | |
139 | mtspr(SPRN_IC_CST, IDC_INVALL); | |
140 | isync(); | |
141 | } |