2 * Copyright 2008-2011 Freescale Semiconductor, Inc.
5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7 * See file CREDITS for list of people who contributed to this
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27 #include <asm/processor.h>
29 #ifdef CONFIG_ADDR_MAP
33 DECLARE_GLOBAL_DATA_PTR
;
35 void invalidate_tlb(u8 tlb
)
47 for (i
= 0; i
< num_tlb_entries
; i
++) {
48 write_tlb(tlb_table
[i
].mas0
,
58 #ifndef CONFIG_NAND_SPL
59 void read_tlbcam_entry(int idx
, u32
*valid
, u32
*tsize
, unsigned long *epn
,
64 mtspr(MAS0
, FSL_BOOKE_MAS0(1, idx
, 0));
65 asm volatile("tlbre;isync");
68 *valid
= (_mas1
& MAS1_VALID
);
69 *tsize
= (_mas1
>> 8) & 0xf;
70 *epn
= mfspr(MAS2
) & MAS2_EPN
;
71 *rpn
= mfspr(MAS3
) & MAS3_RPN
;
72 #ifdef CONFIG_ENABLE_36BIT_PHYS
73 *rpn
|= ((u64
)mfspr(MAS7
)) << 32;
77 void print_tlbcam(void)
80 unsigned int num_cam
= mfspr(SPRN_TLB1CFG
) & 0xfff;
82 /* walk all the entries */
83 printf("TLBCAM entries\n");
84 for (i
= 0; i
< num_cam
; i
++) {
89 read_tlbcam_entry(i
, &valid
, &tsize
, &epn
, &rpn
);
90 printf("entry %02d: V: %d EPN 0x%08x RPN 0x%08llx size:",
91 i
, (valid
== 0) ? 0 : 1, (unsigned int)epn
,
92 (unsigned long long)rpn
);
93 print_size(TSIZE_TO_BYTES(tsize
), "\n");
97 static inline void use_tlb_cam(u8 idx
)
102 gd
->used_tlb_cams
[i
] |= (1 << bit
);
105 static inline void free_tlb_cam(u8 idx
)
110 gd
->used_tlb_cams
[i
] &= ~(1 << bit
);
113 void init_used_tlb_cams(void)
116 unsigned int num_cam
= mfspr(SPRN_TLB1CFG
) & 0xfff;
118 for (i
= 0; i
< ((CONFIG_SYS_NUM_TLBCAMS
+31)/32); i
++)
119 gd
->used_tlb_cams
[i
] = 0;
121 /* walk all the entries */
122 for (i
= 0; i
< num_cam
; i
++) {
123 mtspr(MAS0
, FSL_BOOKE_MAS0(1, i
, 0));
124 asm volatile("tlbre;isync");
125 if (mfspr(MAS1
) & MAS1_VALID
)
130 int find_free_tlbcam(void)
135 for (i
= 0; i
< ((CONFIG_SYS_NUM_TLBCAMS
+31)/32); i
++) {
136 idx
= ffz(gd
->used_tlb_cams
[i
]);
144 if (idx
>= CONFIG_SYS_NUM_TLBCAMS
)
150 void set_tlb(u8 tlb
, u32 epn
, u64 rpn
,
152 u8 ts
, u8 esel
, u8 tsize
, u8 iprot
)
154 u32 _mas0
, _mas1
, _mas2
, _mas3
, _mas7
;
159 _mas0
= FSL_BOOKE_MAS0(tlb
, esel
, 0);
160 _mas1
= FSL_BOOKE_MAS1(1, iprot
, 0, ts
, tsize
);
161 _mas2
= FSL_BOOKE_MAS2(epn
, wimge
);
162 _mas3
= FSL_BOOKE_MAS3(rpn
, 0, perms
);
163 _mas7
= FSL_BOOKE_MAS7(rpn
);
165 write_tlb(_mas0
, _mas1
, _mas2
, _mas3
, _mas7
);
167 #ifdef CONFIG_ADDR_MAP
168 if ((tlb
== 1) && (gd
->flags
& GD_FLG_RELOC
))
169 addrmap_set_entry(epn
, rpn
, TSIZE_TO_BYTES(tsize
), esel
);
173 void disable_tlb(u8 esel
)
175 u32 _mas0
, _mas1
, _mas2
, _mas3
, _mas7
;
179 _mas0
= FSL_BOOKE_MAS0(1, esel
, 0);
189 #ifdef CONFIG_ENABLE_36BIT_PHYS
192 asm volatile("isync;msync;tlbwe;isync");
194 #ifdef CONFIG_ADDR_MAP
195 if (gd
->flags
& GD_FLG_RELOC
)
196 addrmap_set_entry(0, 0, 0, esel
);
200 static void tlbsx (const volatile unsigned *addr
)
202 __asm__
__volatile__ ("tlbsx 0,%0" : : "r" (addr
), "m" (*addr
));
205 /* return -1 if we didn't find anything */
206 int find_tlb_idx(void *addr
, u8 tlbsel
)
210 /* zero out Search PID, AS */
218 /* we found something, and its in the TLB we expect */
219 if ((MAS1_VALID
& _mas1
) &&
220 (MAS0_TLBSEL(tlbsel
) == (_mas0
& MAS0_TLBSEL_MSK
))) {
221 return ((_mas0
& MAS0_ESEL_MSK
) >> 16);
227 #ifdef CONFIG_ADDR_MAP
228 void init_addr_map(void)
231 unsigned int num_cam
= mfspr(SPRN_TLB1CFG
) & 0xfff;
233 /* walk all the entries */
234 for (i
= 0; i
< num_cam
; i
++) {
239 read_tlbcam_entry(i
, &valid
, &tsize
, &epn
, &rpn
);
240 if (valid
& MAS1_VALID
)
241 addrmap_set_entry(epn
, rpn
, TSIZE_TO_BYTES(tsize
), i
);
249 setup_ddr_tlbs_phys(phys_addr_t p_addr
, unsigned int memsize_in_meg
)
252 unsigned int tlb_size
;
253 unsigned int wimge
= 0;
254 unsigned int ram_tlb_address
= (unsigned int)CONFIG_SYS_DDR_SDRAM_BASE
;
255 unsigned int max_cam
;
256 u64 size
, memsize
= (u64
)memsize_in_meg
<< 20;
258 #ifdef CONFIG_SYS_PPC_DDR_WIMGE
259 wimge
= CONFIG_SYS_PPC_DDR_WIMGE
;
261 size
= min(memsize
, CONFIG_MAX_MEM_MAPPED
);
262 if ((mfspr(SPRN_MMUCFG
) & MMUCFG_MAVN
) == MMUCFG_MAVN_V1
) {
263 /* Convert (4^max) kB to (2^max) bytes */
264 max_cam
= ((mfspr(SPRN_TLB1CFG
) >> 16) & 0xf) * 2 + 10;
266 /* Convert (2^max) kB to (2^max) bytes */
267 max_cam
= __ilog2(mfspr(SPRN_TLB1PS
)) + 10;
270 for (i
= 0; size
&& i
< 8; i
++) {
271 int ram_tlb_index
= find_free_tlbcam();
272 u32 camsize
= __ilog2_u64(size
) & ~1U;
273 u32 align
= __ilog2(ram_tlb_address
) & ~1U;
275 if (ram_tlb_index
== -1)
278 if (align
== -2) align
= max_cam
;
282 if (camsize
> max_cam
)
285 tlb_size
= (camsize
- 10) / 2;
287 set_tlb(1, ram_tlb_address
, p_addr
,
288 MAS3_SX
|MAS3_SW
|MAS3_SR
, wimge
,
289 0, ram_tlb_index
, tlb_size
, 1);
291 size
-= 1ULL << camsize
;
292 memsize
-= 1ULL << camsize
;
293 ram_tlb_address
+= 1UL << camsize
;
294 p_addr
+= 1UL << camsize
;
298 print_size(memsize
, " left unmapped\n");
299 return memsize_in_meg
;
302 unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg
)
305 setup_ddr_tlbs_phys(CONFIG_SYS_DDR_SDRAM_BASE
, memsize_in_meg
);
308 /* Invalidate the DDR TLBs for the requested size */
309 void clear_ddr_tlbs_phys(phys_addr_t p_addr
, unsigned int memsize_in_meg
)
311 u32 vstart
= CONFIG_SYS_DDR_SDRAM_BASE
;
313 u32 tsize
, valid
, ptr
;
316 u64 memsize
= (u64
)memsize_in_meg
<< 20;
320 while (ptr
< (vstart
+ memsize
)) {
321 ddr_esel
= find_tlb_idx((void *)ptr
, 1);
322 if (ddr_esel
!= -1) {
323 read_tlbcam_entry(ddr_esel
, &valid
, &tsize
, &epn
, &rpn
);
324 disable_tlb(ddr_esel
);
326 ptr
+= TSIZE_TO_BYTES(tsize
);
330 void clear_ddr_tlbs(unsigned int memsize_in_meg
)
332 clear_ddr_tlbs_phys(CONFIG_SYS_DDR_SDRAM_BASE
, memsize_in_meg
);
336 #endif /* !CONFIG_NAND_SPL */