1 /*
2 * hw_mmu.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * API definitions to setup MMU TLB and PTE
7 *
8 * Copyright (C) 2007 Texas Instruments, Inc.
9 *
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 */
18
19 #include <linux/io.h>
20 #include "MMURegAcM.h"
21 #include <hw_defs.h>
22 #include <hw_mmu.h>
23 #include <linux/types.h>
24 #include <linux/err.h>
25
26 #define MMU_BASE_VAL_MASK 0xFC00
27 #define MMU_PAGE_MAX 3
28 #define MMU_ELEMENTSIZE_MAX 3
29 #define MMU_ADDR_MASK 0xFFFFF000
30 #define MMU_TTB_MASK 0xFFFFC000
31 #define MMU_SECTION_ADDR_MASK 0xFFF00000
32 #define MMU_SSECTION_ADDR_MASK 0xFF000000
33 #define MMU_PAGE_TABLE_MASK 0xFFFFFC00
34 #define MMU_LARGE_PAGE_MASK 0xFFFF0000
35 #define MMU_SMALL_PAGE_MASK 0xFFFFF000
36
37 #define MMU_LOAD_TLB 0x00000001
38 #define MMU_GFLUSH 0x60
39
40 /*
41 * hw_mmu_page_size_t: Enumerated Type used to specify the MMU Page Size(SLSS)
42 */
43 enum hw_mmu_page_size_t {
44 HW_MMU_SECTION,
45 HW_MMU_LARGE_PAGE,
46 HW_MMU_SMALL_PAGE,
47 HW_MMU_SUPERSECTION
48 };
49
50 /*
51 * FUNCTION : mmu_set_cam_entry
52 *
53 * INPUTS:
54 *
55 * Identifier : base_address
56 * Type : void __iomem *
57 * Description : Base Address of instance of MMU module
58 *
59 * Identifier : page_sz
60 * TypE : const u32
61 * Description : It indicates the page size
62 *
63 * Identifier : preserved_bit
64 * Type : const u32
65 * Description : It indicates the TLB entry is preserved entry
66 * or not
67 *
68 * Identifier : valid_bit
69 * Type : const u32
70 * Description : It indicates the TLB entry is valid entry or not
71 *
72 *
73 * Identifier : virtual_addr_tag
74 * Type : const u32
75 * Description : virtual Address
76 *
77 * RETURNS:
78 *
79 * Type : hw_status
80 * Description : 0 -- No errors occurred
81 * RET_BAD_NULL_PARAM -- A Pointer Parameter
82 * was set to NULL
83 * RET_PARAM_OUT_OF_RANGE -- Input Parameter out
84 * of Range
85 *
86 * PURPOSE: : Set MMU_CAM reg
87 *
88 * METHOD: : Check the Input parameters and set the CAM entry.
89 */
90 static hw_status mmu_set_cam_entry(void __iomem *base_address,
91 const u32 page_sz,
92 const u32 preserved_bit,
93 const u32 valid_bit,
94 const u32 virtual_addr_tag);
95
96 /*
97 * FUNCTION : mmu_set_ram_entry
98 *
99 * INPUTS:
100 *
101 * Identifier : base_address
102 * Type : void __iomem *
103 * Description : Base Address of instance of MMU module
104 *
105 * Identifier : physical_addr
106 * Type : const u32
107 * Description : Physical Address to which the corresponding
108 * virtual Address shouldpoint
109 *
110 * Identifier : endianism
111 * Type : hw_endianism_t
112 * Description : endianism for the given page
113 *
114 * Identifier : element_size
115 * Type : hw_element_size_t
116 * Description : The element size ( 8,16, 32 or 64 bit)
117 *
118 * Identifier : mixed_size
119 * Type : hw_mmu_mixed_size_t
120 * Description : Element Size to follow CPU or TLB
121 *
122 * RETURNS:
123 *
124 * Type : hw_status
125 * Description : 0 -- No errors occurred
126 * RET_BAD_NULL_PARAM -- A Pointer Parameter
127 * was set to NULL
128 * RET_PARAM_OUT_OF_RANGE -- Input Parameter
129 * out of Range
130 *
131 * PURPOSE: : Set MMU_CAM reg
132 *
133 * METHOD: : Check the Input parameters and set the RAM entry.
134 */
135 static hw_status mmu_set_ram_entry(void __iomem *base_address,
136 const u32 physical_addr,
137 enum hw_endianism_t endianism,
138 enum hw_element_size_t element_size,
139 enum hw_mmu_mixed_size_t mixed_size);
140
141 /* HW FUNCTIONS */
142
hw_mmu_enable(void __iomem * base_address)143 hw_status hw_mmu_enable(void __iomem *base_address)
144 {
145 hw_status status = 0;
146
147 MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, HW_SET);
148
149 return status;
150 }
151
hw_mmu_disable(void __iomem * base_address)152 hw_status hw_mmu_disable(void __iomem *base_address)
153 {
154 hw_status status = 0;
155
156 MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, HW_CLEAR);
157
158 return status;
159 }
160
hw_mmu_num_locked_set(void __iomem * base_address,u32 num_locked_entries)161 hw_status hw_mmu_num_locked_set(void __iomem *base_address,
162 u32 num_locked_entries)
163 {
164 hw_status status = 0;
165
166 MMUMMU_LOCK_BASE_VALUE_WRITE32(base_address, num_locked_entries);
167
168 return status;
169 }
170
hw_mmu_victim_num_set(void __iomem * base_address,u32 victim_entry_num)171 hw_status hw_mmu_victim_num_set(void __iomem *base_address,
172 u32 victim_entry_num)
173 {
174 hw_status status = 0;
175
176 MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, victim_entry_num);
177
178 return status;
179 }
180
hw_mmu_event_ack(void __iomem * base_address,u32 irq_mask)181 hw_status hw_mmu_event_ack(void __iomem *base_address, u32 irq_mask)
182 {
183 hw_status status = 0;
184
185 MMUMMU_IRQSTATUS_WRITE_REGISTER32(base_address, irq_mask);
186
187 return status;
188 }
189
hw_mmu_event_disable(void __iomem * base_address,u32 irq_mask)190 hw_status hw_mmu_event_disable(void __iomem *base_address, u32 irq_mask)
191 {
192 hw_status status = 0;
193 u32 irq_reg;
194
195 irq_reg = MMUMMU_IRQENABLE_READ_REGISTER32(base_address);
196
197 MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, irq_reg & ~irq_mask);
198
199 return status;
200 }
201
hw_mmu_event_enable(void __iomem * base_address,u32 irq_mask)202 hw_status hw_mmu_event_enable(void __iomem *base_address, u32 irq_mask)
203 {
204 hw_status status = 0;
205 u32 irq_reg;
206
207 irq_reg = MMUMMU_IRQENABLE_READ_REGISTER32(base_address);
208
209 MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, irq_reg | irq_mask);
210
211 return status;
212 }
213
hw_mmu_event_status(void __iomem * base_address,u32 * irq_mask)214 hw_status hw_mmu_event_status(void __iomem *base_address, u32 *irq_mask)
215 {
216 hw_status status = 0;
217
218 *irq_mask = MMUMMU_IRQSTATUS_READ_REGISTER32(base_address);
219
220 return status;
221 }
222
hw_mmu_fault_addr_read(void __iomem * base_address,u32 * addr)223 hw_status hw_mmu_fault_addr_read(void __iomem *base_address, u32 *addr)
224 {
225 hw_status status = 0;
226
227 /* read values from register */
228 *addr = MMUMMU_FAULT_AD_READ_REGISTER32(base_address);
229
230 return status;
231 }
232
hw_mmu_ttb_set(void __iomem * base_address,u32 ttb_phys_addr)233 hw_status hw_mmu_ttb_set(void __iomem *base_address, u32 ttb_phys_addr)
234 {
235 hw_status status = 0;
236 u32 load_ttb;
237
238 load_ttb = ttb_phys_addr & ~0x7FUL;
239 /* write values to register */
240 MMUMMU_TTB_WRITE_REGISTER32(base_address, load_ttb);
241
242 return status;
243 }
244
hw_mmu_twl_enable(void __iomem * base_address)245 hw_status hw_mmu_twl_enable(void __iomem *base_address)
246 {
247 hw_status status = 0;
248
249 MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, HW_SET);
250
251 return status;
252 }
253
hw_mmu_twl_disable(void __iomem * base_address)254 hw_status hw_mmu_twl_disable(void __iomem *base_address)
255 {
256 hw_status status = 0;
257
258 MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, HW_CLEAR);
259
260 return status;
261 }
262
hw_mmu_tlb_add(void __iomem * base_address,u32 physical_addr,u32 virtual_addr,u32 page_sz,u32 entry_num,struct hw_mmu_map_attrs_t * map_attrs,s8 preserved_bit,s8 valid_bit)263 hw_status hw_mmu_tlb_add(void __iomem *base_address,
264 u32 physical_addr,
265 u32 virtual_addr,
266 u32 page_sz,
267 u32 entry_num,
268 struct hw_mmu_map_attrs_t *map_attrs,
269 s8 preserved_bit, s8 valid_bit)
270 {
271 hw_status status = 0;
272 u32 lock_reg;
273 u32 virtual_addr_tag;
274 enum hw_mmu_page_size_t mmu_pg_size;
275
276 /*Check the input Parameters */
277 switch (page_sz) {
278 case HW_PAGE_SIZE4KB:
279 mmu_pg_size = HW_MMU_SMALL_PAGE;
280 break;
281
282 case HW_PAGE_SIZE64KB:
283 mmu_pg_size = HW_MMU_LARGE_PAGE;
284 break;
285
286 case HW_PAGE_SIZE1MB:
287 mmu_pg_size = HW_MMU_SECTION;
288 break;
289
290 case HW_PAGE_SIZE16MB:
291 mmu_pg_size = HW_MMU_SUPERSECTION;
292 break;
293
294 default:
295 return -EINVAL;
296 }
297
298 lock_reg = MMUMMU_LOCK_READ_REGISTER32(base_address);
299
300 /* Generate the 20-bit tag from virtual address */
301 virtual_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12);
302
303 /* Write the fields in the CAM Entry Register */
304 mmu_set_cam_entry(base_address, mmu_pg_size, preserved_bit, valid_bit,
305 virtual_addr_tag);
306
307 /* Write the different fields of the RAM Entry Register */
308 /* endianism of the page,Element Size of the page (8, 16, 32, 64 bit) */
309 mmu_set_ram_entry(base_address, physical_addr, map_attrs->endianism,
310 map_attrs->element_size, map_attrs->mixed_size);
311
312 /* Update the MMU Lock Register */
313 /* currentVictim between lockedBaseValue and (MMU_Entries_Number - 1) */
314 MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, entry_num);
315
316 /* Enable loading of an entry in TLB by writing 1
317 into LD_TLB_REG register */
318 MMUMMU_LD_TLB_WRITE_REGISTER32(base_address, MMU_LOAD_TLB);
319
320 MMUMMU_LOCK_WRITE_REGISTER32(base_address, lock_reg);
321
322 return status;
323 }
324
hw_mmu_pte_set(const u32 pg_tbl_va,u32 physical_addr,u32 virtual_addr,u32 page_sz,struct hw_mmu_map_attrs_t * map_attrs)325 hw_status hw_mmu_pte_set(const u32 pg_tbl_va,
326 u32 physical_addr,
327 u32 virtual_addr,
328 u32 page_sz, struct hw_mmu_map_attrs_t *map_attrs)
329 {
330 hw_status status = 0;
331 u32 pte_addr, pte_val;
332 s32 num_entries = 1;
333
334 switch (page_sz) {
335 case HW_PAGE_SIZE4KB:
336 pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
337 virtual_addr &
338 MMU_SMALL_PAGE_MASK);
339 pte_val =
340 ((physical_addr & MMU_SMALL_PAGE_MASK) |
341 (map_attrs->endianism << 9) | (map_attrs->
342 element_size << 4) |
343 (map_attrs->mixed_size << 11) | 2);
344 break;
345
346 case HW_PAGE_SIZE64KB:
347 num_entries = 16;
348 pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
349 virtual_addr &
350 MMU_LARGE_PAGE_MASK);
351 pte_val =
352 ((physical_addr & MMU_LARGE_PAGE_MASK) |
353 (map_attrs->endianism << 9) | (map_attrs->
354 element_size << 4) |
355 (map_attrs->mixed_size << 11) | 1);
356 break;
357
358 case HW_PAGE_SIZE1MB:
359 pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
360 virtual_addr &
361 MMU_SECTION_ADDR_MASK);
362 pte_val =
363 ((((physical_addr & MMU_SECTION_ADDR_MASK) |
364 (map_attrs->endianism << 15) | (map_attrs->
365 element_size << 10) |
366 (map_attrs->mixed_size << 17)) & ~0x40000) | 0x2);
367 break;
368
369 case HW_PAGE_SIZE16MB:
370 num_entries = 16;
371 pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
372 virtual_addr &
373 MMU_SSECTION_ADDR_MASK);
374 pte_val =
375 (((physical_addr & MMU_SSECTION_ADDR_MASK) |
376 (map_attrs->endianism << 15) | (map_attrs->
377 element_size << 10) |
378 (map_attrs->mixed_size << 17)
379 ) | 0x40000 | 0x2);
380 break;
381
382 case HW_MMU_COARSE_PAGE_SIZE:
383 pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
384 virtual_addr &
385 MMU_SECTION_ADDR_MASK);
386 pte_val = (physical_addr & MMU_PAGE_TABLE_MASK) | 1;
387 break;
388
389 default:
390 return -EINVAL;
391 }
392
393 while (--num_entries >= 0)
394 ((u32 *) pte_addr)[num_entries] = pte_val;
395
396 return status;
397 }
398
hw_mmu_pte_clear(const u32 pg_tbl_va,u32 virtual_addr,u32 page_size)399 hw_status hw_mmu_pte_clear(const u32 pg_tbl_va, u32 virtual_addr, u32 page_size)
400 {
401 hw_status status = 0;
402 u32 pte_addr;
403 s32 num_entries = 1;
404
405 switch (page_size) {
406 case HW_PAGE_SIZE4KB:
407 pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
408 virtual_addr &
409 MMU_SMALL_PAGE_MASK);
410 break;
411
412 case HW_PAGE_SIZE64KB:
413 num_entries = 16;
414 pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
415 virtual_addr &
416 MMU_LARGE_PAGE_MASK);
417 break;
418
419 case HW_PAGE_SIZE1MB:
420 case HW_MMU_COARSE_PAGE_SIZE:
421 pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
422 virtual_addr &
423 MMU_SECTION_ADDR_MASK);
424 break;
425
426 case HW_PAGE_SIZE16MB:
427 num_entries = 16;
428 pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
429 virtual_addr &
430 MMU_SSECTION_ADDR_MASK);
431 break;
432
433 default:
434 return -EINVAL;
435 }
436
437 while (--num_entries >= 0)
438 ((u32 *) pte_addr)[num_entries] = 0;
439
440 return status;
441 }
442
443 /* mmu_set_cam_entry */
mmu_set_cam_entry(void __iomem * base_address,const u32 page_sz,const u32 preserved_bit,const u32 valid_bit,const u32 virtual_addr_tag)444 static hw_status mmu_set_cam_entry(void __iomem *base_address,
445 const u32 page_sz,
446 const u32 preserved_bit,
447 const u32 valid_bit,
448 const u32 virtual_addr_tag)
449 {
450 hw_status status = 0;
451 u32 mmu_cam_reg;
452
453 mmu_cam_reg = (virtual_addr_tag << 12);
454 mmu_cam_reg = (mmu_cam_reg) | (page_sz) | (valid_bit << 2) |
455 (preserved_bit << 3);
456
457 /* write values to register */
458 MMUMMU_CAM_WRITE_REGISTER32(base_address, mmu_cam_reg);
459
460 return status;
461 }
462
463 /* mmu_set_ram_entry */
mmu_set_ram_entry(void __iomem * base_address,const u32 physical_addr,enum hw_endianism_t endianism,enum hw_element_size_t element_size,enum hw_mmu_mixed_size_t mixed_size)464 static hw_status mmu_set_ram_entry(void __iomem *base_address,
465 const u32 physical_addr,
466 enum hw_endianism_t endianism,
467 enum hw_element_size_t element_size,
468 enum hw_mmu_mixed_size_t mixed_size)
469 {
470 hw_status status = 0;
471 u32 mmu_ram_reg;
472
473 mmu_ram_reg = (physical_addr & MMU_ADDR_MASK);
474 mmu_ram_reg = (mmu_ram_reg) | ((endianism << 9) | (element_size << 7) |
475 (mixed_size << 6));
476
477 /* write values to register */
478 MMUMMU_RAM_WRITE_REGISTER32(base_address, mmu_ram_reg);
479
480 return status;
481
482 }
483
hw_mmu_tlb_flush_all(void __iomem * base)484 void hw_mmu_tlb_flush_all(void __iomem *base)
485 {
486 __raw_writel(1, base + MMU_GFLUSH);
487 }
488