blob: 6ecbedfed96c33f3938131bd5a3dd7b60df9fd7f [file] [log] [blame]
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +02001/*
2 * (C) Copyright 2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25#include <asm/system.h>
R Sricharan96fdbec2013-03-04 20:04:44 +000026#include <asm/cache.h>
27#include <linux/compiler.h>
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +020028
Aneesh Ve47f2db2011-06-16 23:30:48 +000029#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
Heiko Schocher880eff52010-09-17 13:10:29 +020030
Heiko Schocher880eff52010-09-17 13:10:29 +020031DECLARE_GLOBAL_DATA_PTR;
32
Aneesh Vc2dd0d42011-06-16 23:30:49 +000033void __arm_init_before_mmu(void)
34{
35}
36void arm_init_before_mmu(void)
37 __attribute__((weak, alias("__arm_init_before_mmu")));
38
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +020039static void cp_delay (void)
40{
41 volatile int i;
42
43 /* copro seems to need some delay between reading and writing */
44 for (i = 0; i < 100; i++)
45 nop();
Heiko Schocher880eff52010-09-17 13:10:29 +020046 asm volatile("" : : : "memory");
47}
48
Simon Glass0dde7f52012-10-17 13:24:53 +000049void set_section_dcache(int section, enum dcache_option option)
Heiko Schocherf1d2b312010-09-17 13:10:39 +020050{
Simon Glass34fd5d22012-12-13 20:48:39 +000051 u32 *page_table = (u32 *)gd->arch.tlb_addr;
Simon Glass0dde7f52012-10-17 13:24:53 +000052 u32 value;
53
54 value = (section << MMU_SECTION_SHIFT) | (3 << 10);
55 value |= option;
56 page_table[section] = value;
57}
58
59void __mmu_page_table_flush(unsigned long start, unsigned long stop)
60{
61 debug("%s: Warning: not implemented\n", __func__);
62}
63
64void mmu_page_table_flush(unsigned long start, unsigned long stop)
65 __attribute__((weak, alias("__mmu_page_table_flush")));
66
67void mmu_set_region_dcache_behaviour(u32 start, int size,
68 enum dcache_option option)
69{
Simon Glass34fd5d22012-12-13 20:48:39 +000070 u32 *page_table = (u32 *)gd->arch.tlb_addr;
Simon Glass0dde7f52012-10-17 13:24:53 +000071 u32 upto, end;
72
73 end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT;
74 start = start >> MMU_SECTION_SHIFT;
75 debug("%s: start=%x, size=%x, option=%d\n", __func__, start, size,
76 option);
77 for (upto = start; upto < end; upto++)
78 set_section_dcache(upto, option);
79 mmu_page_table_flush((u32)&page_table[start], (u32)&page_table[end]);
80}
81
R Sricharan96fdbec2013-03-04 20:04:44 +000082__weak void dram_bank_mmu_setup(int bank)
Simon Glass0dde7f52012-10-17 13:24:53 +000083{
Heiko Schocherf1d2b312010-09-17 13:10:39 +020084 bd_t *bd = gd->bd;
85 int i;
86
87 debug("%s: bank: %d\n", __func__, bank);
88 for (i = bd->bi_dram[bank].start >> 20;
89 i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
90 i++) {
Simon Glass0dde7f52012-10-17 13:24:53 +000091#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
92 set_section_dcache(i, DCACHE_WRITETHROUGH);
93#else
94 set_section_dcache(i, DCACHE_WRITEBACK);
95#endif
Heiko Schocherf1d2b312010-09-17 13:10:39 +020096 }
97}
Heiko Schocherf1d2b312010-09-17 13:10:39 +020098
99/* to activate the MMU we need to set up virtual memory: use 1M areas */
Heiko Schocher880eff52010-09-17 13:10:29 +0200100static inline void mmu_setup(void)
101{
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200102 int i;
Heiko Schocher880eff52010-09-17 13:10:29 +0200103 u32 reg;
104
Aneesh Vc2dd0d42011-06-16 23:30:49 +0000105 arm_init_before_mmu();
Heiko Schocher880eff52010-09-17 13:10:29 +0200106 /* Set up an identity-mapping for all 4GB, rw for everyone */
107 for (i = 0; i < 4096; i++)
Simon Glass0dde7f52012-10-17 13:24:53 +0000108 set_section_dcache(i, DCACHE_OFF);
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200109
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200110 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
111 dram_bank_mmu_setup(i);
112 }
Heiko Schocher880eff52010-09-17 13:10:29 +0200113
114 /* Copy the page table address to cp15 */
115 asm volatile("mcr p15, 0, %0, c2, c0, 0"
Simon Glass34fd5d22012-12-13 20:48:39 +0000116 : : "r" (gd->arch.tlb_addr) : "memory");
Heiko Schocher880eff52010-09-17 13:10:29 +0200117 /* Set the access control to all-supervisor */
118 asm volatile("mcr p15, 0, %0, c3, c0, 0"
119 : : "r" (~0));
120 /* and enable the mmu */
121 reg = get_cr(); /* get control reg. */
122 cp_delay();
123 set_cr(reg | CR_M);
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200124}
125
Aneesh Ve05f0072011-06-16 23:30:50 +0000126static int mmu_enabled(void)
127{
128 return get_cr() & CR_M;
129}
130
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200131/* cache_bit must be either CR_I or CR_C */
132static void cache_enable(uint32_t cache_bit)
133{
134 uint32_t reg;
135
Heiko Schocher880eff52010-09-17 13:10:29 +0200136 /* The data cache is not active unless the mmu is enabled too */
Aneesh Ve05f0072011-06-16 23:30:50 +0000137 if ((cache_bit == CR_C) && !mmu_enabled())
Heiko Schocher880eff52010-09-17 13:10:29 +0200138 mmu_setup();
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200139 reg = get_cr(); /* get control reg. */
140 cp_delay();
141 set_cr(reg | cache_bit);
142}
143
144/* cache_bit must be either CR_I or CR_C */
145static void cache_disable(uint32_t cache_bit)
146{
147 uint32_t reg;
148
SRICHARAN Rd702b082012-05-16 23:52:54 +0000149 reg = get_cr();
150 cp_delay();
151
Heiko Schocher880eff52010-09-17 13:10:29 +0200152 if (cache_bit == CR_C) {
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200153 /* if cache isn;t enabled no need to disable */
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200154 if ((reg & CR_C) != CR_C)
155 return;
Heiko Schocher880eff52010-09-17 13:10:29 +0200156 /* if disabling data cache, disable mmu too */
157 cache_bit |= CR_M;
Heiko Schocher880eff52010-09-17 13:10:29 +0200158 }
Arun Mankuzhi44df5e82012-11-30 13:01:14 +0000159 reg = get_cr();
160 cp_delay();
161 if (cache_bit == (CR_C | CR_M))
162 flush_dcache_all();
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200163 set_cr(reg & ~cache_bit);
164}
165#endif
166
Aneesh Ve47f2db2011-06-16 23:30:48 +0000167#ifdef CONFIG_SYS_ICACHE_OFF
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200168void icache_enable (void)
169{
170 return;
171}
172
173void icache_disable (void)
174{
175 return;
176}
177
178int icache_status (void)
179{
180 return 0; /* always off */
181}
182#else
183void icache_enable(void)
184{
185 cache_enable(CR_I);
186}
187
188void icache_disable(void)
189{
190 cache_disable(CR_I);
191}
192
193int icache_status(void)
194{
195 return (get_cr() & CR_I) != 0;
196}
197#endif
198
Aneesh Ve47f2db2011-06-16 23:30:48 +0000199#ifdef CONFIG_SYS_DCACHE_OFF
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200200void dcache_enable (void)
201{
202 return;
203}
204
205void dcache_disable (void)
206{
207 return;
208}
209
210int dcache_status (void)
211{
212 return 0; /* always off */
213}
214#else
215void dcache_enable(void)
216{
217 cache_enable(CR_C);
218}
219
220void dcache_disable(void)
221{
222 cache_disable(CR_C);
223}
224
225int dcache_status(void)
226{
227 return (get_cr() & CR_C) != 0;
228}
229#endif