Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / cris / arch-v32 / mm / init.c
diff --git a/kernel/arch/cris/arch-v32/mm/init.c b/kernel/arch/cris/arch-v32/mm/init.c
new file mode 100644 (file)
index 0000000..f5438ca
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Set up paging and the MMU.
+ *
+ * Copyright (C) 2000-2003, Axis Communications AB.
+ *
+ * Authors:   Bjorn Wesen <bjornw@axis.com>
+ *            Tobias Anderberg <tobiasa@axis.com>, CRISv32 port.
+ */
+#include <linux/mmzone.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/types.h>
+#include <asm/mmu.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <arch/hwregs/asm/mmu_defs_asm.h>
+#include <arch/hwregs/supp_reg.h>
+
+extern void tlb_init(void);
+
+/*
+ * The kernel is already mapped with linear mapping at kseg_c so there's no
+ * need to map it with a page table. However, head.S also temporarily mapped it
+ * at kseg_4 thus the ksegs are set up again. Also clear the TLB and do various
+ * other paging stuff.
+ */
+void __init cris_mmu_init(void)
+{
+       unsigned long mmu_config;
+       unsigned long mmu_kbase_hi;
+       unsigned long mmu_kbase_lo;
+       unsigned short mmu_page_id;
+
+       /*
+        * Make sure the current pgd table points to something sane, even if it
+        * is most probably not used until the next switch_mm.
+        */
+       per_cpu(current_pgd, smp_processor_id()) = init_mm.pgd;
+
+       /* Initialise the TLB. Function found in tlb.c. */
+       tlb_init();
+
+       /*
+        * Enable exceptions and initialize the kernel segments.
+        * See head.S for differences between ARTPEC-3 and ETRAX FS.
+        */
+       mmu_config = ( REG_STATE(mmu, rw_mm_cfg, we, on)        |
+                      REG_STATE(mmu, rw_mm_cfg, acc, on)       |
+                      REG_STATE(mmu, rw_mm_cfg, ex, on)        |
+                      REG_STATE(mmu, rw_mm_cfg, inv, on)       |
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
+                      REG_STATE(mmu, rw_mm_cfg, seg_f, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_e, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_d, linear) |
+#else
+                      REG_STATE(mmu, rw_mm_cfg, seg_f, linear) |
+                      REG_STATE(mmu, rw_mm_cfg, seg_e, linear) |
+                      REG_STATE(mmu, rw_mm_cfg, seg_d, page)   |
+#endif
+                      REG_STATE(mmu, rw_mm_cfg, seg_c, linear) |
+                      REG_STATE(mmu, rw_mm_cfg, seg_b, linear) |
+                       REG_STATE(mmu, rw_mm_cfg, seg_a, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_9, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_8, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_7, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_6, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_5, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_4, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_3, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_2, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_1, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_0, page));
+
+       /* See head.S for differences between ARTPEC-3 and ETRAX FS. */
+       mmu_kbase_hi = ( REG_FIELD(mmu, rw_mm_kbase_hi, base_f, 0x0) |
+#ifdef CONFIG_CRIS_MACH_ARTPEC3
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x5) |
+#else
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x8) |
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x0) |
+#endif
+                         REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) |
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) |
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_9, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_8, 0x0));
+
+       mmu_kbase_lo = ( REG_FIELD(mmu, rw_mm_kbase_lo, base_7, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_6, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_5, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_3, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_2, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_1, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0x0));
+
+       mmu_page_id = REG_FIELD(mmu, rw_mm_tlb_hi, pid, 0);
+
+       /* Update the instruction MMU. */
+       SUPP_BANK_SEL(BANK_IM);
+       SUPP_REG_WR(RW_MM_CFG, mmu_config);
+       SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi);
+       SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo);
+       SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id);
+
+       /* Update the data MMU. */
+       SUPP_BANK_SEL(BANK_DM);
+       SUPP_REG_WR(RW_MM_CFG, mmu_config);
+       SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi);
+       SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo);
+       SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id);
+
+       SPEC_REG_WR(SPEC_REG_PID, 0);
+
+       /*
+        * The MMU has been enabled ever since head.S but just to make it
+        * totally obvious enable it here as well.
+        */
+       SUPP_BANK_SEL(BANK_GC);
+       SUPP_REG_WR(RW_GC_CFG, 0xf); /* IMMU, DMMU, ICache, DCache on */
+}
+
+void __init paging_init(void)
+{
+       int i;
+       unsigned long zones_size[MAX_NR_ZONES];
+
+       printk("Setting up paging and the MMU.\n");
+
+       /* Clear out the init_mm.pgd that will contain the kernel's mappings. */
+       for(i = 0; i < PTRS_PER_PGD; i++)
+               swapper_pg_dir[i] = __pgd(0);
+
+       cris_mmu_init();
+
+       /*
+        * Initialize the bad page table and bad page to point to a couple of
+        * allocated pages.
+        */
+       empty_zero_page = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+       memset((void *) empty_zero_page, 0, PAGE_SIZE);
+
+       /* All pages are DMA'able in Etrax, so put all in the DMA'able zone. */
+       zones_size[0] = ((unsigned long) high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+
+       for (i = 1; i < MAX_NR_ZONES; i++)
+               zones_size[i] = 0;
+
+       /*
+        * Use free_area_init_node instead of free_area_init, because it is
+        * designed for systems where the DRAM starts at an address
+        * substantially higher than 0, like us (we start at PAGE_OFFSET). This
+        * saves space in the mem_map page array.
+        */
+       free_area_init_node(0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
+
+       mem_map = contig_page_data.node_mem_map;
+}