]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/mach-omap1/mmu.c
Merge omap-drivers
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap1 / mmu.c
1 /*
2  * linux/arch/arm/mach-omap2/mmu.c
3  *
4  * Support for non-MPU OMAP1 MMUs.
5  *
6  * Copyright (C) 2002-2005 Nokia Corporation
7  *
8  * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
9  *        and Paul Mundt <paul.mundt@nokia.com>
10  *
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.
15  *
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.
20  *
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
24  */
25 #include <linux/types.h>
26 #include <linux/init.h>
27 #include <linux/rwsem.h>
28 #include <linux/device.h>
29 #include <linux/kernel.h>
30 #include <linux/mm.h>
31 #include <linux/err.h>
32 #include "mmu.h"
33 #include <asm/tlbflush.h>
34
35 static void *dspvect_page;
36 #define DSP_INIT_PAGE   0xfff000
37
38 static unsigned int get_cam_l_va_mask(u16 pgsz)
39 {
40         switch (pgsz) {
41         case OMAP_MMU_CAM_PAGESIZE_1MB:
42                 return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
43                        OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1MB;
44         case OMAP_MMU_CAM_PAGESIZE_64KB:
45                 return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
46                        OMAP_MMU_CAM_L_VA_TAG_L2_MASK_64KB;
47         case OMAP_MMU_CAM_PAGESIZE_4KB:
48                 return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
49                        OMAP_MMU_CAM_L_VA_TAG_L2_MASK_4KB;
50         case OMAP_MMU_CAM_PAGESIZE_1KB:
51                 return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
52                        OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1KB;
53         }
54         return 0;
55 }
56
57 #define get_cam_va_mask(pgsz) \
58         ((u32)OMAP_MMU_CAM_H_VA_TAG_H_MASK << 22 | \
59          (u32)get_cam_l_va_mask(pgsz) << 6)
60
61 static int intmem_usecount;
62
63 /* for safety */
64 void dsp_mem_usecount_clear(void)
65 {
66         if (intmem_usecount != 0) {
67                 printk(KERN_WARNING
68                        "MMU: unbalanced memory request/release detected.\n"
69                        "         intmem_usecount is not zero at where "
70                        "it should be! ... fixed to be zero.\n");
71                 intmem_usecount = 0;
72                 omap_dsp_release_mem();
73         }
74 }
75 EXPORT_SYMBOL_GPL(dsp_mem_usecount_clear);
76
77 static int omap1_mmu_mem_enable(struct omap_mmu *mmu, void *addr)
78 {
79         int ret = 0;
80
81         if (omap_mmu_internal_memory(mmu, addr)) {
82                 if (intmem_usecount++ == 0)
83                         ret = omap_dsp_request_mem();
84         } else
85                 ret = -EIO;
86
87         return ret;
88 }
89
90 static int omap1_mmu_mem_disable(struct omap_mmu *mmu, void *addr)
91 {
92         int ret = 0;
93
94         if (omap_mmu_internal_memory(mmu, addr)) {
95                 if (--intmem_usecount == 0)
96                         omap_dsp_release_mem();
97         } else
98                 ret = -EIO;
99
100         return ret;
101 }
102
103 static inline void
104 omap1_mmu_read_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
105 {
106         /* read a TLB entry */
107         omap_mmu_write_reg(mmu, OMAP_MMU_LD_TLB_RD, OMAP_MMU_LD_TLB);
108
109         cr->cam_h = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM_H);
110         cr->cam_l = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM_L);
111         cr->ram_h = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM_H);
112         cr->ram_l = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM_L);
113 }
114
115 static inline void
116 omap1_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
117 {
118         /* Set the CAM and RAM entries */
119         omap_mmu_write_reg(mmu, cr->cam_h, OMAP_MMU_CAM_H);
120         omap_mmu_write_reg(mmu, cr->cam_l, OMAP_MMU_CAM_L);
121         omap_mmu_write_reg(mmu, cr->ram_h, OMAP_MMU_RAM_H);
122         omap_mmu_write_reg(mmu, cr->ram_l, OMAP_MMU_RAM_L);
123 }
124
125 static ssize_t omap1_mmu_show(struct omap_mmu *mmu, char *buf,
126                               struct omap_mmu_tlb_lock *tlb_lock)
127 {
128         int i, len;
129
130         len = sprintf(buf, "P: preserved, V: valid\n"
131                            "ety P V size   cam_va     ram_pa ap\n");
132                          /* 00: P V  4KB 0x300000 0x10171800 FA */
133
134         for (i = 0; i < mmu->nr_tlb_entries; i++) {
135                 struct omap_mmu_tlb_entry ent;
136                 struct cam_ram_regset cr;
137                 struct omap_mmu_tlb_lock entry_lock;
138                 char *pgsz_str, *ap_str;
139
140                 /* read a TLB entry */
141                 entry_lock.base   = tlb_lock->base;
142                 entry_lock.victim = i;
143                 omap_mmu_read_tlb(mmu, &entry_lock, &cr);
144
145                 ent.pgsz  = cr.cam_l & OMAP_MMU_CAM_PAGESIZE_MASK;
146                 ent.prsvd = cr.cam_l & OMAP_MMU_CAM_P;
147                 ent.valid = cr.cam_l & OMAP_MMU_CAM_V;
148                 ent.ap    = cr.ram_l & OMAP_MMU_RAM_L_AP_MASK;
149                 ent.va = (u32)(cr.cam_h & OMAP_MMU_CAM_H_VA_TAG_H_MASK) << 22 |
150                          (u32)(cr.cam_l & get_cam_l_va_mask(ent.pgsz)) << 6;
151                 ent.pa = (unsigned long)cr.ram_h << 16 |
152                          (cr.ram_l & OMAP_MMU_RAM_L_RAM_LSB_MASK);
153
154                 pgsz_str = (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1MB)  ? " 1MB":
155                            (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
156                            (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_4KB)  ? " 4KB":
157                            (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1KB)  ? " 1KB":
158                                                                      " ???";
159                 ap_str = (ent.ap == OMAP_MMU_RAM_L_AP_RO) ? "RO":
160                          (ent.ap == OMAP_MMU_RAM_L_AP_FA) ? "FA":
161                          (ent.ap == OMAP_MMU_RAM_L_AP_NA) ? "NA":
162                                                            "??";
163
164                 if (i == tlb_lock->base)
165                         len += sprintf(buf + len, "lock base = %d\n",
166                                        tlb_lock->base);
167                 if (i == tlb_lock->victim)
168                         len += sprintf(buf + len, "victim    = %d\n",
169                                        tlb_lock->victim);
170                 len += sprintf(buf + len,
171                                /* 00: P V  4KB 0x300000 0x10171800 FA */
172                                "%02d: %c %c %s 0x%06lx 0x%08lx %s\n",
173                                i,
174                                ent.prsvd ? 'P' : ' ',
175                                ent.valid ? 'V' : ' ',
176                                pgsz_str, ent.va, ent.pa, ap_str);
177         }
178
179         return len;
180 }
181
182 static int exmap_setup_preserved_entries(struct omap_mmu *mmu)
183 {
184         int n = 0;
185
186         exmap_setup_preserved_mem_page(mmu, dspvect_page, DSP_INIT_PAGE, n++);
187
188         return n;
189 }
190
191 static void exmap_clear_preserved_entries(struct omap_mmu *mmu)
192 {
193         exmap_clear_mem_page(mmu, DSP_INIT_PAGE);
194 }
195
196 static int omap1_mmu_startup(struct omap_mmu *mmu)
197 {
198         dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
199         if (dspvect_page == NULL) {
200                 printk(KERN_ERR "MMU: failed to allocate memory "
201                                 "for dsp vector table\n");
202                 return -ENOMEM;
203         }
204
205         mmu->nr_exmap_preserved = exmap_setup_preserved_entries(mmu);
206
207         return 0;
208 }
209
210 static void omap1_mmu_shutdown(struct omap_mmu *mmu)
211 {
212         exmap_clear_preserved_entries(mmu);
213
214         if (dspvect_page != NULL) {
215                 unsigned long virt;
216
217                 down_read(&mmu->exmap_sem);
218
219                 virt = (unsigned long)omap_mmu_to_virt(mmu, DSP_INIT_PAGE);
220                 flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
221                 free_page((unsigned long)dspvect_page);
222                 dspvect_page = NULL;
223
224                 up_read(&mmu->exmap_sem);
225         }
226 }
227
228 static inline unsigned long omap1_mmu_cam_va(struct cam_ram_regset *cr)
229 {
230         unsigned int page_size = cr->cam_l & OMAP_MMU_CAM_PAGESIZE_MASK;
231
232         return (u32)(cr->cam_h & OMAP_MMU_CAM_H_VA_TAG_H_MASK)  << 22 |
233                (u32)(cr->cam_l & get_cam_l_va_mask(page_size)) << 6;
234 }
235
236 static struct cam_ram_regset *
237 omap1_mmu_cam_ram_alloc(struct omap_mmu_tlb_entry *entry)
238 {
239         struct cam_ram_regset *cr;
240
241         if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
242                 printk(KERN_ERR "MMU: mapping vadr (0x%06lx) is not on an "
243                        "aligned boundary\n", entry->va);
244                 return ERR_PTR(-EINVAL);
245         }
246
247         cr = kmalloc(sizeof(struct cam_ram_regset), GFP_KERNEL);
248
249         cr->cam_h = entry->va >> 22;
250         cr->cam_l = (entry->va >> 6 & get_cam_l_va_mask(entry->pgsz)) |
251                    entry->prsvd | entry->pgsz;
252         cr->ram_h = entry->pa >> 16;
253         cr->ram_l = (entry->pa & OMAP_MMU_RAM_L_RAM_LSB_MASK) | entry->ap;
254
255         return cr;
256 }
257
258 static inline int omap1_mmu_cam_ram_valid(struct cam_ram_regset *cr)
259 {
260         return cr->cam_l & OMAP_MMU_CAM_V;
261 }
262
263 struct omap_mmu_ops omap1_mmu_ops = {
264         .startup        = omap1_mmu_startup,
265         .shutdown       = omap1_mmu_shutdown,
266         .mem_enable     = omap1_mmu_mem_enable,
267         .mem_disable    = omap1_mmu_mem_disable,
268         .read_tlb       = omap1_mmu_read_tlb,
269         .load_tlb       = omap1_mmu_load_tlb,
270         .show           = omap1_mmu_show,
271         .cam_va         = omap1_mmu_cam_va,
272         .cam_ram_alloc  = omap1_mmu_cam_ram_alloc,
273         .cam_ram_valid  = omap1_mmu_cam_ram_valid,
274 };
275 EXPORT_SYMBOL_GPL(omap1_mmu_ops);