+
+ /*
+ * Block PTEs at this level are already covered by the parent page
+ * table, so we only need to count sub page tables.
+ */
+ if (pte_type == PTE_LEVEL) {
+ int sublevel = level + 1;
+ u64 sublevelsize = 1ULL << level2shift(sublevel);
+
+ /* Account for the new sub page table ... */
+ r = 1;
+
+ /* ... and for all child page tables that one might have */
+ for (i = 0; i < MAX_PTE_ENTRIES; i++) {
+ r += count_required_pts(addr, sublevel, maxaddr);
+ addr += sublevelsize;
+
+ if (addr >= maxaddr) {
+ /*
+ * We reached the end of address space, no need
+ * to look any further.
+ */
+ break;
+ }
+ }
+ }
+
+ return r;
+}
+
+/* Returns the estimated required size of all page tables */
+__weak u64 get_page_table_size(void)
+{
+ u64 one_pt = MAX_PTE_ENTRIES * sizeof(u64);
+ u64 size = 0;
+ u64 va_bits;
+ int start_level = 0;
+
+ get_tcr(0, NULL, &va_bits);
+ if (va_bits < 39)
+ start_level = 1;
+
+ /* Account for all page tables we would need to cover our memory map */
+ size = one_pt * count_required_pts(0, start_level - 1, 1ULL << va_bits);
+
+ /*
+ * We need to duplicate our page table once to have an emergency pt to
+ * resort to when splitting page tables later on
+ */
+ size *= 2;
+
+ /*
+ * We may need to split page tables later on if dcache settings change,
+ * so reserve up to 4 (random pick) page tables for that.
+ */
+ size += one_pt * 4;
+
+ return size;
+}
+
+void setup_pgtables(void)
+{
+ int i;
+
+ if (!gd->arch.tlb_fillptr || !gd->arch.tlb_addr)
+ panic("Page table pointer not setup.");
+
+ /*
+ * Allocate the first level we're on with invalidate entries.
+ * If the starting level is 0 (va_bits >= 39), then this is our
+ * Lv0 page table, otherwise it's the entry Lv1 page table.
+ */
+ create_table();
+
+ /* Now add all MMU table entries one after another to the table */
+ for (i = 0; mem_map[i].size || mem_map[i].attrs; i++)
+ add_map(&mem_map[i]);
+}
+
+static void setup_all_pgtables(void)
+{
+ u64 tlb_addr = gd->arch.tlb_addr;
+ u64 tlb_size = gd->arch.tlb_size;
+
+ /* Reset the fill ptr */
+ gd->arch.tlb_fillptr = tlb_addr;
+
+ /* Create normal system page tables */
+ setup_pgtables();
+
+ /* Create emergency page tables */
+ gd->arch.tlb_size -= (uintptr_t)gd->arch.tlb_fillptr -
+ (uintptr_t)gd->arch.tlb_addr;
+ gd->arch.tlb_addr = gd->arch.tlb_fillptr;
+ setup_pgtables();
+ gd->arch.tlb_emerg = gd->arch.tlb_addr;
+ gd->arch.tlb_addr = tlb_addr;
+ gd->arch.tlb_size = tlb_size;
+}
+
+/* to activate the MMU we need to set up virtual memory */
+__weak void mmu_setup(void)
+{
+ int el;
+
+ /* Set up page tables only once */
+ if (!gd->arch.tlb_fillptr)
+ setup_all_pgtables();
+
+ el = current_el();
+ set_ttbr_tcr_mair(el, gd->arch.tlb_addr, get_tcr(el, NULL, NULL),
+ MEMORY_ATTRIBUTES);
+