forked from esp8266/Arduino
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmmu_iram.cpp
241 lines (216 loc) · 8.66 KB
/
mmu_iram.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/*
* Copyright 2020 M Hightower
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Arduino.h"
#include "mmu_iram.h"
#include <user_interface.h>
#define ICACHE_SIZE_32 1
#define ICACHE_SIZE_16 0
extern "C" {
#if (MMU_ICACHE_SIZE == 0x4000)
#define SOC_CACHE_SIZE ICACHE_SIZE_16
#pragma message("ICACHE size 16K")
#else
#define SOC_CACHE_SIZE ICACHE_SIZE_32
#endif
#if (MMU_ICACHE_SIZE == 0x4000)
/*
* "Cache_Read_Enable" as in Instruction Read Cache enable, ICACHE.
*
* The Boot ROM "Cache_Read_Enable" API enables virtual execution of code in
* flash memory via an instruction cache, ICACHE. The cache size can be set to
* 16K or 32K, and the NONOS SDK 2.x will always set ICACHE to 32K during
* initialization.
*
* When you select a 16K vs. a 32K ICACHE size, you get 48K contiguous IRAM to
* work with. The NONOS SDK 2.x does not have an option to select 16K/32K. This
* is where this Boot ROM wrapper for Cache_Read_Enable comes in.
* Note, there is support for 16K/32K cache size in NONOS SDK 3.0; however, I
* do not see an option to have it has part of your general IRAM. That SDK adds
* it to the heap.
*
* With this wrapper function, we override the SDK's ICACHE size.
* A build-time define MMU_ICACHE_SIZE selects 16K or 32K ICACHE size.
*
* mmu_status is used to help understand calling behavior. At some point, it
* should be trimmed down to the essentials.
*
* During NONOS SDK init, it will call to enable. Then call later, to process a
* spi_flash_get_id request, it will disable/enable around the Boot ROM SPI calls.
*
*
*
* Arguments for Cache_Read_Enable
*
* The first two arguments appear to specify which 1MB block of the flash to
* access with the ICACHE.
*
* The first argument, map, is partly understood. It has three values 0, 1,
* and 2+. The value 0 selects the even 1MB block, and 1 selects the odd 1MB
* block, in other words, bit20 of the flash address. No guesses for a value
* of 2 or greater.
*
* The second argument, p, bit 21 of the flash address. Or, it may be bits 23,
* 22, 21 of the flash address. A three-bit field is cleared in the register
* for this argument; however, I have not seen any examples of it being used
* that way.
*
* The third argument, v, holds our center of attention. A value of 0 selects
* 16K, and a value of 1 selects a 32K ICACHE. This is the only parameter we
* need to modify on Cache_Read_Enable calls.
*
*
*
* Clues and Information sources
*
* "Cache_Read_Enable" is underdocumented. Main sources of information were from
* rboot, zboot, https://richard.burtons.org/2015/06/12/esp8266-cache_read_enable/,
* and other places. And some additional experimentation.
*
* Searching through the NONOS SDK shows nothing on this API; however, some
* clues on what the NONOS SDK might be doing with ICACHE related calls can be
* found in the RTOS SDK.
* eg. ESP8266_RTOS_SDK/blob/master/components/spi_flash/src/spi_flash_raw.c
* also calls to it in the bootloader.
*
*/
#ifndef ROM_Cache_Read_Enable
#define ROM_Cache_Read_Enable 0x40004678U
#endif
typedef void (*fp_Cache_Read_Enable_t)(uint8_t map, uint8_t p, uint8_t v);
#define real_Cache_Read_Enable (reinterpret_cast<fp_Cache_Read_Enable_t>(ROM_Cache_Read_Enable))
void IRAM_ATTR Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v) {
(void)v;
real_Cache_Read_Enable(map, p, SOC_CACHE_SIZE);
}
#ifdef DEV_DEBUG_PRINT
#if 0
#ifndef ROM_Cache_Read_Disable
#define ROM_Cache_Read_Disable 0x400047f0
#endif
typedef void (*fp_Cache_Read_Disable_t)(void);
#define real_Cache_Read_Disable (reinterpret_cast<fp_Cache_Read_Disable_t>(ROM_Cache_Read_Disable))
/*
*
*/
void IRAM_ATTR Cache_Read_Disable(void) {
real_Cache_Read_Disable();
}
#endif
//C This was used to probe at different stages of boot the state of the PLL
//C register. I think we can get rid of this one.
extern "C" uint8_t rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add);
extern "C" void rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
extern "C" void IRAM_ATTR dbg_set_pll(void)
{
char r103_4_1 = rom_i2c_readReg(103,4,1);
char r103_4_2 = rom_i2c_readReg(103,4,2);
mmu_set_pll();
ets_uart_printf("\nrom_i2c_readReg(103,4,1) == %u\n", r103_4_1);
ets_uart_printf( "rom_i2c_readReg(103,4,2) == %u\n", r103_4_2);
}
/*
This helps keep the UART enabled at user_init() so we can get a few more
messages printed.
*/
extern struct rst_info resetInfo;
extern "C" void __pinMode( uint8_t pin, uint8_t mode );
inline bool is_gpio_persistent(void) {
return REASON_EXCEPTION_RST <= resetInfo.reason &&
REASON_SOFT_RESTART >= resetInfo.reason;
}
extern "C" void pinMode( uint8_t pin, uint8_t mode ) {
static bool in_initPins = true;
if (in_initPins && (1 == pin)) {
if (!is_gpio_persistent()) {
/* Restore pin to TX after Power-on and EXT_RST */
__pinMode(pin, FUNCTION_0);
}
in_initPins = false;
return;
}
__pinMode( pin, mode );
}
#else // #ifdef DEV_DEBUG_PRINT
extern void Cache_Read_Disable(void);
#endif // #ifdef DEV_DEBUG_PRINT
#else // #if (MMU_ICACHE_SIZE == 0x4000)
extern void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v);
#endif // #if (MMU_ICACHE_SIZE == 0x4000)
/*
* Early adjustment for CPU crystal frequency will allow early debug printing to
* be readable before the SDK initialization is complete.
* This should not be left enabled all the time in Cashe_Read..., I am concerned
* that there may be unknown interference with the NONOS SDK startup.
* It does low-level calls that could clash with the SDKs startup.
*
* Inspired by:
* https://github.com/pvvx/esp8266web/blob/2e25559bc489487747205db2ef171d48326b32d4/app/sdklib/system/app_main.c#L581-L591
*/
extern "C" uint8_t rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add);
extern "C" void rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
extern "C" void IRAM_ATTR mmu_set_pll(void)
{
#if !defined(F_CRYSTAL)
#define F_CRYSTAL 26000000
#endif
if (F_CRYSTAL != 40000000) {
// At Boot ROM(-BIOS) start, it assumes a 40MHz crystal.
// If it is not, we assume a 26MHz crystal.
// There is no support for 24MHz crustal at this time.
if(rom_i2c_readReg(103,4,1) != 136) { // 8: 40MHz, 136: 26MHz
// Assume 26MHz crystal
// soc_param0: 0: 40MHz, 1: 26MHz, 2: 24MHz
// set 80MHz PLL CPU
rom_i2c_writeReg(103,4,1,136);
rom_i2c_writeReg(103,4,2,145);
}
}
}
/*
* This wrapper is for running code early from IROM (flash) before the SDK
* starts. Since the NONOS SDK will do a full and proper flash device init for
* speed and mode, we only do a minimum to make ICACHE functional, keeping IRAM
* use to a minimum. After the SDK has started, this function is not needed and
* must not be called.
*/
void IRAM_ATTR mmu_wrap_irom_fn(void (*fn)(void)) {
// Cache Read must be disabled. This is always the case on entry when called
// from the right context.
// Cache_Read_Disable();
// The SPI_CS_SETUP parameter has been observed set by RTOS SDK and NONOS SDK
// as part of flash init/configuration. It may be necessary for some flash
// chips to perform correctly with ICACHE hardware access. Turning on and
// leaving it on should be okay.
//
// One SPI bus clock cycle time is inserted between #CS active and 1st SPI bus
// clock cycle. The number of clock cycles is in SPI_CNTRL2 SPI_SETUP_TIME,
// defaults to 1.
SPI0U |= SPIUCSSETUP; // SPI_CS_SETUP or BIT5
// phy_get_bb_evm is the key function, called from fix_cache_bug in the NONOS
// SDK. This addition resolves the PUYA Flash issue with exception 0, when
// early Cache_Read_Enable is used.
extern uint32_t phy_get_bb_evm(void); // undocumented
phy_get_bb_evm();
// For early Cache_Read_Enable, only do ICACHE_SIZE_16. With this option,
// Cache_Read_Disable will fully restore the original register states. With
// ICACHE_SIZE_32, one bit is missed when disabling. Leave the full access
// calls for the NONOS SDK.
// This only works with image slice 0, which is all we do presently.
Cache_Read_Enable(0, 0, ICACHE_SIZE_16);
fn();
Cache_Read_Disable();
}
};