1 /*
2 * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include "sdkconfig.h"
9 #include "string.h"
10 #include "esp_attr.h"
11 #include "esp_err.h"
12 #include "esp_types.h"
13 #include "esp_bit_defs.h"
14 #include "esp_log.h"
15 #include "../esp_psram_impl.h"
16 #include "esp32s3/rom/ets_sys.h"
17 #include "esp32s3/rom/spi_flash.h"
18 #include "esp32s3/rom/opi_flash.h"
19 #include "esp32s3/rom/cache.h"
20 #include "soc/gpio_periph.h"
21 #include "soc/io_mux_reg.h"
22 #include "soc/syscon_reg.h"
23 #include "esp_private/spi_flash_os.h"
24 #include "esp_private/mspi_timing_tuning.h"
25 #include "esp_private/esp_gpio_reserve.h"
26
27 #define OPI_PSRAM_SYNC_READ 0x0000
28 #define OPI_PSRAM_SYNC_WRITE 0x8080
29 #define OPI_PSRAM_REG_READ 0x4040
30 #define OPI_PSRAM_REG_WRITE 0xC0C0
31 #define OCT_PSRAM_RD_CMD_BITLEN 16
32 #define OCT_PSRAM_WR_CMD_BITLEN 16
33 #define OCT_PSRAM_ADDR_BITLEN 32
34 #define OCT_PSRAM_RD_DUMMY_BITLEN (2*(10-1))
35 #define OCT_PSRAM_WR_DUMMY_BITLEN (2*(5-1))
36 #define OCT_PSRAM_CS1_IO SPI_CS1_GPIO_NUM
37 #define OCT_PSRAM_VENDOR_ID 0xD
38
39 #define OCT_PSRAM_CS_SETUP_TIME 3
40 #define OCT_PSRAM_CS_HOLD_TIME 3
41 #define OCT_PSRAM_CS_ECC_HOLD_TIME 3
42 #define OCT_PSRAM_CS_HOLD_DELAY 2
43
44 #define OCT_PSRAM_PAGE_SIZE 2 //2 for 1024B
45 #define OCT_PSRAM_ECC_ENABLE_MASK BIT(8)
46
47
48 typedef struct {
49 union {
50 struct {
51 uint8_t drive_str: 2;
52 uint8_t read_latency: 3;
53 uint8_t lt: 1;
54 uint8_t rsvd0_1: 2;
55 };
56 uint8_t val;
57 } mr0;
58 union {
59 struct {
60 uint8_t vendor_id: 5;
61 uint8_t rsvd0_2: 3;
62 };
63 uint8_t val;
64 } mr1;
65 union {
66 struct {
67 uint8_t density: 3;
68 uint8_t dev_id: 2;
69 uint8_t rsvd1_2: 2;
70 uint8_t gb: 1;
71 };
72 uint8_t val;
73 } mr2;
74 union {
75 struct {
76 uint8_t rsvd3_7: 5;
77 uint8_t srf: 1;
78 uint8_t vcc: 1;
79 uint8_t rsvd0: 1;
80 };
81 uint8_t val;
82 } mr3;
83 union {
84 struct {
85 uint8_t pasr: 3;
86 uint8_t rf: 1;
87 uint8_t rsvd3: 1;
88 uint8_t wr_latency: 3;
89 };
90 uint8_t val;
91 } mr4;
92 union {
93 struct {
94 uint8_t bl: 2;
95 uint8_t bt: 1;
96 uint8_t rsvd0_4: 5;
97 };
98 uint8_t val;
99 } mr8;
100 } opi_psram_mode_reg_t;
101
102 static const char* TAG = "octal_psram";
103 static uint32_t s_psram_size; //this stands for physical psram size in bytes
104 static void s_config_psram_spi_phases(void);
105
esp_psram_impl_get_cs_io(void)106 uint8_t esp_psram_impl_get_cs_io(void)
107 {
108 return OCT_PSRAM_CS1_IO;
109 }
110
111 /**
112 * Initialise mode registers of the PSRAM
113 */
s_init_psram_mode_reg(int spi_num,opi_psram_mode_reg_t * mode_reg_config)114 static void s_init_psram_mode_reg(int spi_num, opi_psram_mode_reg_t *mode_reg_config)
115 {
116 esp_rom_spiflash_read_mode_t mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
117 int cmd_len = 16;
118 uint32_t addr = 0x0; //0x0 is the MR0 register
119 int addr_bit_len = 32;
120 int dummy = OCT_PSRAM_RD_DUMMY_BITLEN;
121 opi_psram_mode_reg_t mode_reg = {0};
122 int data_bit_len = 16;
123
124 //read
125 esp_rom_opiflash_exec_cmd(spi_num, mode,
126 OPI_PSRAM_REG_READ, cmd_len,
127 addr, addr_bit_len,
128 dummy,
129 NULL, 0,
130 &mode_reg.mr0.val, data_bit_len,
131 BIT(1),
132 false);
133
134 //modify
135 mode_reg.mr0.lt = mode_reg_config->mr0.lt;
136 mode_reg.mr0.read_latency = mode_reg_config->mr0.read_latency;
137 mode_reg.mr0.drive_str = mode_reg_config->mr0.drive_str;
138
139 //write
140 esp_rom_opiflash_exec_cmd(spi_num, mode,
141 OPI_PSRAM_REG_WRITE, cmd_len,
142 addr, addr_bit_len,
143 0,
144 &mode_reg.mr0.val, 16,
145 NULL, 0,
146 BIT(1),
147 false);
148
149 #if CONFIG_SPIRAM_ECC_ENABLE
150 addr = 0x8; //0x8 is the MR8 register
151 data_bit_len = 8;
152 //read
153 esp_rom_opiflash_exec_cmd(spi_num, mode,
154 OPI_PSRAM_REG_READ, cmd_len,
155 addr, addr_bit_len,
156 dummy,
157 NULL, 0,
158 &mode_reg.mr8.val, data_bit_len,
159 BIT(1),
160 false);
161
162 //modify
163 mode_reg.mr8.bt = mode_reg_config->mr8.bt;
164 mode_reg.mr8.bl = mode_reg_config->mr8.bl;
165
166 //write
167 esp_rom_opiflash_exec_cmd(spi_num, mode,
168 OPI_PSRAM_REG_WRITE, cmd_len,
169 addr, addr_bit_len,
170 0,
171 &mode_reg.mr8.val, 16,
172 NULL, 0,
173 BIT(1),
174 false);
175 #endif
176 }
177
s_get_psram_mode_reg(int spi_num,opi_psram_mode_reg_t * out_reg)178 static void s_get_psram_mode_reg(int spi_num, opi_psram_mode_reg_t *out_reg)
179 {
180 esp_rom_spiflash_read_mode_t mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
181 int cmd_len = 16;
182 int addr_bit_len = 32;
183 int dummy = OCT_PSRAM_RD_DUMMY_BITLEN;
184 int data_bit_len = 16;
185
186 //Read MR0~1 register
187 esp_rom_opiflash_exec_cmd(spi_num, mode,
188 OPI_PSRAM_REG_READ, cmd_len,
189 0x0, addr_bit_len,
190 dummy,
191 NULL, 0,
192 &out_reg->mr0.val, data_bit_len,
193 BIT(1),
194 false);
195 //Read MR2~3 register
196 esp_rom_opiflash_exec_cmd(spi_num, mode,
197 OPI_PSRAM_REG_READ, cmd_len,
198 0x2, addr_bit_len,
199 dummy,
200 NULL, 0,
201 &out_reg->mr2.val, data_bit_len,
202 BIT(1),
203 false);
204 data_bit_len = 8;
205 //Read MR4 register
206 esp_rom_opiflash_exec_cmd(spi_num, mode,
207 OPI_PSRAM_REG_READ, cmd_len,
208 0x4, addr_bit_len,
209 dummy,
210 NULL, 0,
211 &out_reg->mr4.val, data_bit_len,
212 BIT(1),
213 false);
214 //Read MR8 register
215 esp_rom_opiflash_exec_cmd(spi_num, mode,
216 OPI_PSRAM_REG_READ, cmd_len,
217 0x8, addr_bit_len,
218 dummy,
219 NULL, 0,
220 &out_reg->mr8.val, data_bit_len,
221 BIT(1),
222 false);
223 }
224
s_print_psram_info(opi_psram_mode_reg_t * reg_val)225 static void s_print_psram_info(opi_psram_mode_reg_t *reg_val)
226 {
227 ESP_EARLY_LOGI(TAG, "vendor id : 0x%02x (%s)", reg_val->mr1.vendor_id, reg_val->mr1.vendor_id == 0x0d ? "AP" : "UNKNOWN");
228 ESP_EARLY_LOGI(TAG, "dev id : 0x%02x (generation %d)", reg_val->mr2.dev_id, reg_val->mr2.dev_id + 1);
229 ESP_EARLY_LOGI(TAG, "density : 0x%02x (%d Mbit)", reg_val->mr2.density, reg_val->mr2.density == 0x1 ? 32 :
230 reg_val->mr2.density == 0X3 ? 64 :
231 reg_val->mr2.density == 0x5 ? 128 :
232 reg_val->mr2.density == 0x7 ? 256 : 0);
233 ESP_EARLY_LOGI(TAG, "good-die : 0x%02x (%s)", reg_val->mr2.gb, reg_val->mr2.gb == 1 ? "Pass" : "Fail");
234 ESP_EARLY_LOGI(TAG, "Latency : 0x%02x (%s)", reg_val->mr0.lt, reg_val->mr0.lt == 1 ? "Fixed" : "Variable");
235 ESP_EARLY_LOGI(TAG, "VCC : 0x%02x (%s)", reg_val->mr3.vcc, reg_val->mr3.vcc == 1 ? "3V" : "1.8V");
236 ESP_EARLY_LOGI(TAG, "SRF : 0x%02x (%s Refresh)", reg_val->mr3.srf, reg_val->mr3.srf == 0x1 ? "Fast" : "Slow");
237 ESP_EARLY_LOGI(TAG, "BurstType : 0x%02x (%s Wrap)", reg_val->mr8.bt, reg_val->mr8.bt == 1 && reg_val->mr8.bl != 3 ? "Hybrid" : "");
238 ESP_EARLY_LOGI(TAG, "BurstLen : 0x%02x (%d Byte)", reg_val->mr8.bl, reg_val->mr8.bl == 0x00 ? 16 :
239 reg_val->mr8.bl == 0x01 ? 32 :
240 reg_val->mr8.bl == 0x10 ? 64 : 1024);
241 ESP_EARLY_LOGI(TAG, "Readlatency : 0x%02x (%d cycles@%s)", reg_val->mr0.read_latency, reg_val->mr0.read_latency * 2 + 6,
242 reg_val->mr0.lt == 1 ? "Fixed" : "Variable");
243 ESP_EARLY_LOGI(TAG, "DriveStrength: 0x%02x (1/%d)", reg_val->mr0.drive_str, reg_val->mr0.drive_str == 0x00 ? 1 :
244 reg_val->mr0.drive_str == 0x01 ? 2 :
245 reg_val->mr0.drive_str == 0x02 ? 4 : 8);
246 }
247
s_set_psram_cs_timing(void)248 static void s_set_psram_cs_timing(void)
249 {
250 //SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time, cs_hold_delay registers for PSRAM, so we only need to set SPI0 related registers here
251 SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_M | SPI_MEM_SPI_SMEM_CS_SETUP_M);
252 SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V, OCT_PSRAM_CS_HOLD_TIME, SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S);
253 SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V, OCT_PSRAM_CS_SETUP_TIME, SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S);
254 #if CONFIG_SPIRAM_ECC_ENABLE
255 SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_ECC_CS_HOLD_TIME_V, OCT_PSRAM_CS_ECC_HOLD_TIME, SPI_MEM_SPI_SMEM_ECC_CS_HOLD_TIME_S);
256 #endif
257 //CS1 high time
258 SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_V, OCT_PSRAM_CS_HOLD_DELAY, SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_S);
259 }
260
s_init_psram_pins(void)261 static void s_init_psram_pins(void)
262 {
263 //Set cs1 pin function
264 PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[OCT_PSRAM_CS1_IO], FUNC_SPICS1_SPICS1);
265 //Set mspi cs1 drive strength
266 PIN_SET_DRV(GPIO_PIN_MUX_REG[OCT_PSRAM_CS1_IO], 3);
267 //Set psram clock pin drive strength
268 REG_SET_FIELD(SPI_MEM_DATE_REG(0), SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV, 3);
269
270 // Preserve psram pins
271 esp_gpio_reserve_pins(BIT64(OCT_PSRAM_CS1_IO));
272 }
273
274 /**
275 * Enable error correcting code feature
276 *
277 * Can add an input parameter for selecting ECC mode if needed
278 */
s_configure_psram_ecc(void)279 static void s_configure_psram_ecc(void)
280 {
281 #if CONFIG_SPIRAM_ECC_ENABLE
282 //Clear this bit to use ECC 16to17 mode
283 CLEAR_PERI_REG_MASK(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_ECC_16TO18_BYTE_EN_M);
284 SET_PERI_REG_BITS(SYSCON_SPI_MEM_ECC_CTRL_REG, SYSCON_SRAM_PAGE_SIZE_V, OCT_PSRAM_PAGE_SIZE, SYSCON_SRAM_PAGE_SIZE_S);
285 SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_ECC_SKIP_PAGE_CORNER_M);
286 /**
287 * Enable ECC region 0 (ACE0)
288 * Default: ACE0 range: 0 ~ 256MB
289 * Current Octal PSRAM is 8MB, ACE0 is enough
290 */
291 SET_PERI_REG_MASK(SYSCON_SRAM_ACE0_ATTR_REG, OCT_PSRAM_ECC_ENABLE_MASK);
292 ESP_EARLY_LOGI(TAG, "ECC is enabled");
293 #else
294 CLEAR_PERI_REG_MASK(SYSCON_SRAM_ACE0_ATTR_REG, OCT_PSRAM_ECC_ENABLE_MASK);
295 #endif
296 }
297
esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode)298 esp_err_t esp_psram_impl_enable(psram_vaddr_mode_t vaddrmode)
299 {
300 s_init_psram_pins();
301 s_set_psram_cs_timing();
302 s_configure_psram_ecc();
303
304 //enter MSPI slow mode to init PSRAM device registers
305 mspi_timing_enter_low_speed_mode(true);
306
307 //set to variable dummy mode
308 SET_PERI_REG_MASK(SPI_MEM_DDR_REG(1), SPI_MEM_SPI_FMEM_VAR_DUMMY);
309 esp_rom_spi_set_dtr_swap_mode(1, false, false);
310
311 //Set PSRAM read latency and drive strength
312 static opi_psram_mode_reg_t mode_reg = {0};
313 mode_reg.mr0.lt = 1;
314 mode_reg.mr0.read_latency = 2;
315 mode_reg.mr0.drive_str = 0;
316 mode_reg.mr8.bl = 3;
317 mode_reg.mr8.bt = 0;
318 s_init_psram_mode_reg(1, &mode_reg);
319 //Print PSRAM info
320 s_get_psram_mode_reg(1, &mode_reg);
321 if (mode_reg.mr1.vendor_id != OCT_PSRAM_VENDOR_ID) {
322 ESP_EARLY_LOGE(TAG, "PSRAM ID read error: 0x%08x, PSRAM chip not found or not supported, or wrong PSRAM line mode", mode_reg.mr1.vendor_id);
323 return ESP_ERR_NOT_SUPPORTED;
324 }
325 s_print_psram_info(&mode_reg);
326 s_psram_size = mode_reg.mr2.density == 0x1 ? PSRAM_SIZE_4MB :
327 mode_reg.mr2.density == 0X3 ? PSRAM_SIZE_8MB :
328 mode_reg.mr2.density == 0x5 ? PSRAM_SIZE_16MB :
329 mode_reg.mr2.density == 0x7 ? PSRAM_SIZE_32MB : 0;
330
331 //Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the SPI0 PSRAM timing related registers accordingly
332 mspi_timing_psram_tuning();
333 //Back to the high speed mode. Flash/PSRAM clocks are set to the clock that user selected. SPI0/1 registers are all set correctly
334 mspi_timing_enter_high_speed_mode(true);
335
336 /**
337 * Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on these regs.
338 * This function is to restore SPI1 init state.
339 */
340 spi_flash_set_rom_required_regs();
341 //Flash chip requires MSPI specifically, call this function to set them
342 spi_flash_set_vendor_required_regs();
343
344 s_config_psram_spi_phases();
345 return ESP_OK;
346 }
347
348 //Configure PSRAM SPI0 phase related registers here according to the PSRAM chip requirement
s_config_psram_spi_phases(void)349 static void s_config_psram_spi_phases(void)
350 {
351 //Config Write CMD phase for SPI0 to access PSRAM
352 SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_SRAM_USR_WCMD_M);
353 SET_PERI_REG_BITS(SPI_MEM_SRAM_DWR_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN, OCT_PSRAM_WR_CMD_BITLEN - 1, SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
354 SET_PERI_REG_BITS(SPI_MEM_SRAM_DWR_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE, OPI_PSRAM_SYNC_WRITE, SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE_S);
355
356 //Config Read CMD phase for SPI0 to access PSRAM
357 SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_SRAM_USR_RCMD_M);
358 SET_PERI_REG_BITS(SPI_MEM_SRAM_DRD_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_V, OCT_PSRAM_RD_CMD_BITLEN - 1, SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
359 SET_PERI_REG_BITS(SPI_MEM_SRAM_DRD_CMD_REG(0), SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_V, OPI_PSRAM_SYNC_READ, SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_S);
360
361 //Config ADDR phase
362 SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_ADDR_BITLEN_V, OCT_PSRAM_ADDR_BITLEN - 1, SPI_MEM_SRAM_ADDR_BITLEN_S);
363 SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_CACHE_USR_SCMD_4BYTE_M);
364
365 //Config RD/WR Dummy phase
366 SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_USR_RD_SRAM_DUMMY_M | SPI_MEM_USR_WR_SRAM_DUMMY_M);
367 SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_RDUMMY_CYCLELEN_V, OCT_PSRAM_RD_DUMMY_BITLEN - 1, SPI_MEM_SRAM_RDUMMY_CYCLELEN_S);
368 SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_DDR_REG(0), SPI_MEM_SPI_SMEM_VAR_DUMMY_M);
369 SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_WDUMMY_CYCLELEN_V, OCT_PSRAM_WR_DUMMY_BITLEN - 1, SPI_MEM_SRAM_WDUMMY_CYCLELEN_S);
370
371 CLEAR_PERI_REG_MASK(SPI_MEM_SPI_SMEM_DDR_REG(0), SPI_MEM_SPI_SMEM_DDR_WDAT_SWP_M | SPI_MEM_SPI_SMEM_DDR_RDAT_SWP_M);
372 SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_DDR_REG(0), SPI_MEM_SPI_SMEM_DDR_EN_M);
373
374 SET_PERI_REG_MASK(SPI_MEM_SRAM_CMD_REG(0), SPI_MEM_SDUMMY_OUT_M | SPI_MEM_SCMD_OCT_M | SPI_MEM_SADDR_OCT_M | SPI_MEM_SDOUT_OCT_M | SPI_MEM_SDIN_OCT_M);
375 SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(0), SPI_MEM_SRAM_OCT_M);
376
377 Cache_Resume_DCache(0);
378 }
379
380
381 /*---------------------------------------------------------------------------------
382 * Following APIs are not required to be IRAM-Safe
383 *
384 * Consider moving these to another file if this kind of APIs grows dramatically
385 *-------------------------------------------------------------------------------*/
esp_psram_impl_get_physical_size(uint32_t * out_size_bytes)386 esp_err_t esp_psram_impl_get_physical_size(uint32_t *out_size_bytes)
387 {
388 if (!out_size_bytes) {
389 return ESP_ERR_INVALID_ARG;
390 }
391
392 *out_size_bytes = s_psram_size;
393 return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
394 }
395
396 /**
397 * This function is to get the available physical psram size in bytes.
398 * If ECC is enabled, available PSRAM size will be 15/16 times its physical size.
399 */
esp_psram_impl_get_available_size(uint32_t * out_size_bytes)400 esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
401 {
402 if (!out_size_bytes) {
403 return ESP_ERR_INVALID_ARG;
404 }
405
406 #if CONFIG_SPIRAM_ECC_ENABLE
407 *out_size_bytes = s_psram_size * 15 / 16;
408 #else
409 *out_size_bytes = s_psram_size;
410 #endif
411 return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
412 }
413