xref: /haiku/src/system/boot/platform/u-boot/arch/ppc/arch_mmu_amcc440.cpp (revision 81291304ada328790118123ac74fb3dee8ce11fa)
1 /*
2  * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
3  * Based on code written by Travis Geiselbrecht for NewOS.
4  *
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include "mmu.h"
10 
11 #include <boot/platform.h>
12 #include <boot/stdio.h>
13 #include <boot/kernel_args.h>
14 #include <boot/stage2.h>
15 #include <arch/cpu.h>
16 #include <arch/ppc/arch_mmu_amcc440.h>
17 #include <arch_kernel.h>
18 #include <platform/openfirmware/openfirmware.h>
19 #ifdef __ARM__
20 #include <arm_mmu.h>
21 #endif
22 #include <kernel.h>
23 
24 #include <board_config.h>
25 
26 #include <OS.h>
27 
28 #include <string.h>
29 
30 int32 of_address_cells(int package);
31 int32 of_size_cells(int package);
32 
33 #define TRACE_MMU
34 #ifdef TRACE_MMU
35 #	define TRACE(x) dprintf x
36 #else
37 #	define TRACE(x) ;
38 #endif
39 
40 
41 /*!	Computes the recommended minimal page table size as
42 	described in table 7-22 of the PowerPC "Programming
43 	Environment for 32-Bit Microprocessors".
44 	The page table size ranges from 64 kB (for 8 MB RAM)
45 	to 32 MB (for 4 GB RAM).
46 	FIXME: account for larger TLB descriptors for Book-E
47 */
48 static size_t
suggested_page_table_size(phys_addr_t total)49 suggested_page_table_size(phys_addr_t total)
50 {
51 	uint32 max = 23;
52 		// 2^23 == 8 MB
53 
54 	while (max < 32) {
55 		if (total <= (1UL << max))
56 			break;
57 
58 		max++;
59 	}
60 
61 	return 1UL << (max - 7);
62 		// 2^(23 - 7) == 64 kB
63 }
64 
65 
66 static void
read_TLB(int i,uint32 tlb[3],uint8 & pid)67 read_TLB(int i, uint32 tlb[3], uint8 &pid)
68 {
69 	//FIXME:read pid too
70 	asm volatile(
71 		"tlbre %0,%3,0\n"
72 		"\ttlbre %1,%3,1\n"
73 		"\ttlbre %2,%3,2"
74 		:   "=r"(tlb[0]),
75 			"=r"(tlb[1]),
76 			"=r"(tlb[2])
77 		:	"r"(i)
78 	);
79 }
80 
81 
82 static void
write_TLB(int i,uint32 tlb[3],uint8 pid)83 write_TLB(int i, uint32 tlb[3], uint8 pid)
84 {
85 	//FIXME:write pid too
86 	asm volatile(
87 		"tlbwe %0,%3,0\n"
88 		"\ttlbwe %1,%3,1\n"
89 		"\ttlbwe %2,%3,2"
90 		: : "r"(tlb[0]),
91 			"r"(tlb[1]),
92 			"r"(tlb[2]),
93 			"r"(i)
94 	);
95 }
96 
97 
98 static void
dump_TLBs(void)99 dump_TLBs(void)
100 {
101 	int i;
102 	for (i = 0; i < TLB_COUNT; i++) {
103 		uint32 tlb[3];// = { 0, 0, 0 };
104 		uint8 pid;
105 		read_TLB(i, tlb, pid);
106 		dprintf("TLB[%02d]: %08lx %08lx %08lx %02x\n",
107 			i, tlb[0], tlb[1], tlb[2], pid);
108 	}
109 }
110 
111 
112 status_t
arch_mmu_setup_pinned_tlb_amcc440(phys_addr_t totalRam,size_t & tableSize,size_t & tlbSize)113 arch_mmu_setup_pinned_tlb_amcc440(phys_addr_t totalRam, size_t &tableSize,
114 	size_t &tlbSize)
115 {
116 	dump_TLBs();
117 	tlb_length tlbLength = TLB_LENGTH_16MB;
118 //XXX:totalRam = 4LL*1024*1024*1024;
119 
120 	size_t suggestedTableSize = suggested_page_table_size(totalRam);
121 	dprintf("suggested page table size = %" B_PRIuSIZE "\n",
122 		suggestedTableSize);
123 
124 	tableSize = suggestedTableSize;
125 
126 	// add 4MB for kernel and some more for modules...
127 	tlbSize = tableSize + 8 * 1024 * 1024;
128 
129 	// round up to realistic TLB lengths, either 16MB or 256MB
130 	// the unused space will be filled with SLAB areas
131 	if (tlbSize < 16 * 1024 * 1024)
132 		tlbSize = 16 * 1024 * 1024;
133 	else {
134 		tlbSize = 256 * 1024 * 1024;
135 		tlbLength = TLB_LENGTH_256MB;
136 	}
137 
138 	uint32 tlb[3];
139 	uint8 pid;
140 	int i;
141 
142 	// Make sure the last TLB is free, else we are in trouble
143 	// XXX: allow using a different TLB entry?
144 	read_TLB(TLB_COUNT - 1, tlb, pid);
145 	if ((tlb[0] & TLB_V) != 0) {
146 		panic("Last TLB already in use. FIXME.");
147 		return B_ERROR;
148 	}
149 
150 	// TODO: remove existing mapping from U-Boot at KERNEL_BASE !!!
151 	// (on Sam460ex it's pci mem)
152 	// for now we just move it to AS1 which we don't use, until calling
153 	// the kernel.
154 	// we could probably swap it with our own KERNEL_BASE TLB to call U-Boot
155 	// if required, but it'd be quite ugly.
156 	for (i = 0; i < TLB_COUNT; i++) {
157 		read_TLB(i, tlb, pid);
158 		//dprintf("tlb[%d][0] = %08lx\n", i, tlb[0]);
159 		// TODO: make the test more complete and correct
160 		if ((tlb[0] & 0xfffffc00) == KERNEL_BASE) {
161 			tlb[0] |= 0x100; // AS1
162 			write_TLB(i, tlb, pid);
163 			dprintf("Moved existing translation in TLB[%d] to AS1\n", i);
164 		}
165 	}
166 
167 	// pin the last TLB
168 	//XXX:also maybe skip the FDT + initrd + loader ?
169 	phys_addr_t physBase = gKernelArgs.physical_memory_range[0].start;
170 	//TODO:make sure 1st range is large enough?
171 	i = TLB_COUNT - 1; // last one
172 	pid = 0; // the kernel's PID
173 	tlb[0] = (KERNEL_BASE | tlbLength << 4 | TLB_V);
174 	tlb[1] = ((physBase & 0xfffffc00) | (physBase >> 32));
175 	tlb[2] = (0x0000003f); // user:RWX kernel:RWX
176 	write_TLB(i, tlb, pid);
177 
178 	return B_OK;
179 }
180 
181