esp_psram_impl_ap_hex.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "sdkconfig.h"
  7. #include "esp_attr.h"
  8. #include "esp_err.h"
  9. #include "esp_log.h"
  10. #include "esp_private/periph_ctrl.h"
  11. #include "../esp_psram_impl.h"
  12. #include "rom/opi_flash.h"
  13. #include "hal/psram_ctrlr_ll.h"
  14. // Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section
  15. #define PSRAM_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
  16. #define AP_HEX_PSRAM_SYNC_READ 0x0000
  17. #define AP_HEX_PSRAM_SYNC_WRITE 0x8080
  18. #define AP_HEX_PSRAM_BURST_READ 0x2020
  19. #define AP_HEX_PSRAM_BURST_WRITE 0xA0A0
  20. #define AP_HEX_PSRAM_REG_READ 0x4040
  21. #define AP_HEX_PSRAM_REG_WRITE 0xC0C0
  22. #define AP_HEX_PSRAM_RD_CMD_BITLEN 16
  23. #define AP_HEX_PSRAM_WR_CMD_BITLEN 16
  24. #define AP_HEX_PSRAM_ADDR_BITLEN 32
  25. #define AP_HEX_PSRAM_RD_DUMMY_BITLEN (2*(10-1))
  26. #define AP_HEX_PSRAM_WR_DUMMY_BITLEN (2*(5-1))
  27. #define AP_HEX_PSRAM_VENDOR_ID 0xD
  28. #define AP_HEX_PSRAM_CS_SETUP_TIME 4
  29. #define AP_HEX_PSRAM_CS_HOLD_TIME 4
  30. #define AP_HEX_PSRAM_CS_ECC_HOLD_TIME 4
  31. #define AP_HEX_PSRAM_CS_HOLD_DELAY 3
  32. typedef struct {
  33. union {
  34. struct {
  35. uint8_t drive_str: 2;
  36. uint8_t read_latency: 3;
  37. uint8_t lt: 1;
  38. uint8_t rsvd6: 1;
  39. uint8_t tso: 1;
  40. };
  41. uint8_t val;
  42. } mr0;
  43. union {
  44. struct {
  45. uint8_t vendor_id: 5;
  46. uint8_t rsvd0_2: 2;
  47. uint8_t ulp: 1;
  48. };
  49. uint8_t val;
  50. } mr1;
  51. union {
  52. struct {
  53. uint8_t density: 3;
  54. uint8_t dev_id: 2;
  55. uint8_t kgd: 3;
  56. };
  57. uint8_t val;
  58. } mr2;
  59. union {
  60. struct {
  61. uint8_t rsvd3_7: 4;
  62. uint8_t srf: 2;
  63. uint8_t rsvd0: 1;
  64. uint8_t rbx_en: 1;
  65. };
  66. uint8_t val;
  67. } mr3;
  68. union {
  69. struct {
  70. uint8_t pasr: 3;
  71. uint8_t rf: 2;
  72. uint8_t wr_latency: 3;
  73. };
  74. uint8_t val;
  75. } mr4;
  76. union {
  77. struct {
  78. uint8_t bl: 2;
  79. uint8_t bt: 1;
  80. uint8_t rbx: 1;
  81. uint8_t rsvd5: 2;
  82. uint8_t x16: 1;
  83. uint8_t rsvd7: 1;
  84. };
  85. uint8_t val;
  86. } mr8;
  87. } hex_psram_mode_reg_t;
  88. static const char* TAG = "hex_psram";
  89. static uint32_t s_psram_size; //this stands for physical psram size in bytes
  90. /**
  91. * Common psram transaction
  92. */
  93. static void s_psram_common_transaction(uint32_t mspi_id,
  94. uint32_t cmd, uint32_t cmd_bitlen,
  95. uint32_t addr, uint32_t addr_bitlen,
  96. uint32_t dummy_bits,
  97. uint8_t* mosi_data, uint32_t mosi_bitlen,
  98. uint8_t* miso_data, uint32_t miso_bitlen,
  99. bool is_write_erase_operation)
  100. {
  101. psram_ctrlr_ll_common_transaction(mspi_id, cmd, cmd_bitlen, addr, addr_bitlen, dummy_bits,
  102. mosi_data, mosi_bitlen, miso_data, miso_bitlen,
  103. is_write_erase_operation);
  104. }
  105. /**
  106. * Initialise mode registers of the PSRAM
  107. */
  108. static void s_init_psram_mode_reg(int spi_num, hex_psram_mode_reg_t *mode_reg_config)
  109. {
  110. int cmd_len = 16;
  111. uint32_t addr = 0x0;
  112. int addr_bit_len = 32;
  113. int dummy = AP_HEX_PSRAM_RD_DUMMY_BITLEN;
  114. hex_psram_mode_reg_t mode_reg = {0};
  115. int data_bit_len = 16;
  116. //read
  117. s_psram_common_transaction(spi_num,
  118. AP_HEX_PSRAM_REG_READ, cmd_len,
  119. addr, addr_bit_len,
  120. dummy,
  121. NULL, 0,
  122. &mode_reg.mr0.val, data_bit_len,
  123. false);
  124. //modify
  125. mode_reg.mr0.lt = mode_reg_config->mr0.lt;
  126. mode_reg.mr0.read_latency = mode_reg_config->mr0.read_latency;
  127. mode_reg.mr0.drive_str = mode_reg_config->mr0.drive_str;
  128. //write
  129. s_psram_common_transaction(spi_num,
  130. AP_HEX_PSRAM_REG_WRITE, cmd_len,
  131. addr, addr_bit_len,
  132. 0,
  133. &mode_reg.mr0.val, 16,
  134. NULL, 0,
  135. false);
  136. addr = 0x8;
  137. data_bit_len = 8;
  138. //read
  139. s_psram_common_transaction(spi_num,
  140. AP_HEX_PSRAM_REG_READ, cmd_len,
  141. addr, addr_bit_len,
  142. dummy,
  143. NULL, 0,
  144. &mode_reg.mr8.val, data_bit_len,
  145. false);
  146. //modify
  147. mode_reg.mr8.bt = mode_reg_config->mr8.bt;
  148. mode_reg.mr8.bl = mode_reg_config->mr8.bl;
  149. mode_reg.mr8.rbx = mode_reg_config->mr8.rbx;
  150. mode_reg.mr8.x16 = mode_reg_config->mr8.x16;
  151. //write
  152. s_psram_common_transaction(spi_num,
  153. AP_HEX_PSRAM_REG_WRITE, cmd_len,
  154. addr, addr_bit_len,
  155. 0,
  156. &mode_reg.mr8.val, 16,
  157. NULL, 0,
  158. false);
  159. }
  160. static void s_get_psram_mode_reg(int spi_num, hex_psram_mode_reg_t *out_reg)
  161. {
  162. int cmd_len = 16;
  163. int addr_bit_len = 32;
  164. int dummy = AP_HEX_PSRAM_RD_DUMMY_BITLEN;
  165. int data_bit_len = 16;
  166. //Read MR0~1 register
  167. s_psram_common_transaction(spi_num,
  168. AP_HEX_PSRAM_REG_READ, cmd_len,
  169. 0x0, addr_bit_len,
  170. dummy,
  171. NULL, 0,
  172. &out_reg->mr0.val, data_bit_len,
  173. false);
  174. //Read MR2~3 register
  175. s_psram_common_transaction(spi_num,
  176. AP_HEX_PSRAM_REG_READ, cmd_len,
  177. 0x2, addr_bit_len,
  178. dummy,
  179. NULL, 0,
  180. &out_reg->mr2.val, data_bit_len,
  181. false);
  182. data_bit_len = 8;
  183. //Read MR4 register
  184. s_psram_common_transaction(spi_num,
  185. AP_HEX_PSRAM_REG_READ, cmd_len,
  186. 0x4, addr_bit_len,
  187. dummy,
  188. NULL, 0,
  189. &out_reg->mr4.val, data_bit_len,
  190. false);
  191. //Read MR8 register
  192. s_psram_common_transaction(spi_num,
  193. AP_HEX_PSRAM_REG_READ, cmd_len,
  194. 0x8, addr_bit_len,
  195. dummy,
  196. NULL, 0,
  197. &out_reg->mr8.val, data_bit_len,
  198. false);
  199. }
  200. static void s_print_psram_info(hex_psram_mode_reg_t *reg_val)
  201. {
  202. ESP_EARLY_LOGI(TAG, "vendor id : 0x%02x (%s)", reg_val->mr1.vendor_id, reg_val->mr1.vendor_id == 0x0d ? "AP" : "UNKNOWN");
  203. ESP_EARLY_LOGI(TAG, "Latency : 0x%02x (%s)", reg_val->mr0.lt, reg_val->mr0.lt == 1 ? "Fixed" : "Variable");
  204. ESP_EARLY_LOGI(TAG, "DriveStr. : 0x%02x (%d Ohm)", reg_val->mr0.drive_str, reg_val->mr0.drive_str < 2 ? 25 * (reg_val->mr0.drive_str + 1) : 100 * (reg_val->mr0.drive_str - 1));
  205. ESP_EARLY_LOGI(TAG, "dev id : 0x%02x (generation %d)", reg_val->mr2.dev_id, reg_val->mr2.dev_id + 1);
  206. ESP_EARLY_LOGI(TAG, "density : 0x%02x (%d Mbit)", reg_val->mr2.density, reg_val->mr2.density == 0x1 ? 32 :
  207. reg_val->mr2.density == 0X3 ? 64 :
  208. reg_val->mr2.density == 0x5 ? 128 :
  209. reg_val->mr2.density == 0x7 ? 256 : 0);
  210. ESP_EARLY_LOGI(TAG, "good-die : 0x%02x (%s)", reg_val->mr2.kgd, reg_val->mr2.kgd == 6 ? "Pass" : "Fail");
  211. ESP_EARLY_LOGI(TAG, "SRF : 0x%02x (%s Refresh)", reg_val->mr3.srf, reg_val->mr3.srf == 0x1 ? "Fast" : "Slow");
  212. ESP_EARLY_LOGI(TAG, "BurstType : 0x%02x (%s Wrap)", reg_val->mr8.bt, reg_val->mr8.bt == 1 && reg_val->mr8.bl != 3 ? "Hybrid" : "");
  213. ESP_EARLY_LOGI(TAG, "BurstLen : 0x%02x (%d Byte)", reg_val->mr8.bl, reg_val->mr8.bl == 0x00 ? 16 :
  214. reg_val->mr8.bl == 0x01 ? 32 :
  215. reg_val->mr8.bl == 0x10 ? 64 : 2048);
  216. ESP_EARLY_LOGI(TAG, "BitMode : 0x%02x (%s Mode)", reg_val->mr8.x16, reg_val->mr8.x16 == 1 ? "X16" : "X8");
  217. ESP_EARLY_LOGI(TAG, "Readlatency : 0x%02x (%d cycles@%s)", reg_val->mr0.read_latency, reg_val->mr0.read_latency * 2 + 6,
  218. reg_val->mr0.lt == 1 ? "Fixed" : "Variable");
  219. ESP_EARLY_LOGI(TAG, "DriveStrength: 0x%02x (1/%d)", reg_val->mr0.drive_str, reg_val->mr0.drive_str == 0x00 ? 1 :
  220. reg_val->mr0.drive_str == 0x01 ? 2 :
  221. reg_val->mr0.drive_str == 0x02 ? 4 : 8);
  222. }
  223. static void s_config_mspi_for_psram(void)
  224. {
  225. //Config Write CMD phase for SPI0 to access PSRAM
  226. psram_ctrlr_ll_set_wr_cmd(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_WR_CMD_BITLEN, AP_HEX_PSRAM_BURST_WRITE);
  227. //Config Read CMD phase for SPI0 to access PSRAM
  228. psram_ctrlr_ll_set_rd_cmd(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_RD_CMD_BITLEN, AP_HEX_PSRAM_BURST_READ);
  229. //Config ADDR phase
  230. psram_ctrlr_ll_set_addr_bitlen(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_ADDR_BITLEN);
  231. psram_ctrlr_ll_enable_4byte_addr(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  232. //Config RD/WR Dummy phase
  233. psram_ctrlr_ll_set_wr_dummy(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_WR_DUMMY_BITLEN);
  234. psram_ctrlr_ll_set_rd_dummy(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_RD_DUMMY_BITLEN);
  235. psram_ctrlr_ll_enable_variable_dummy(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  236. psram_ctrlr_ll_enable_wr_dummy_level_control(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  237. //DDR
  238. psram_ctrlr_ll_enable_ddr_wr_data_swap(PSRAM_CTRLR_LL_MSPI_ID_2, false);
  239. psram_ctrlr_ll_enable_ddr_rd_data_swap(PSRAM_CTRLR_LL_MSPI_ID_2, false);
  240. psram_ctrlr_ll_enable_ddr_mode(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  241. //Line mode
  242. psram_ctrlr_ll_enable_oct_line_mode(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  243. psram_ctrlr_ll_enable_hex_data_line_mode(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  244. #if CONFIG_SPIRAM_USE_8LINE_MODE
  245. psram_ctrlr_ll_enable_hex_data_line_mode(PSRAM_CTRLR_LL_MSPI_ID_2, false);
  246. #endif
  247. //AXI
  248. psram_ctrlr_ll_enable_axi_access(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  249. psram_ctrlr_ll_enable_wr_splice(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  250. psram_ctrlr_ll_enable_rd_splice(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  251. }
  252. static void s_set_psram_cs_timing(void)
  253. {
  254. psram_ctrlr_ll_set_cs_setup(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_CS_SETUP_TIME);
  255. psram_ctrlr_ll_set_cs_hold(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_CS_HOLD_TIME);
  256. psram_ctrlr_ll_set_cs_hold_delay(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_CS_HOLD_DELAY);
  257. #if CONFIG_SPIRAM_ECC_ENABLE
  258. psram_ctrlr_ll_set_cs_hold_ecc(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_CS_ECC_HOLD_TIME);
  259. #endif
  260. }
  261. #if CONFIG_SPIRAM_ECC_ENABLE
  262. static void s_mspi_ecc_show_info(void)
  263. {
  264. for (int i = 0; i < PSRAM_CTRLR_LL_PMS_REGION_NUMS; i++) {
  265. ESP_EARLY_LOGV(TAG, "region[%d] addr: 0x%08x", i, psram_ctrlr_ll_get_pms_region_start_addr(PSRAM_CTRLR_LL_MSPI_ID_2, i));
  266. ESP_EARLY_LOGV(TAG, "region[%d] size: 0x%08x", i, psram_ctrlr_ll_get_pms_region_size(PSRAM_CTRLR_LL_MSPI_ID_2, i));
  267. }
  268. uint32_t page_size = psram_ctrlr_ll_get_page_size(PSRAM_CTRLR_LL_MSPI_ID_2);
  269. ESP_EARLY_LOGV(TAG, "ECC page size: %d", page_size);
  270. }
  271. /**
  272. * Enable error correcting code feature
  273. *
  274. * Can add an input parameter for selecting ECC mode if needed
  275. */
  276. static void s_configure_psram_ecc(void)
  277. {
  278. psram_ctrlr_ll_enable_16to18_ecc(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  279. psram_ctrlr_ll_enable_skip_page_corner(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  280. psram_ctrlr_ll_enable_split_trans(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  281. psram_ctrlr_ll_set_page_size(PSRAM_CTRLR_LL_MSPI_ID_2, 2048);
  282. psram_ctrlr_ll_enable_ecc_addr_conversion(PSRAM_CTRLR_LL_MSPI_ID_2, 2048);
  283. /**
  284. * Enable ECC region 0 (ACE0)
  285. * Default: ACE0 range: 0 ~ 256MB
  286. * Current Hex PSRAM is 8MB, ACE0 is enough
  287. */
  288. psram_ctrlr_ll_enable_pms_region_ecc(PSRAM_CTRLR_LL_MSPI_ID_2, 0, true);
  289. ESP_EARLY_LOGI(TAG, "ECC is enabled");
  290. s_mspi_ecc_show_info();
  291. }
  292. #endif //#if CONFIG_SPIRAM_ECC_ENABLE
  293. esp_err_t esp_psram_impl_enable(void)
  294. {
  295. PSRAM_RCC_ATOMIC() {
  296. psram_ctrlr_ll_enable_module_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  297. psram_ctrlr_ll_reset_module_clock(PSRAM_CTRLR_LL_MSPI_ID_2);
  298. psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_2, PSRAM_CLK_SRC_XTAL);
  299. }
  300. s_set_psram_cs_timing();
  301. #if CONFIG_SPIRAM_ECC_ENABLE
  302. s_configure_psram_ecc();
  303. #endif
  304. //enter MSPI slow mode to init PSRAM device registers
  305. psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_2, 2);
  306. psram_ctrlr_ll_enable_dll(PSRAM_CTRLR_LL_MSPI_ID_2, true);
  307. psram_ctrlr_ll_enable_dll(PSRAM_CTRLR_LL_MSPI_ID_3, true);
  308. static hex_psram_mode_reg_t mode_reg = {};
  309. mode_reg.mr0.lt = 1;
  310. mode_reg.mr0.read_latency = 2;
  311. mode_reg.mr0.drive_str = 0;
  312. mode_reg.mr8.bl = 3;
  313. mode_reg.mr8.bt = 0;
  314. mode_reg.mr8.rbx = 1;
  315. mode_reg.mr8.x16 = 1;
  316. #if CONFIG_SPIRAM_USE_8LINE_MODE
  317. mode_reg.mr8.x16 = 0;
  318. #endif
  319. s_init_psram_mode_reg(PSRAM_CTRLR_LL_MSPI_ID_3, &mode_reg);
  320. //Print PSRAM info
  321. s_get_psram_mode_reg(PSRAM_CTRLR_LL_MSPI_ID_3, &mode_reg);
  322. if (mode_reg.mr1.vendor_id != AP_HEX_PSRAM_VENDOR_ID) {
  323. 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);
  324. return ESP_ERR_NOT_SUPPORTED;
  325. }
  326. s_print_psram_info(&mode_reg);
  327. s_psram_size = mode_reg.mr2.density == 0x1 ? PSRAM_SIZE_4MB :
  328. mode_reg.mr2.density == 0X3 ? PSRAM_SIZE_8MB :
  329. mode_reg.mr2.density == 0x5 ? PSRAM_SIZE_16MB :
  330. mode_reg.mr2.density == 0x7 ? PSRAM_SIZE_32MB :
  331. mode_reg.mr2.density == 0x6 ? PSRAM_SIZE_64MB : 0;
  332. s_config_mspi_for_psram();
  333. return ESP_OK;
  334. }
  335. uint8_t esp_psram_impl_get_cs_io(void)
  336. {
  337. ESP_EARLY_LOGI(TAG, "psram CS IO is dedicated");
  338. return -1;
  339. }
  340. esp_err_t esp_psram_impl_get_physical_size(uint32_t *out_size_bytes)
  341. {
  342. if (!out_size_bytes) {
  343. return ESP_ERR_INVALID_ARG;
  344. }
  345. *out_size_bytes = s_psram_size;
  346. return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
  347. }
  348. /**
  349. * This function is to get the available physical psram size in bytes.
  350. * If ECC is enabled, available PSRAM size will be 7/8 times its physical size.
  351. */
  352. esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
  353. {
  354. if (!out_size_bytes) {
  355. return ESP_ERR_INVALID_ARG;
  356. }
  357. #if CONFIG_SPIRAM_ECC_ENABLE
  358. *out_size_bytes = s_psram_size * 7 / 8;
  359. #else
  360. *out_size_bytes = s_psram_size;
  361. #endif
  362. return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
  363. }