blob: f0c1b03728be3bca6ff16e0ded0abb4eeb19abae [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 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +02006 */
7
8#include <common.h>
9#include <asm/system.h>
R Sricharan96fdbec2013-03-04 20:04:44 +000010#include <asm/cache.h>
11#include <linux/compiler.h>
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +020012
Aneesh Ve47f2db2011-06-16 23:30:48 +000013#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
Heiko Schocher880eff52010-09-17 13:10:29 +020014
Heiko Schocher880eff52010-09-17 13:10:29 +020015DECLARE_GLOBAL_DATA_PTR;
16
Jeroen Hofsteefcfddfd2014-06-23 22:07:04 +020017__weak void arm_init_before_mmu(void)
Aneesh Vc2dd0d42011-06-16 23:30:49 +000018{
19}
Aneesh Vc2dd0d42011-06-16 23:30:49 +000020
R Sricharande63ac22013-03-04 20:04:45 +000021__weak void arm_init_domains(void)
22{
23}
24
Simon Glass0dde7f52012-10-17 13:24:53 +000025void set_section_dcache(int section, enum dcache_option option)
Heiko Schocherf1d2b312010-09-17 13:10:39 +020026{
Alexander Grafd990f5c2016-03-16 15:41:21 +010027#ifdef CONFIG_ARMV7_LPAE
28 u64 *page_table = (u64 *)gd->arch.tlb_addr;
29 /* Need to set the access flag to not fault */
30 u64 value = TTB_SECT_AP | TTB_SECT_AF;
31#else
Simon Glass34fd5d22012-12-13 20:48:39 +000032 u32 *page_table = (u32 *)gd->arch.tlb_addr;
Alexander Grafd990f5c2016-03-16 15:41:21 +010033 u32 value = TTB_SECT_AP;
34#endif
Simon Glass0dde7f52012-10-17 13:24:53 +000035
Alexander Grafd990f5c2016-03-16 15:41:21 +010036 /* Add the page offset */
37 value |= ((u32)section << MMU_SECTION_SHIFT);
38
39 /* Add caching bits */
Simon Glass0dde7f52012-10-17 13:24:53 +000040 value |= option;
Alexander Grafd990f5c2016-03-16 15:41:21 +010041
42 /* Set PTE */
Simon Glass0dde7f52012-10-17 13:24:53 +000043 page_table[section] = value;
44}
45
Jeroen Hofsteefcfddfd2014-06-23 22:07:04 +020046__weak void mmu_page_table_flush(unsigned long start, unsigned long stop)
Simon Glass0dde7f52012-10-17 13:24:53 +000047{
48 debug("%s: Warning: not implemented\n", __func__);
49}
50
Thierry Reding25026fa2014-08-26 17:34:21 +020051void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
Simon Glass0dde7f52012-10-17 13:24:53 +000052 enum dcache_option option)
53{
Stefan Agnerc5b3cab2016-08-14 21:33:00 -070054#ifdef CONFIG_ARMV7_LPAE
55 u64 *page_table = (u64 *)gd->arch.tlb_addr;
56#else
Simon Glass34fd5d22012-12-13 20:48:39 +000057 u32 *page_table = (u32 *)gd->arch.tlb_addr;
Stefan Agnerc5b3cab2016-08-14 21:33:00 -070058#endif
Stefan Agner8f894a42016-08-14 21:33:01 -070059 unsigned long startpt, stoppt;
Thierry Reding25026fa2014-08-26 17:34:21 +020060 unsigned long upto, end;
Simon Glass0dde7f52012-10-17 13:24:53 +000061
62 end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT;
63 start = start >> MMU_SECTION_SHIFT;
Keerthy06d43c82016-10-29 15:19:10 +053064#ifdef CONFIG_ARMV7_LPAE
65 debug("%s: start=%pa, size=%zu, option=%llx\n", __func__, &start, size,
66 option);
67#else
Keerthy2b373cb2016-10-29 15:19:09 +053068 debug("%s: start=%pa, size=%zu, option=0x%x\n", __func__, &start, size,
Simon Glass0dde7f52012-10-17 13:24:53 +000069 option);
Keerthy06d43c82016-10-29 15:19:10 +053070#endif
Simon Glass0dde7f52012-10-17 13:24:53 +000071 for (upto = start; upto < end; upto++)
72 set_section_dcache(upto, option);
Stefan Agner8f894a42016-08-14 21:33:01 -070073
74 /*
75 * Make sure range is cache line aligned
76 * Only CPU maintains page tables, hence it is safe to always
77 * flush complete cache lines...
78 */
79
80 startpt = (unsigned long)&page_table[start];
81 startpt &= ~(CONFIG_SYS_CACHELINE_SIZE - 1);
82 stoppt = (unsigned long)&page_table[end];
83 stoppt = ALIGN(stoppt, CONFIG_SYS_CACHELINE_SIZE);
84 mmu_page_table_flush(startpt, stoppt);
Simon Glass0dde7f52012-10-17 13:24:53 +000085}
86
R Sricharan96fdbec2013-03-04 20:04:44 +000087__weak void dram_bank_mmu_setup(int bank)
Simon Glass0dde7f52012-10-17 13:24:53 +000088{
Heiko Schocherf1d2b312010-09-17 13:10:39 +020089 bd_t *bd = gd->bd;
90 int i;
91
92 debug("%s: bank: %d\n", __func__, bank);
Alexander Grafd990f5c2016-03-16 15:41:21 +010093 for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;
94 i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +
95 (bd->bi_dram[bank].size >> MMU_SECTION_SHIFT);
Heiko Schocherf1d2b312010-09-17 13:10:39 +020096 i++) {
Simon Glass0dde7f52012-10-17 13:24:53 +000097#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
98 set_section_dcache(i, DCACHE_WRITETHROUGH);
Marek Vasutff7e9702014-09-15 02:44:36 +020099#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
100 set_section_dcache(i, DCACHE_WRITEALLOC);
Simon Glass0dde7f52012-10-17 13:24:53 +0000101#else
102 set_section_dcache(i, DCACHE_WRITEBACK);
103#endif
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200104 }
105}
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200106
107/* to activate the MMU we need to set up virtual memory: use 1M areas */
Heiko Schocher880eff52010-09-17 13:10:29 +0200108static inline void mmu_setup(void)
109{
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200110 int i;
Heiko Schocher880eff52010-09-17 13:10:29 +0200111 u32 reg;
112
Aneesh Vc2dd0d42011-06-16 23:30:49 +0000113 arm_init_before_mmu();
Heiko Schocher880eff52010-09-17 13:10:29 +0200114 /* Set up an identity-mapping for all 4GB, rw for everyone */
Alexander Grafd990f5c2016-03-16 15:41:21 +0100115 for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++)
Simon Glass0dde7f52012-10-17 13:24:53 +0000116 set_section_dcache(i, DCACHE_OFF);
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200117
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200118 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
119 dram_bank_mmu_setup(i);
120 }
Heiko Schocher880eff52010-09-17 13:10:29 +0200121
Simon Glass10d602a2017-05-31 17:57:13 -0600122#if defined(CONFIG_ARMV7_LPAE) && __LINUX_ARM_ARCH__ != 4
Alexander Grafd990f5c2016-03-16 15:41:21 +0100123 /* Set up 4 PTE entries pointing to our 4 1GB page tables */
124 for (i = 0; i < 4; i++) {
125 u64 *page_table = (u64 *)(gd->arch.tlb_addr + (4096 * 4));
126 u64 tpt = gd->arch.tlb_addr + (4096 * i);
127 page_table[i] = tpt | TTB_PAGETABLE;
128 }
129
130 reg = TTBCR_EAE;
131#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
132 reg |= TTBCR_ORGN0_WT | TTBCR_IRGN0_WT;
133#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
134 reg |= TTBCR_ORGN0_WBWA | TTBCR_IRGN0_WBWA;
135#else
136 reg |= TTBCR_ORGN0_WBNWA | TTBCR_IRGN0_WBNWA;
137#endif
138
139 if (is_hyp()) {
Simon Glass579dfca2017-05-31 17:57:12 -0600140 /* Set HTCR to enable LPAE */
Alexander Grafd990f5c2016-03-16 15:41:21 +0100141 asm volatile("mcr p15, 4, %0, c2, c0, 2"
142 : : "r" (reg) : "memory");
143 /* Set HTTBR0 */
144 asm volatile("mcrr p15, 4, %0, %1, c2"
145 :
146 : "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
147 : "memory");
148 /* Set HMAIR */
149 asm volatile("mcr p15, 4, %0, c10, c2, 0"
150 : : "r" (MEMORY_ATTRIBUTES) : "memory");
151 } else {
152 /* Set TTBCR to enable LPAE */
153 asm volatile("mcr p15, 0, %0, c2, c0, 2"
154 : : "r" (reg) : "memory");
155 /* Set 64-bit TTBR0 */
156 asm volatile("mcrr p15, 0, %0, %1, c2"
157 :
158 : "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
159 : "memory");
160 /* Set MAIR */
161 asm volatile("mcr p15, 0, %0, c10, c2, 0"
162 : : "r" (MEMORY_ATTRIBUTES) : "memory");
163 }
164#elif defined(CONFIG_CPU_V7)
Simon Glass50a48862017-05-31 17:57:14 -0600165 if (is_hyp()) {
166 /* Set HTCR to disable LPAE */
167 asm volatile("mcr p15, 4, %0, c2, c0, 2"
168 : : "r" (0) : "memory");
169 } else {
170 /* Set TTBCR to disable LPAE */
171 asm volatile("mcr p15, 0, %0, c2, c0, 2"
172 : : "r" (0) : "memory");
173 }
Bryan Brinsko97840b52015-03-24 11:25:12 -0500174 /* Set TTBR0 */
175 reg = gd->arch.tlb_addr & TTBR0_BASE_ADDR_MASK;
176#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
177 reg |= TTBR0_RGN_WT | TTBR0_IRGN_WT;
178#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
179 reg |= TTBR0_RGN_WBWA | TTBR0_IRGN_WBWA;
180#else
181 reg |= TTBR0_RGN_WB | TTBR0_IRGN_WB;
182#endif
183 asm volatile("mcr p15, 0, %0, c2, c0, 0"
184 : : "r" (reg) : "memory");
185#else
Heiko Schocher880eff52010-09-17 13:10:29 +0200186 /* Copy the page table address to cp15 */
187 asm volatile("mcr p15, 0, %0, c2, c0, 0"
Simon Glass34fd5d22012-12-13 20:48:39 +0000188 : : "r" (gd->arch.tlb_addr) : "memory");
Bryan Brinsko97840b52015-03-24 11:25:12 -0500189#endif
Heiko Schocher880eff52010-09-17 13:10:29 +0200190 /* Set the access control to all-supervisor */
191 asm volatile("mcr p15, 0, %0, c3, c0, 0"
192 : : "r" (~0));
R Sricharande63ac22013-03-04 20:04:45 +0000193
194 arm_init_domains();
195
Heiko Schocher880eff52010-09-17 13:10:29 +0200196 /* and enable the mmu */
197 reg = get_cr(); /* get control reg. */
Heiko Schocher880eff52010-09-17 13:10:29 +0200198 set_cr(reg | CR_M);
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200199}
200
Aneesh Ve05f0072011-06-16 23:30:50 +0000201static int mmu_enabled(void)
202{
203 return get_cr() & CR_M;
204}
205
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200206/* cache_bit must be either CR_I or CR_C */
207static void cache_enable(uint32_t cache_bit)
208{
209 uint32_t reg;
210
Heiko Schocher880eff52010-09-17 13:10:29 +0200211 /* The data cache is not active unless the mmu is enabled too */
Aneesh Ve05f0072011-06-16 23:30:50 +0000212 if ((cache_bit == CR_C) && !mmu_enabled())
Heiko Schocher880eff52010-09-17 13:10:29 +0200213 mmu_setup();
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200214 reg = get_cr(); /* get control reg. */
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200215 set_cr(reg | cache_bit);
216}
217
218/* cache_bit must be either CR_I or CR_C */
219static void cache_disable(uint32_t cache_bit)
220{
221 uint32_t reg;
222
SRICHARAN Rd702b082012-05-16 23:52:54 +0000223 reg = get_cr();
SRICHARAN Rd702b082012-05-16 23:52:54 +0000224
Heiko Schocher880eff52010-09-17 13:10:29 +0200225 if (cache_bit == CR_C) {
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200226 /* if cache isn;t enabled no need to disable */
Heiko Schocherf1d2b312010-09-17 13:10:39 +0200227 if ((reg & CR_C) != CR_C)
228 return;
Heiko Schocher880eff52010-09-17 13:10:29 +0200229 /* if disabling data cache, disable mmu too */
230 cache_bit |= CR_M;
Heiko Schocher880eff52010-09-17 13:10:29 +0200231 }
Arun Mankuzhi44df5e82012-11-30 13:01:14 +0000232 reg = get_cr();
Lothar Waßmann53d4ed72017-06-08 09:48:41 +0200233
Arun Mankuzhi44df5e82012-11-30 13:01:14 +0000234 if (cache_bit == (CR_C | CR_M))
235 flush_dcache_all();
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200236 set_cr(reg & ~cache_bit);
237}
238#endif
239
Aneesh Ve47f2db2011-06-16 23:30:48 +0000240#ifdef CONFIG_SYS_ICACHE_OFF
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200241void icache_enable (void)
242{
243 return;
244}
245
246void icache_disable (void)
247{
248 return;
249}
250
251int icache_status (void)
252{
253 return 0; /* always off */
254}
255#else
256void icache_enable(void)
257{
258 cache_enable(CR_I);
259}
260
261void icache_disable(void)
262{
263 cache_disable(CR_I);
264}
265
266int icache_status(void)
267{
268 return (get_cr() & CR_I) != 0;
269}
270#endif
271
Aneesh Ve47f2db2011-06-16 23:30:48 +0000272#ifdef CONFIG_SYS_DCACHE_OFF
Jean-Christophe PLAGNIOL-VILLARDb3acb6c2009-04-05 13:06:31 +0200273void dcache_enable (void)
274{
275 return;
276}
277
278void dcache_disable (void)
279{
280 return;
281}
282
283int dcache_status (void)
284{
285 return 0; /* always off */
286}
287#else
288void dcache_enable(void)
289{
290 cache_enable(CR_C);
291}
292
293void dcache_disable(void)
294{
295 cache_disable(CR_C);
296}
297
298int dcache_status(void)
299{
300 return (get_cr() & CR_C) != 0;
301}
302#endif