2 * linux/arch/arm/mach-omap2/mmu.c
4 * Support for non-MPU OMAP2 MMUs.
6 * Copyright (C) 2002-2005 Nokia Corporation
8 * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
9 * and Paul Mundt <paul.mundt@nokia.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <linux/types.h>
26 #include <linux/init.h>
27 #include <linux/rwsem.h>
28 #include <linux/device.h>
31 #include <asm/arch/mmu.h>
32 #include <asm/tlbflush.h>
34 #include <asm/sizes.h>
36 static void *dspvect_page;
37 #define DSP_INIT_PAGE 0xfff000
40 omap2_mmu_read_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
42 cr->cam = omap_mmu_read_reg(mmu, MMU_READ_CAM);
43 cr->ram = omap_mmu_read_reg(mmu, MMU_READ_RAM);
47 omap2_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
49 /* Set the CAM and RAM entries */
50 omap_mmu_write_reg(mmu, cr->cam | OMAP_MMU_CAM_V, MMU_CAM);
51 omap_mmu_write_reg(mmu, cr->ram, MMU_RAM);
54 static void exmap_setup_iomap_page(struct omap_mmu *mmu, unsigned long phys,
55 unsigned long dsp_io_adr, int index)
59 struct omap_mmu_tlb_entry tlb_ent;
61 dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
62 virt = omap_mmu_to_virt(mmu, dspadr);
63 exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
64 INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(mmu->exmap_tbl + index, NULL, virt);
65 INIT_TLB_ENTRY_4KB_ES32_PRESERVED(&tlb_ent, dspadr, phys);
66 omap_mmu_load_tlb_entry(mmu, &tlb_ent);
69 static void exmap_clear_iomap_page(struct omap_mmu *mmu,
70 unsigned long dsp_io_adr)
75 dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
76 virt = omap_mmu_to_virt(mmu, dspadr);
77 exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE);
78 /* DSP MMU is shutting down. not handled here. */
81 #define OMAP24XX_MAILBOX_BASE (L4_24XX_BASE + 0x94000)
82 #define OMAP2420_GPT5_BASE (L4_24XX_BASE + 0x7c000)
83 #define OMAP2420_GPT6_BASE (L4_24XX_BASE + 0x7e000)
84 #define OMAP2420_GPT7_BASE (L4_24XX_BASE + 0x80000)
85 #define OMAP2420_GPT8_BASE (L4_24XX_BASE + 0x82000)
86 #define OMAP24XX_EAC_BASE (L4_24XX_BASE + 0x90000)
87 #define OMAP24XX_STI_BASE (L4_24XX_BASE + 0x68000)
88 #define OMAP24XX_STI_CH_BASE (L4_24XX_BASE + 0x0c000000)
90 static int exmap_setup_preserved_entries(struct omap_mmu *mmu)
94 exmap_setup_preserved_mem_page(mmu, dspvect_page, DSP_INIT_PAGE, n++);
96 exmap_setup_iomap_page(mmu, OMAP24XX_PRCM_BASE, 0x7000, n++);
97 exmap_setup_iomap_page(mmu, OMAP24XX_MAILBOX_BASE, 0x11000, n++);
99 if (cpu_is_omap2420()) {
100 exmap_setup_iomap_page(mmu, OMAP2420_GPT5_BASE, 0xe000, n++);
101 exmap_setup_iomap_page(mmu, OMAP2420_GPT6_BASE, 0xe800, n++);
102 exmap_setup_iomap_page(mmu, OMAP2420_GPT7_BASE, 0xf000, n++);
103 exmap_setup_iomap_page(mmu, OMAP2420_GPT8_BASE, 0xf800, n++);
104 exmap_setup_iomap_page(mmu, OMAP24XX_EAC_BASE, 0x10000, n++);
105 exmap_setup_iomap_page(mmu, OMAP24XX_STI_BASE, 0xc800, n++);
106 for (i = 0; i < 5; i++)
107 exmap_setup_preserved_mem_page(mmu,
108 __va(OMAP24XX_STI_CH_BASE + i*SZ_4K),
109 0xfb0000 + i*SZ_4K, n++);
115 static void exmap_clear_preserved_entries(struct omap_mmu *mmu)
119 exmap_clear_iomap_page(mmu, 0x7000); /* PRCM registers */
120 exmap_clear_iomap_page(mmu, 0x11000); /* MAILBOX registers */
122 if (cpu_is_omap2420()) {
123 exmap_clear_iomap_page(mmu, 0xe000); /* GPT5 */
124 exmap_clear_iomap_page(mmu, 0xe800); /* GPT6 */
125 exmap_clear_iomap_page(mmu, 0xf000); /* GPT7 */
126 exmap_clear_iomap_page(mmu, 0xf800); /* GPT8 */
127 exmap_clear_iomap_page(mmu, 0x10000); /* EAC */
128 exmap_clear_iomap_page(mmu, 0xc800); /* STI */
129 for (i = 0; i < 5; i++) /* STI CH */
130 exmap_clear_mem_page(mmu, 0xfb0000 + i*SZ_4K);
133 exmap_clear_mem_page(mmu, DSP_INIT_PAGE);
136 #define MMU_IRQ_MASK \
137 (OMAP_MMU_IRQ_MULTIHITFAULT | \
138 OMAP_MMU_IRQ_TABLEWALKFAULT | \
139 OMAP_MMU_IRQ_EMUMISS | \
140 OMAP_MMU_IRQ_TRANSLATIONFAULT | \
141 OMAP_MMU_IRQ_TLBMISS)
143 static int omap2_mmu_startup(struct omap_mmu *mmu)
145 dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
146 if (dspvect_page == NULL) {
147 printk(KERN_ERR "MMU: failed to allocate memory "
148 "for dsp vector table\n");
152 mmu->nr_exmap_preserved = exmap_setup_preserved_entries(mmu);
154 omap_mmu_write_reg(mmu, MMU_IRQ_MASK, MMU_IRQENABLE);
159 static void omap2_mmu_shutdown(struct omap_mmu *mmu)
161 exmap_clear_preserved_entries(mmu);
163 if (dspvect_page != NULL) {
166 down_read(&mmu->exmap_sem);
168 virt = (unsigned long)omap_mmu_to_virt(mmu, DSP_INIT_PAGE);
169 flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
170 free_page((unsigned long)dspvect_page);
173 up_read(&mmu->exmap_sem);
177 static ssize_t omap2_mmu_show(struct omap_mmu *mmu, char *buf,
178 struct omap_mmu_tlb_lock *tlb_lock)
182 len = sprintf(buf, "P: preserved, V: valid\n"
183 "B: big endian, L:little endian, "
184 "M: mixed page attribute\n"
185 "ety P V size cam_va ram_pa E ES M\n");
186 /* 00: P V 4KB 0x300000 0x10171800 B 16 M */
188 for (i = 0; i < mmu->nr_tlb_entries; i++) {
189 struct omap_mmu_tlb_entry ent;
190 struct cam_ram_regset cr;
191 struct omap_mmu_tlb_lock entry_lock;
192 char *pgsz_str, *elsz_str;
194 /* read a TLB entry */
195 entry_lock.base = tlb_lock->base;
196 entry_lock.victim = i;
197 omap_mmu_read_tlb(mmu, &entry_lock, &cr);
199 ent.pgsz = cr.cam & OMAP_MMU_CAM_PAGESIZE_MASK;
200 ent.prsvd = cr.cam & OMAP_MMU_CAM_P;
201 ent.valid = cr.cam & OMAP_MMU_CAM_V;
202 ent.va = cr.cam & OMAP_MMU_CAM_VATAG_MASK;
203 ent.endian = cr.ram & OMAP_MMU_RAM_ENDIANNESS;
204 ent.elsz = cr.ram & OMAP_MMU_RAM_ELEMENTSIZE_MASK;
205 ent.pa = cr.ram & OMAP_MMU_RAM_PADDR_MASK;
206 ent.mixed = cr.ram & OMAP_MMU_RAM_MIXED;
208 pgsz_str = (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_16MB) ? "64MB":
209 (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1MB) ? " 1MB":
210 (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
211 (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_4KB) ? " 4KB":
213 elsz_str = (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_8) ? " 8":
214 (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_16) ? "16":
215 (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_32) ? "32":
218 if (i == tlb_lock->base)
219 len += sprintf(buf + len, "lock base = %d\n",
221 if (i == tlb_lock->victim)
222 len += sprintf(buf + len, "victim = %d\n",
225 len += sprintf(buf + len,
226 /* 00: P V 4KB 0x300000 0x10171800 B 16 M */
227 "%02d: %c %c %s 0x%06lx 0x%08lx %c %s %c\n",
229 ent.prsvd ? 'P' : ' ',
230 ent.valid ? 'V' : ' ',
231 pgsz_str, ent.va, ent.pa,
232 ent.endian ? 'B' : 'L',
234 ent.mixed ? 'M' : ' ');
240 #define get_cam_va_mask(pgsz) \
241 (((pgsz) == OMAP_MMU_CAM_PAGESIZE_16MB) ? 0xff000000 : \
242 ((pgsz) == OMAP_MMU_CAM_PAGESIZE_1MB) ? 0xfff00000 : \
243 ((pgsz) == OMAP_MMU_CAM_PAGESIZE_64KB) ? 0xffff0000 : \
244 ((pgsz) == OMAP_MMU_CAM_PAGESIZE_4KB) ? 0xfffff000 : 0)
246 static inline unsigned long omap2_mmu_cam_va(struct cam_ram_regset *cr)
248 unsigned int page_size = cr->cam & OMAP_MMU_CAM_PAGESIZE_MASK;
249 unsigned int mask = get_cam_va_mask(cr->cam & page_size);
251 return cr->cam & mask;
254 static struct cam_ram_regset *
255 omap2_mmu_cam_ram_alloc(struct omap_mmu_tlb_entry *entry)
257 struct cam_ram_regset *cr;
259 if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
260 printk(KERN_ERR "MMU: mapping vadr (0x%06lx) is not on an "
261 "aligned boundary\n", entry->va);
262 return ERR_PTR(-EINVAL);
265 cr = kmalloc(sizeof(struct cam_ram_regset), GFP_KERNEL);
267 cr->cam = (entry->va & OMAP_MMU_CAM_VATAG_MASK) |
268 entry->prsvd | entry->pgsz;
269 cr->ram = entry->pa | entry->endian | entry->elsz;
274 static inline int omap2_mmu_cam_ram_valid(struct cam_ram_regset *cr)
276 return cr->cam & OMAP_MMU_CAM_V;
279 struct omap_mmu_ops omap2_mmu_ops = {
280 .startup = omap2_mmu_startup,
281 .shutdown = omap2_mmu_shutdown,
282 .read_tlb = omap2_mmu_read_tlb,
283 .load_tlb = omap2_mmu_load_tlb,
284 .show = omap2_mmu_show,
285 .cam_va = omap2_mmu_cam_va,
286 .cam_ram_alloc = omap2_mmu_cam_ram_alloc,
287 .cam_ram_valid = omap2_mmu_cam_ram_valid,
289 EXPORT_SYMBOL_GPL(omap2_mmu_ops);
291 MODULE_LICENSE("GPL");