blob: 947012f29963d0663b02b77c348a17098df6fd77 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +02002/*
3 * (C) Copyright 2002
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +02005 */
6
Simon Glass1d91ba72019-11-14 12:57:37 -07007#include <cpu_func.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <asm/global_data.h>
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +020010#include <asm/system.h>
R Sricharan08716072013-03-04 20:04:44 +000011#include <asm/cache.h>
12#include <linux/compiler.h>
Lokesh Vutla19858f92018-04-26 18:21:31 +053013#include <asm/armv7_mpu.h>
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +020014
Trevor Woerner43ec7e02019-05-03 09:41:00 -040015#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
Heiko Schocher69f1d0c2010-09-17 13:10:29 +020016
Heiko Schocher69f1d0c2010-09-17 13:10:29 +020017DECLARE_GLOBAL_DATA_PTR;
18
Lokesh Vutla19858f92018-04-26 18:21:31 +053019#ifdef CONFIG_SYS_ARM_MMU
Jeroen Hofsteed7460772014-06-23 22:07:04 +020020__weak void arm_init_before_mmu(void)
Aneesh V3e3bc1e2011-06-16 23:30:49 +000021{
22}
Aneesh V3e3bc1e2011-06-16 23:30:49 +000023
Marek Szyprowskif76fb512020-06-03 14:43:42 +020024static void set_section_phys(int section, phys_addr_t phys,
25 enum dcache_option option)
Heiko Schocheraeb29912010-09-17 13:10:39 +020026{
Alexander Grafae6c2bc2016-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 Glass6b4ee152012-12-13 20:48:39 +000032 u32 *page_table = (u32 *)gd->arch.tlb_addr;
Alexander Grafae6c2bc2016-03-16 15:41:21 +010033 u32 value = TTB_SECT_AP;
34#endif
35
36 /* Add the page offset */
Marek Szyprowskif76fb512020-06-03 14:43:42 +020037 value |= phys;
Simon Glassa4f20792012-10-17 13:24:53 +000038
Alexander Grafae6c2bc2016-03-16 15:41:21 +010039 /* Add caching bits */
Simon Glassa4f20792012-10-17 13:24:53 +000040 value |= option;
Alexander Grafae6c2bc2016-03-16 15:41:21 +010041
42 /* Set PTE */
Simon Glassa4f20792012-10-17 13:24:53 +000043 page_table[section] = value;
44}
45
Marek Szyprowskif76fb512020-06-03 14:43:42 +020046void set_section_dcache(int section, enum dcache_option option)
47{
48 set_section_phys(section, (u32)section << MMU_SECTION_SHIFT, option);
49}
50
Jeroen Hofsteed7460772014-06-23 22:07:04 +020051__weak void mmu_page_table_flush(unsigned long start, unsigned long stop)
Simon Glassa4f20792012-10-17 13:24:53 +000052{
53 debug("%s: Warning: not implemented\n", __func__);
54}
55
Marek Szyprowskif76fb512020-06-03 14:43:42 +020056void mmu_set_region_dcache_behaviour_phys(phys_addr_t start, phys_addr_t phys,
57 size_t size, enum dcache_option option)
Simon Glassa4f20792012-10-17 13:24:53 +000058{
Stefan Agnerc4a73222016-08-14 21:33:00 -070059#ifdef CONFIG_ARMV7_LPAE
60 u64 *page_table = (u64 *)gd->arch.tlb_addr;
61#else
Simon Glass6b4ee152012-12-13 20:48:39 +000062 u32 *page_table = (u32 *)gd->arch.tlb_addr;
Stefan Agnerc4a73222016-08-14 21:33:00 -070063#endif
Stefan Agnerbae14802016-08-14 21:33:01 -070064 unsigned long startpt, stoppt;
Thierry Redingfe2007152014-08-26 17:34:21 +020065 unsigned long upto, end;
Simon Glassa4f20792012-10-17 13:24:53 +000066
Patrick Delaunay594b7cf2020-04-24 20:20:17 +020067 /* div by 2 before start + size to avoid phys_addr_t overflow */
68 end = ALIGN((start / 2) + (size / 2), MMU_SECTION_SIZE / 2)
69 >> (MMU_SECTION_SHIFT - 1);
Simon Glassa4f20792012-10-17 13:24:53 +000070 start = start >> MMU_SECTION_SHIFT;
Patrick Delaunay594b7cf2020-04-24 20:20:17 +020071
Keerthy266c8c12016-10-29 15:19:10 +053072#ifdef CONFIG_ARMV7_LPAE
73 debug("%s: start=%pa, size=%zu, option=%llx\n", __func__, &start, size,
74 option);
75#else
Keerthy485110a2016-10-29 15:19:09 +053076 debug("%s: start=%pa, size=%zu, option=0x%x\n", __func__, &start, size,
Simon Glassa4f20792012-10-17 13:24:53 +000077 option);
Keerthy266c8c12016-10-29 15:19:10 +053078#endif
Marek Szyprowskif76fb512020-06-03 14:43:42 +020079 for (upto = start; upto < end; upto++, phys += MMU_SECTION_SIZE)
80 set_section_phys(upto, phys, option);
Stefan Agnerbae14802016-08-14 21:33:01 -070081
82 /*
83 * Make sure range is cache line aligned
84 * Only CPU maintains page tables, hence it is safe to always
85 * flush complete cache lines...
86 */
87
88 startpt = (unsigned long)&page_table[start];
89 startpt &= ~(CONFIG_SYS_CACHELINE_SIZE - 1);
90 stoppt = (unsigned long)&page_table[end];
91 stoppt = ALIGN(stoppt, CONFIG_SYS_CACHELINE_SIZE);
92 mmu_page_table_flush(startpt, stoppt);
Simon Glassa4f20792012-10-17 13:24:53 +000093}
94
R Sricharan08716072013-03-04 20:04:44 +000095__weak void dram_bank_mmu_setup(int bank)
Simon Glassa4f20792012-10-17 13:24:53 +000096{
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +090097 struct bd_info *bd = gd->bd;
Heiko Schocheraeb29912010-09-17 13:10:39 +020098 int i;
99
Patrick Delaunay77cc8b22020-04-24 20:20:15 +0200100 /* bd->bi_dram is available only after relocation */
101 if ((gd->flags & GD_FLG_RELOC) == 0)
102 return;
103
Heiko Schocheraeb29912010-09-17 13:10:39 +0200104 debug("%s: bank: %d\n", __func__, bank);
Alexander Grafae6c2bc2016-03-16 15:41:21 +0100105 for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;
106 i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +
107 (bd->bi_dram[bank].size >> MMU_SECTION_SHIFT);
Patrick Delaunayd7e6a1d2020-04-24 20:20:16 +0200108 i++)
109 set_section_dcache(i, DCACHE_DEFAULT_OPTION);
Heiko Schocheraeb29912010-09-17 13:10:39 +0200110}
Heiko Schocheraeb29912010-09-17 13:10:39 +0200111
112/* to activate the MMU we need to set up virtual memory: use 1M areas */
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200113static inline void mmu_setup(void)
114{
Heiko Schocheraeb29912010-09-17 13:10:39 +0200115 int i;
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200116 u32 reg;
117
Aneesh V3e3bc1e2011-06-16 23:30:49 +0000118 arm_init_before_mmu();
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200119 /* Set up an identity-mapping for all 4GB, rw for everyone */
Alexander Grafae6c2bc2016-03-16 15:41:21 +0100120 for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++)
Simon Glassa4f20792012-10-17 13:24:53 +0000121 set_section_dcache(i, DCACHE_OFF);
Heiko Schocheraeb29912010-09-17 13:10:39 +0200122
Heiko Schocheraeb29912010-09-17 13:10:39 +0200123 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
124 dram_bank_mmu_setup(i);
125 }
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200126
Simon Glass5bfd41d2017-05-31 17:57:13 -0600127#if defined(CONFIG_ARMV7_LPAE) && __LINUX_ARM_ARCH__ != 4
Alexander Grafae6c2bc2016-03-16 15:41:21 +0100128 /* Set up 4 PTE entries pointing to our 4 1GB page tables */
129 for (i = 0; i < 4; i++) {
130 u64 *page_table = (u64 *)(gd->arch.tlb_addr + (4096 * 4));
131 u64 tpt = gd->arch.tlb_addr + (4096 * i);
132 page_table[i] = tpt | TTB_PAGETABLE;
133 }
134
135 reg = TTBCR_EAE;
136#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
137 reg |= TTBCR_ORGN0_WT | TTBCR_IRGN0_WT;
138#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
139 reg |= TTBCR_ORGN0_WBWA | TTBCR_IRGN0_WBWA;
140#else
141 reg |= TTBCR_ORGN0_WBNWA | TTBCR_IRGN0_WBNWA;
142#endif
143
144 if (is_hyp()) {
Simon Glass3b372472017-05-31 17:57:12 -0600145 /* Set HTCR to enable LPAE */
Alexander Grafae6c2bc2016-03-16 15:41:21 +0100146 asm volatile("mcr p15, 4, %0, c2, c0, 2"
147 : : "r" (reg) : "memory");
148 /* Set HTTBR0 */
149 asm volatile("mcrr p15, 4, %0, %1, c2"
150 :
151 : "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
152 : "memory");
153 /* Set HMAIR */
154 asm volatile("mcr p15, 4, %0, c10, c2, 0"
155 : : "r" (MEMORY_ATTRIBUTES) : "memory");
156 } else {
157 /* Set TTBCR to enable LPAE */
158 asm volatile("mcr p15, 0, %0, c2, c0, 2"
159 : : "r" (reg) : "memory");
160 /* Set 64-bit TTBR0 */
161 asm volatile("mcrr p15, 0, %0, %1, c2"
162 :
163 : "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
164 : "memory");
165 /* Set MAIR */
166 asm volatile("mcr p15, 0, %0, c10, c2, 0"
167 : : "r" (MEMORY_ATTRIBUTES) : "memory");
168 }
Lokesh Vutla81b1a672018-04-26 18:21:26 +0530169#elif defined(CONFIG_CPU_V7A)
Simon Glass1375e582017-05-31 17:57:14 -0600170 if (is_hyp()) {
171 /* Set HTCR to disable LPAE */
172 asm volatile("mcr p15, 4, %0, c2, c0, 2"
173 : : "r" (0) : "memory");
174 } else {
175 /* Set TTBCR to disable LPAE */
176 asm volatile("mcr p15, 0, %0, c2, c0, 2"
177 : : "r" (0) : "memory");
178 }
Bryan Brinsko29d23ec2015-03-24 11:25:12 -0500179 /* Set TTBR0 */
180 reg = gd->arch.tlb_addr & TTBR0_BASE_ADDR_MASK;
181#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
182 reg |= TTBR0_RGN_WT | TTBR0_IRGN_WT;
183#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
184 reg |= TTBR0_RGN_WBWA | TTBR0_IRGN_WBWA;
185#else
186 reg |= TTBR0_RGN_WB | TTBR0_IRGN_WB;
187#endif
188 asm volatile("mcr p15, 0, %0, c2, c0, 0"
189 : : "r" (reg) : "memory");
190#else
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200191 /* Copy the page table address to cp15 */
192 asm volatile("mcr p15, 0, %0, c2, c0, 0"
Simon Glass6b4ee152012-12-13 20:48:39 +0000193 : : "r" (gd->arch.tlb_addr) : "memory");
Bryan Brinsko29d23ec2015-03-24 11:25:12 -0500194#endif
Patrick Delaunay4aae24d2021-02-05 13:53:36 +0100195 /*
196 * initial value of Domain Access Control Register (DACR)
197 * Set the access control to client (1U) for each of the 16 domains
198 */
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200199 asm volatile("mcr p15, 0, %0, c3, c0, 0"
Patrick Delaunay4aae24d2021-02-05 13:53:36 +0100200 : : "r" (0x55555555));
R Sricharan06396c12013-03-04 20:04:45 +0000201
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200202 /* and enable the mmu */
203 reg = get_cr(); /* get control reg. */
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200204 set_cr(reg | CR_M);
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200205}
206
Aneesh V3bda3772011-06-16 23:30:50 +0000207static int mmu_enabled(void)
208{
209 return get_cr() & CR_M;
210}
Lokesh Vutla19858f92018-04-26 18:21:31 +0530211#endif /* CONFIG_SYS_ARM_MMU */
Aneesh V3bda3772011-06-16 23:30:50 +0000212
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200213/* cache_bit must be either CR_I or CR_C */
214static void cache_enable(uint32_t cache_bit)
215{
216 uint32_t reg;
217
Lokesh Vutla19858f92018-04-26 18:21:31 +0530218 /* The data cache is not active unless the mmu/mpu is enabled too */
219#ifdef CONFIG_SYS_ARM_MMU
Aneesh V3bda3772011-06-16 23:30:50 +0000220 if ((cache_bit == CR_C) && !mmu_enabled())
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200221 mmu_setup();
Lokesh Vutla19858f92018-04-26 18:21:31 +0530222#elif defined(CONFIG_SYS_ARM_MPU)
223 if ((cache_bit == CR_C) && !mpu_enabled()) {
224 printf("Consider enabling MPU before enabling caches\n");
225 return;
226 }
227#endif
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200228 reg = get_cr(); /* get control reg. */
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200229 set_cr(reg | cache_bit);
230}
231
232/* cache_bit must be either CR_I or CR_C */
233static void cache_disable(uint32_t cache_bit)
234{
235 uint32_t reg;
236
SRICHARAN R88f4bf22012-05-16 23:52:54 +0000237 reg = get_cr();
SRICHARAN R88f4bf22012-05-16 23:52:54 +0000238
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200239 if (cache_bit == CR_C) {
Heiko Schocheraeb29912010-09-17 13:10:39 +0200240 /* if cache isn;t enabled no need to disable */
Heiko Schocheraeb29912010-09-17 13:10:39 +0200241 if ((reg & CR_C) != CR_C)
242 return;
Lokesh Vutla9ac1d172019-10-30 15:55:41 +0530243#ifdef CONFIG_SYS_ARM_MMU
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200244 /* if disabling data cache, disable mmu too */
245 cache_bit |= CR_M;
Lokesh Vutla9ac1d172019-10-30 15:55:41 +0530246#endif
Heiko Schocher69f1d0c2010-09-17 13:10:29 +0200247 }
Arun Mankuzhi7a7825f2012-11-30 13:01:14 +0000248 reg = get_cr();
Lothar Waßmannbded0c82017-06-08 09:48:41 +0200249
Lokesh Vutla9ac1d172019-10-30 15:55:41 +0530250#ifdef CONFIG_SYS_ARM_MMU
Arun Mankuzhi7a7825f2012-11-30 13:01:14 +0000251 if (cache_bit == (CR_C | CR_M))
Lokesh Vutla9ac1d172019-10-30 15:55:41 +0530252#elif defined(CONFIG_SYS_ARM_MPU)
253 if (cache_bit == CR_C)
254#endif
Arun Mankuzhi7a7825f2012-11-30 13:01:14 +0000255 flush_dcache_all();
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200256 set_cr(reg & ~cache_bit);
257}
258#endif
259
Trevor Woerner43ec7e02019-05-03 09:41:00 -0400260#if CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
Simon Glassfbf091b2019-11-14 12:57:36 -0700261void icache_enable(void)
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200262{
263 return;
264}
265
Simon Glassfbf091b2019-11-14 12:57:36 -0700266void icache_disable(void)
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200267{
268 return;
269}
270
Simon Glassfbf091b2019-11-14 12:57:36 -0700271int icache_status(void)
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200272{
273 return 0; /* always off */
274}
275#else
276void icache_enable(void)
277{
278 cache_enable(CR_I);
279}
280
281void icache_disable(void)
282{
283 cache_disable(CR_I);
284}
285
286int icache_status(void)
287{
288 return (get_cr() & CR_I) != 0;
289}
290#endif
291
Trevor Woerner43ec7e02019-05-03 09:41:00 -0400292#if CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
Simon Glassfbf091b2019-11-14 12:57:36 -0700293void dcache_enable(void)
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200294{
295 return;
296}
297
Simon Glassfbf091b2019-11-14 12:57:36 -0700298void dcache_disable(void)
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200299{
300 return;
301}
302
Simon Glassfbf091b2019-11-14 12:57:36 -0700303int dcache_status(void)
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200304{
305 return 0; /* always off */
306}
Patrice Chotard28522a62021-02-24 13:48:42 +0100307
308void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
309 enum dcache_option option)
310{
311}
312
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200313#else
314void dcache_enable(void)
315{
316 cache_enable(CR_C);
317}
318
319void dcache_disable(void)
320{
321 cache_disable(CR_C);
322}
323
324int dcache_status(void)
325{
326 return (get_cr() & CR_C) != 0;
327}
Patrice Chotard28522a62021-02-24 13:48:42 +0100328
329void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
330 enum dcache_option option)
331{
332 mmu_set_region_dcache_behaviour_phys(start, start, size, option);
333}
Jean-Christophe PLAGNIOL-VILLARDe6b5f1b2009-04-05 13:06:31 +0200334#endif