1 /*
2  * SPDX-FileCopyrightText: 2010-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include "soc/soc.h"
9 #include "soc/dport_reg.h"
10 #include "esp_attr.h"
11 #include "string.h"
12 #include "esp_private/spi_flash_os.h"
13 #include "esp_private/cache_utils.h"
14 #include "spi_flash_mmap.h"
15 
16 //Errors that can be returned
17 #define MMU_SET_ADDR_ALIGNED_ERROR 1
18 #define MMU_SET_PAGE_SIZE_ERROR 3
19 #define MMU_SET_VADDR_OUT_RANGE 5
20 
21 
22 #define PROCACHE_MMU_ADDR_BASE 0x3FF10000
23 #define APPCACHE_MMU_ADDR_BASE 0x3FF12000
24 
25 
26 //sram
27 #define PRO_DRAM1_START_ADDR   0x3F800000
28 #define PRO_DRAM1_END_ADDR(psize)     (PRO_DRAM1_START_ADDR + ((psize) << 17))
29 //cache mmu register file address
30 #define CACHE_MMU_ADDRESS_BASE(cpu_no) ((cpu_no) ? (APPCACHE_MMU_ADDR_BASE) : (PROCACHE_MMU_ADDR_BASE))
31 //virtual address, physical address check
32 #define ADDRESS_CHECK(addr,psize) (((addr) & (0xFFFF >>((64/(psize))-1))) != 0)
33 //CPU number check
34 #define CPU_NUMBER_CHECK(cpu_no)  (((cpu_no)<0) || ((cpu_no)>1))
35 //PID check
36 #define PID_CHECK(pid)  (((pid)<0) || ((pid)>7))
37 //flash MMU edge check (flash size default : 16*1024 K)
38 #define FLASH_MMU_EDGE_CHECK(mmu_val,num) (((mmu_val) + (num)) > 256)
39 //sram MMU edge check (sram size default : 8*1024 K)
40 #define SRAM_MMU_EDGE_CHECK(mmu_val,num,psize) (((mmu_val) + (num)) > ((8*1024)/(psize)))
41 
42 //We can relegate to the ROM version if the 2nd core isn't running (yet) and the RTOS is not started yet, for instance
43 //in the bootloader and in the app start process. The ROM code manually disables the cache, without using
44 //cache guards.
45 unsigned int cache_sram_mmu_set_rom(int cpu_no, int pid, unsigned int vaddr, unsigned int paddr, int psize, int num);
46 
47 
48 #ifndef BOOTLOADER_BUILD
49 
50 /*
51 Note that this function is a replacement for the ROM function with the same name, with these differences:
52 - It uses the DPORT workarounds
53 - It fixes a bug where the ROM version throws an error when vaddr is more than 2MiB into the memory region
54 - It uses the SPI cache guards to make sure the MMU is idle
55 */
cache_sram_mmu_set(int cpu_no,int pid,unsigned int vaddr,unsigned int paddr,int psize,int num)56 unsigned int IRAM_ATTR cache_sram_mmu_set(int cpu_no, int pid, unsigned int vaddr, unsigned int paddr, int psize, int num)
57 {
58     const spi_flash_guard_funcs_t *guard=spi_flash_guard_get();
59     if (!guard) {
60         //Still starting up; guards not available yet. Use ROM version of code.
61         return cache_sram_mmu_set_rom(cpu_no, pid, vaddr, paddr, psize, num);
62     }
63 
64     unsigned int i,shift,mask_s;
65     unsigned int mmu_addr;
66     unsigned int mmu_table_val;
67     //address check
68     if( (ADDRESS_CHECK(vaddr,psize)) || (ADDRESS_CHECK(paddr,psize)) ){
69         return MMU_SET_ADDR_ALIGNED_ERROR;
70     }
71     //psize check
72     if(psize == 32) {
73         shift  = 15;
74         mask_s = 0;
75     } else if(psize == 16) {
76         shift  = 14;
77         mask_s = 1;
78     } else if(psize == 8) {
79         shift  = 13;
80         mask_s = 2;
81     } else if(psize == 4) {
82         shift  = 12;
83         mask_s = 3;
84     } else if(psize == 2) {
85         shift  = 11;
86         mask_s = 4;
87     } else {
88         return MMU_SET_PAGE_SIZE_ERROR;
89     }
90     //mmu value
91     mmu_table_val = paddr >> shift;
92     //mmu_addr
93     if(pid == 0 || pid == 1){
94         if(vaddr >= PRO_DRAM1_START_ADDR && vaddr < PRO_DRAM1_END_ADDR(psize)){
95             mmu_addr = 1152 + ((vaddr & (0x3FFFFF >> mask_s)) >> shift);
96         } else{
97             return MMU_SET_VADDR_OUT_RANGE;
98         }
99     } else {
100         if(vaddr >= PRO_DRAM1_START_ADDR && vaddr < PRO_DRAM1_END_ADDR(psize)){
101             mmu_addr = (1024 + (pid<<7)) + ((vaddr & (0x3FFFFF >> mask_s)) >> shift);
102         } else{
103             return MMU_SET_VADDR_OUT_RANGE;
104         }
105     }
106 
107     //The MMU registers are implemented in such a way that lookups from the cache subsystem may collide with
108     //CPU access to the MMU registers. We use the flash guards to make sure the cache is disabled.
109     guard->start();
110 
111     //mmu change
112     for ( i = 0; i < num; i++){
113         *(volatile unsigned int *)(CACHE_MMU_ADDRESS_BASE(cpu_no) + mmu_addr * 4) = mmu_table_val + i; //write table
114         mmu_addr++;
115     }
116 
117     if(cpu_no == 0){
118         DPORT_REG_SET_FIELD(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CMMU_SRAM_PAGE_MODE, mask_s);
119     } else {
120         DPORT_REG_SET_FIELD(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CMMU_SRAM_PAGE_MODE, mask_s);
121     }
122 
123     guard->end();
124 
125     return 0;
126 }
127 
128 
129 #else
130 
131 //For the bootloader, we can always use the ROM version of this: it works well enough and keeps the size of the bootloader binary down.
cache_sram_mmu_set(int cpu_no,int pid,unsigned int vaddr,unsigned int paddr,int psize,int num)132 unsigned int cache_sram_mmu_set(int cpu_no, int pid, unsigned int vaddr, unsigned int paddr, int psize, int num) {
133     return cache_sram_mmu_set_rom(cpu_no, pid, vaddr, paddr, psize, num);
134 }
135 
136 #endif
137