1/* 2 * Modifications by Matt Porter (mporter@mvista.com) to support 3 * PPC44x Book E processors. 4 * 5 * This file contains the routines for initializing the MMU 6 * on the 4xx series of chips. 7 * -- paulus 8 * 9 * Derived from arch/ppc/mm/init.c: 10 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 11 * 12 * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) 13 * and Cort Dougan (PReP) (cort@cs.nmt.edu) 14 * Copyright (C) 1996 Paul Mackerras 15 * 16 * Derived from "arch/i386/mm/init.c" 17 * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 18 * 19 * This program is free software; you can redistribute it and/or 20 * modify it under the terms of the GNU General Public License 21 * as published by the Free Software Foundation; either version 22 * 2 of the License, or (at your option) any later version. 23 * 24 */ 25 26#include <linux/init.h> 27#include <asm/mmu.h> 28#include <asm/system.h> 29#include <asm/page.h> 30#include <asm/cacheflush.h> 31 32#include "mmu_decl.h" 33 34/* Used by the 44x TLB replacement exception handler. 35 * Just needed it declared someplace. 36 */ 37unsigned int tlb_44x_index; /* = 0 */ 38unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS; 39int icache_44x_need_flush; 40 41unsigned long tlb_47x_boltmap[1024/8]; 42 43static void __cpuinit ppc44x_update_tlb_hwater(void) 44{ 45 extern unsigned int tlb_44x_patch_hwater_D[]; 46 extern unsigned int tlb_44x_patch_hwater_I[]; 47 48 /* The TLB miss handlers hard codes the watermark in a cmpli 49 * instruction to improve performances rather than loading it 50 * from the global variable. Thus, we patch the instructions 51 * in the 2 TLB miss handlers when updating the value 52 */ 53 tlb_44x_patch_hwater_D[0] = (tlb_44x_patch_hwater_D[0] & 0xffff0000) | 54 tlb_44x_hwater; 55 flush_icache_range((unsigned long)&tlb_44x_patch_hwater_D[0], 56 (unsigned long)&tlb_44x_patch_hwater_D[1]); 57 tlb_44x_patch_hwater_I[0] = (tlb_44x_patch_hwater_I[0] & 0xffff0000) | 58 tlb_44x_hwater; 59 flush_icache_range((unsigned long)&tlb_44x_patch_hwater_I[0], 60 (unsigned long)&tlb_44x_patch_hwater_I[1]); 61} 62 63/* 64 * "Pins" a 256MB TLB entry in AS0 for kernel lowmem for 44x type MMU 65 */ 66static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys) 67{ 68 unsigned int entry = tlb_44x_hwater--; 69 70 ppc44x_update_tlb_hwater(); 71 72 mtspr(SPRN_MMUCR, 0); 73 74 __asm__ __volatile__( 75 "tlbwe %2,%3,%4\n" 76 "tlbwe %1,%3,%5\n" 77 "tlbwe %0,%3,%6\n" 78 : 79#ifdef CONFIG_PPC47x 80 : "r" (PPC47x_TLB2_S_RWX), 81#else 82 : "r" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G), 83#endif 84 "r" (phys), 85 "r" (virt | PPC44x_TLB_VALID | PPC44x_TLB_256M), 86 "r" (entry), 87 "i" (PPC44x_TLB_PAGEID), 88 "i" (PPC44x_TLB_XLAT), 89 "i" (PPC44x_TLB_ATTRIB)); 90} 91 92static int __init ppc47x_find_free_bolted(void) 93{ 94 unsigned int mmube0 = mfspr(SPRN_MMUBE0); 95 unsigned int mmube1 = mfspr(SPRN_MMUBE1); 96 97 if (!(mmube0 & MMUBE0_VBE0)) 98 return 0; 99 if (!(mmube0 & MMUBE0_VBE1)) 100 return 1; 101 if (!(mmube0 & MMUBE0_VBE2)) 102 return 2; 103 if (!(mmube1 & MMUBE1_VBE3)) 104 return 3; 105 if (!(mmube1 & MMUBE1_VBE4)) 106 return 4; 107 if (!(mmube1 & MMUBE1_VBE5)) 108 return 5; 109 return -1; 110} 111 112static void __init ppc47x_update_boltmap(void) 113{ 114 unsigned int mmube0 = mfspr(SPRN_MMUBE0); 115 unsigned int mmube1 = mfspr(SPRN_MMUBE1); 116 117 if (mmube0 & MMUBE0_VBE0) 118 __set_bit((mmube0 >> MMUBE0_IBE0_SHIFT) & 0xff, 119 tlb_47x_boltmap); 120 if (mmube0 & MMUBE0_VBE1) 121 __set_bit((mmube0 >> MMUBE0_IBE1_SHIFT) & 0xff, 122 tlb_47x_boltmap); 123 if (mmube0 & MMUBE0_VBE2) 124 __set_bit((mmube0 >> MMUBE0_IBE2_SHIFT) & 0xff, 125 tlb_47x_boltmap); 126 if (mmube1 & MMUBE1_VBE3) 127 __set_bit((mmube1 >> MMUBE1_IBE3_SHIFT) & 0xff, 128 tlb_47x_boltmap); 129 if (mmube1 & MMUBE1_VBE4) 130 __set_bit((mmube1 >> MMUBE1_IBE4_SHIFT) & 0xff, 131 tlb_47x_boltmap); 132 if (mmube1 & MMUBE1_VBE5) 133 __set_bit((mmube1 >> MMUBE1_IBE5_SHIFT) & 0xff, 134 tlb_47x_boltmap); 135} 136 137/* 138 * "Pins" a 256MB TLB entry in AS0 for kernel lowmem for 47x type MMU 139 */ 140static void __cpuinit ppc47x_pin_tlb(unsigned int virt, unsigned int phys) 141{ 142 unsigned int rA; 143 int bolted; 144 145 /* Base rA is HW way select, way 0, bolted bit set */ 146 rA = 0x88000000; 147 148 /* Look for a bolted entry slot */ 149 bolted = ppc47x_find_free_bolted(); 150 BUG_ON(bolted < 0); 151 152 /* Insert bolted slot number */ 153 rA |= bolted << 24; 154 155 pr_debug("256M TLB entry for 0x%08x->0x%08x in bolt slot %d\n", 156 virt, phys, bolted); 157 158 mtspr(SPRN_MMUCR, 0); 159 160 __asm__ __volatile__( 161 "tlbwe %2,%3,0\n" 162 "tlbwe %1,%3,1\n" 163 "tlbwe %0,%3,2\n" 164 : 165 : "r" (PPC47x_TLB2_SW | PPC47x_TLB2_SR | 166 PPC47x_TLB2_SX 167#ifdef CONFIG_SMP 168 | PPC47x_TLB2_M 169#endif 170 ), 171 "r" (phys), 172 "r" (virt | PPC47x_TLB0_VALID | PPC47x_TLB0_256M), 173 "r" (rA)); 174} 175 176void __init MMU_init_hw(void) 177{ 178 /* This is not useful on 47x but won't hurt either */ 179 ppc44x_update_tlb_hwater(); 180 181 flush_instruction_cache(); 182} 183 184unsigned long __init mmu_mapin_ram(unsigned long top) 185{ 186 unsigned long addr; 187 188 /* Pin in enough TLBs to cover any lowmem not covered by the 189 * initial 256M mapping established in head_44x.S */ 190 for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr; 191 addr += PPC_PIN_SIZE) { 192 if (mmu_has_feature(MMU_FTR_TYPE_47x)) 193 ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); 194 else 195 ppc44x_pin_tlb(addr + PAGE_OFFSET, addr); 196 } 197 if (mmu_has_feature(MMU_FTR_TYPE_47x)) { 198 ppc47x_update_boltmap(); 199 200#ifdef DEBUG 201 { 202 int i; 203 204 printk(KERN_DEBUG "bolted entries: "); 205 for (i = 0; i < 255; i++) { 206 if (test_bit(i, tlb_47x_boltmap)) 207 printk("%d ", i); 208 } 209 printk("\n"); 210 } 211#endif /* DEBUG */ 212 } 213 return total_lowmem; 214} 215 216#ifdef CONFIG_SMP 217void __cpuinit mmu_init_secondary(int cpu) 218{ 219 unsigned long addr; 220 221 /* Pin in enough TLBs to cover any lowmem not covered by the 222 * initial 256M mapping established in head_44x.S 223 * 224 * WARNING: This is called with only the first 256M of the 225 * linear mapping in the TLB and we can't take faults yet 226 * so beware of what this code uses. It runs off a temporary 227 * stack. current (r2) isn't initialized, smp_processor_id() 228 * will not work, current thread info isn't accessible, ... 229 */ 230 for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr; 231 addr += PPC_PIN_SIZE) { 232 if (mmu_has_feature(MMU_FTR_TYPE_47x)) 233 ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); 234 else 235 ppc44x_pin_tlb(addr + PAGE_OFFSET, addr); 236 } 237} 238#endif /* CONFIG_SMP */ 239