mtb_serial_memory.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /***********************************************************************************************//**
  2. * \file mtb_serial_memory.h
  3. *
  4. * \brief
  5. * Provides APIs for interacting with an external memory connected to the SPI or
  6. * Serial Memory interface. Read is implemented as both blocking and non-blocking whereas
  7. * write, and erase are implemented as blocking functions.
  8. *
  9. ***************************************************************************************************
  10. * \copyright
  11. * Copyright 2018-2024 Cypress Semiconductor Corporation (an Infineon company) or
  12. * an affiliate of Cypress Semiconductor Corporation
  13. *
  14. * SPDX-License-Identifier: Apache-2.0
  15. *
  16. * Licensed under the Apache License, Version 2.0 (the "License");
  17. * you may not use this file except in compliance with the License.
  18. * You may obtain a copy of the License at
  19. *
  20. * http://www.apache.org/licenses/LICENSE-2.0
  21. *
  22. * Unless required by applicable law or agreed to in writing, software
  23. * distributed under the License is distributed on an "AS IS" BASIS,
  24. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  25. * See the License for the specific language governing permissions and
  26. * limitations under the License.
  27. **************************************************************************************************/
  28. /**
  29. * \addtogroup group_board_libs Serial Memory
  30. * \ingroup group_lib_impl
  31. * \{
  32. *
  33. * \section section_qspi_configurator_to_smif QSPI configurator slave slot correlation with pins
  34. * In QSPI configurator Memory Parts are tied to a specific slave slot that is linked to the
  35. * actual slave select pin mappings of that specific device. So selecting a memory configuration for
  36. * slot 0 means that physically that external memory will be the connected to slave select 0 pin.
  37. * This is important for kits that have hardwired connections to external memories where the
  38. * memory configuration needs to be in the correct slot depending on what slave select pin is
  39. * hardwired to it.
  40. *
  41. * \section section_serial_memory_octal_ddr_handling Serial Memory handling for Octal DDR
  42. * For external memories that are configured in Octal DDR mode, read/write operations at odd
  43. * addresses and with length equal to 1 are not natively supported due to limitations in the
  44. * protocol that requires an even address and/or even lengths.
  45. * For this reason a special handling of these cases is present in \ref mtb_serial_memory_read
  46. * and \ref mtb_serial_memory_write to allow the use of odd addresses in a transparent way for
  47. * the user.
  48. *
  49. * For \ref mtb_serial_memory_read when selecting a read one byte at an odd address, the
  50. * function will instead perform a read at the even address preceding the specified address and
  51. * then discard the extra byte returning to the user only the data they requested.
  52. *
  53. * For \ref mtb_serial_memory_write the function needs to take into consideration all four
  54. * possible combination of even/odd addresses and lengths:
  55. * - For even addresses, even lengths the function directly calls the PDL write function, this is
  56. * the standard use case
  57. * - For even addresses, length equal to one byte the function first reads the memory for 2 bytes
  58. * and
  59. * then creates a new write buffer copying the user's input buffer and making sure the last byte
  60. * is not altered using the data it previously read
  61. * WARNING: This will essentially write a byte past the intended one with its existing value that
  62. * was previously read. Ensure that your memory can support this.
  63. * - For even addresses, odd lengths greater than one the function will return an error as this is
  64. * an unsupported use case
  65. * - For odd addresses, even lengths the function will return an error as this is an unsupported
  66. * use case
  67. * - For odd addresses, length equal to one byte the function first reads the memory for 2 bytes
  68. * starting at the even address preceding the specified address to and then creates a new write
  69. * buffer copying the user's input buffer and making sure the first byte will not be altered using
  70. * the data it previously read.
  71. * WARNING: This will rewrite a location that has already been written (with its existing value).
  72. * Ensure that your memory can support this.
  73. * - For odd addresses, odd lengths greater than one the function will return an error as this is
  74. * an unsupported use case.
  75. *
  76. *
  77. * This special handling needs to be enabled by setting define in
  78. * _MTB_SERIAL_MEMORY_EMULATE_BYTE_ADDRESSABLE
  79. * the application Makefile.
  80. *
  81. */
  82. #pragma once
  83. #include <stddef.h>
  84. #include "cy_result.h"
  85. #include "cy_pdl.h"
  86. #include "mtb_hal.h"
  87. #if defined(MTB_SERIAL_MEMORY_THREAD_SAFE)
  88. #include <stdlib.h>
  89. #include "cyabs_rtos.h"
  90. #endif /* #if defined(MTB_SERIAL_MEMORY_THREAD_SAFE) */
  91. #ifdef DOXYGEN
  92. /** Enables thread-safety for use with multi-threaded RTOS environment. */
  93. #define MTB_SERIAL_MEMORY_THREAD_SAFE
  94. /** The MXSMIF IP is available. */
  95. #define CY_IP_MXSMIF
  96. #endif /* #ifdef DOXYGEN */
  97. #ifdef CY_IP_MXSMIF
  98. #if defined(__cplusplus)
  99. extern "C" {
  100. #endif
  101. /** The major version of the serial memory asset */
  102. #define MTB_SERIAL_MEMORY_VERSION_MAJOR (3U)
  103. /** The function or operation is not supported on the target or the memory */
  104. #define MTB_RSLT_SERIAL_MEMORY_ERR_UNSUPPORTED \
  105. (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_MEMORY, 1))
  106. /** Parameters passed to a function are invalid */
  107. #define MTB_RSLT_SERIAL_MEMORY_ERR_BAD_PARAM \
  108. (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_MEMORY, 2))
  109. /** A previously initiated read operation is not yet complete */
  110. #define MTB_RSLT_SERIAL_MEMORY_ERR_READ_BUSY \
  111. (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_MEMORY, 3))
  112. /** Setting octal enabled failed. */
  113. #define MTB_RSLT_SERIAL_MEMORY_ERR_OCTAL_ENABLE \
  114. (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_MEMORY, 4))
  115. /** Setting rx capture mode failed. */
  116. #define MTB_RSLT_SERIAL_MEMORY_ERR_RX_CAPTURE \
  117. (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_MEMORY, 5))
  118. /**
  119. * Serial Memory Chip Select
  120. * Each chip select is represented by an enumeration that has the bit
  121. * corresponding to the chip select number set.
  122. */
  123. typedef enum
  124. {
  125. MTB_SERIAL_MEMORY_CHIP_SELECT_0 = 1u, /**< The SMIF chip select 0 */
  126. MTB_SERIAL_MEMORY_CHIP_SELECT_1 = 1u << 1, /**< The SMIF chip select 1 */
  127. MTB_SERIAL_MEMORY_CHIP_SELECT_2 = 1u << 2, /**< The SMIF chip select 2 */
  128. MTB_SERIAL_MEMORY_CHIP_SELECT_3 = 1u << 3 /**< The SMIF chip select 3 */
  129. } mtb_serial_memory_chip_select_t;
  130. /**
  131. * Serial memory object
  132. *
  133. * Application code should not rely on the specific contents of this struct.
  134. * They are considered an implementation detail which is subject to change
  135. * between releases.
  136. */
  137. typedef struct
  138. {
  139. uint32_t smif_active_slot;
  140. SMIF_Type* base;
  141. const mtb_hal_clock_t* clock;
  142. uint32_t configured_csel;
  143. uint32_t chip_select;
  144. uint32_t status_flags;
  145. cy_stc_smif_mem_context_t* mem_context;
  146. cy_stc_smif_mem_info_t* mem_info;
  147. #if defined(MTB_SERIAL_MEMORY_THREAD_SAFE)
  148. cy_mutex_t mutex;
  149. #endif /* #if defined(MTB_SERIAL_MEMORY_THREAD_SAFE) */
  150. } mtb_serial_memory_t;
  151. /**
  152. * \brief Sets up the serial memory.
  153. *
  154. * \note The function will reset the memory controller when "Auto Detect SFDP"
  155. * is chosen in the "Memory Part Number" section of the QSPI Configurator.
  156. * However, if a specific part number is specified in the QSPI Configurator,
  157. * the responsibility falls to the application to reset the memory controller
  158. * using the Cy_SMIF_Reset_Memory() PDL function. This approach is adopted
  159. * because the mtb_serial_memory_setup() function might be executed from the
  160. * external memory itself, and resetting the memory controller could disrupt
  161. * the communication with the memory.
  162. * This function initializes the slots of the memory device in the SMIF configuration. It's security
  163. * aware and is a wrapper around Cy_SMIF_MemNumInit, and gather all information about the memory
  164. * size, erase and program size to be used in subsequent serial memory calls.
  165. * It can either be called in a secure partition or in the non-secure partition
  166. * if the peripheral itself is not secured.
  167. *
  168. * \param obj Pointer to the mtb_serial_memory_t object to setup
  169. * \param smif_active_chip The slave select line to configure as active
  170. * \param base Pointer to the SMIf base address
  171. * \param clock Pointer to the clock object
  172. * \param mem_context Pointer to the SMIF Device internal context data
  173. * \param mem_info Pointer to the SMIF memory info structure
  174. * \param block_config Pointer to the SMIF block configuration structure
  175. * \returns CY_RSLT_SUCCESS if the setup was successful, an error code
  176. * otherwise.
  177. */
  178. cy_rslt_t mtb_serial_memory_setup(
  179. mtb_serial_memory_t* obj,
  180. mtb_serial_memory_chip_select_t smif_active_chip,
  181. SMIF_Type* base,
  182. const mtb_hal_clock_t* clock,
  183. cy_stc_smif_mem_context_t* mem_context,
  184. cy_stc_smif_mem_info_t* mem_info,
  185. const cy_stc_smif_block_config_t* block_config);
  186. #if !defined(COMPONENT_SECURE_DEVICE)
  187. /**
  188. * \brief Sets up the serial memory on non-secure world if the peripheral is secure
  189. *
  190. * \note This function is to be called from the non secure partition in trustzone
  191. * devices (after the secure one has successfully called \ref mtb_serial_memory_setup )
  192. * to set up the context and gather all information about the memory size,
  193. * erase and program size to be used in subsequent serial memory calls.
  194. *
  195. * \param obj Pointer to the mtb_serial_memory_t object to setup
  196. * \param smif_active_chip The slave select line to configure as active
  197. * \param base Pointer to the SMIf base address
  198. * \param mem_context Pointer to the SMIF Device internal context data
  199. * \param mem_info Pointer to the SMIF memory info structure
  200. * \returns CY_RSLT_SUCCESS if the setup was successful, an error code
  201. * otherwise.
  202. */
  203. cy_rslt_t mtb_serial_memory_setup_nonsecure(
  204. mtb_serial_memory_t* obj,
  205. mtb_serial_memory_chip_select_t smif_active_chip,
  206. SMIF_Type* base,
  207. cy_stc_smif_mem_context_t* mem_context,
  208. cy_stc_smif_mem_info_t* mem_info);
  209. #endif
  210. /**
  211. * \brief Returns the size of the serial memory in bytes.
  212. * \param obj Pointer to the mtb_serial_memory_t object to obtain information from
  213. * \returns Memory size in bytes.
  214. */
  215. size_t mtb_serial_memory_get_size(mtb_serial_memory_t* obj);
  216. /**
  217. * \brief Returns the size of the erase sector to which the given address
  218. * belongs. Address is used only for a memory with hybrid sector size.
  219. * \param obj Pointer to the mtb_serial_memory_t object to obtain information from.
  220. * \param addr Address that belongs to the sector for which size is returned.
  221. * \returns Erase sector size in bytes.
  222. */
  223. size_t mtb_serial_memory_get_erase_size(mtb_serial_memory_t* obj, uint32_t addr);
  224. /**
  225. * \brief Returns the page size for programming of the sector to which the given
  226. * address belongs. Address is used only for a memory with hybrid sector size.
  227. * \param obj Pointer to the mtb_serial_memory_t object to obtain information from.
  228. * \param addr Address that belongs to the sector for which size is returned.
  229. * \returns Page size in bytes.
  230. */
  231. size_t mtb_serial_memory_get_prog_size(mtb_serial_memory_t* obj, uint32_t addr);
  232. /**
  233. * \brief Utility function to calculate the starting address of an erase sector
  234. * to which the given address belongs.
  235. * \param obj Pointer to the mtb_serial_memory_t object to obtain information from.
  236. * \param addr Address in the sector for which the starting address is returned.
  237. * \returns Starting address of the sector
  238. */
  239. __STATIC_INLINE uint32_t mtb_serial_memory_get_sector_start_address(mtb_serial_memory_t* obj,
  240. uint32_t addr)
  241. {
  242. return (addr & ~(mtb_serial_memory_get_erase_size(obj, addr) - 1U));
  243. }
  244. /**
  245. * \brief Reads data from the serial memory. This is a blocking
  246. * function. Returns error if (addr + length) exceeds the memory size.
  247. * If _MTB_SERIAL_MEMORY_EMULATE_BYTE_ADDRESSABLE is set the function can
  248. * emulate byte addressable memories for Octal DDR memories and handle
  249. * one byte reads even at odd addresses.
  250. *
  251. * \param obj Pointer to the mtb_serial_memory_t object to obtain information from.
  252. * \param addr Starting address to read from
  253. * \param length Number of data bytes to read
  254. * \param buf Pointer to the buffer to store the data read from the memory
  255. * \returns CY_RSLT_SUCCESS if the read was successful, an error code otherwise.
  256. */
  257. cy_rslt_t mtb_serial_memory_read(mtb_serial_memory_t* obj, uint32_t addr, size_t length,
  258. uint8_t* buf);
  259. /**
  260. * \brief Writes the data to the serial memory. The program area
  261. * must have been erased prior to calling this API using
  262. * \ref mtb_serial_memory_erase() This is a blocking function. Returns error if
  263. * (addr + length) exceeds the memory size. If _MTB_SERIAL_MEMORY_EMULATE_BYTE_ADDRESSABLE
  264. * is set the function can emulate byte addressable memories for Octal DDR memories
  265. * and handle one byte writes even at odd addresses. This however actually writes starting from
  266. * the previous even address and will always write two bytes.
  267. * \param obj Pointer to the mtb_serial_memory_t object to write to.
  268. * \param addr Starting address to write to
  269. * \param length Number of bytes to write
  270. * \param buf Pointer to the buffer storing the data to be written
  271. * \returns CY_RSLT_SUCCESS if the write was successful, an error code
  272. * otherwise.
  273. */
  274. cy_rslt_t mtb_serial_memory_write(mtb_serial_memory_t* obj, uint32_t addr, size_t length,
  275. const uint8_t* buf);
  276. /**
  277. * \brief Erases the serial memory, uses chip erase command when
  278. * addr = 0 and length = flash_size otherwise uses sector erase command. This is
  279. * a blocking function. Returns error if addr or (addr + length) is not aligned
  280. * to the sector size or if (addr + length) exceeds the memory size.
  281. * For memories with hybrid sectors, returns error if the end address
  282. * (=addr + length) is not aligned to the size of the sector in which the end
  283. * address is located.
  284. * Call \ref mtb_serial_memory_get_size() to get the flash size and
  285. * call \ref mtb_serial_memory_get_erase_size() to get the size of an erase
  286. * sector.
  287. * \param obj Pointer to the mtb_serial_memory_t object to erase.
  288. * \param addr Starting address to begin erasing
  289. * \param length Number of bytes to erase
  290. * \returns CY_RSLT_SUCCESS if the erase was successful, an error code
  291. * otherwise.
  292. */
  293. cy_rslt_t mtb_serial_memory_erase(mtb_serial_memory_t* obj, uint32_t addr, size_t length);
  294. /**
  295. * \brief Enables Execute-in-Place (memory mapped) mode on the MCU. This
  296. * function does not send any command to the serial memory.
  297. * \param obj Pointer to the mtb_serial_memory_t object to enable XIP on.
  298. * \param enable true: XIP mode is set, false: normal mode is set
  299. * \returns CY_RSLT_SUCCESS if the operation was successful.
  300. */
  301. cy_rslt_t mtb_serial_memory_enable_xip(mtb_serial_memory_t* obj, bool enable);
  302. /**
  303. * \brief Sets the active memory device that the serial-flash functions perform
  304. * the operations on.
  305. * \param obj Pointer to the mtb_serial_memory_t object to set active chip for.
  306. * \param chip_select The chip select of the memory device to be set as active.
  307. * \returns The function will return an error if the device had not been setup
  308. * with \ref mtb_serial_memory_setup .
  309. */
  310. cy_rslt_t mtb_serial_memory_set_active_chip(mtb_serial_memory_t* obj,
  311. mtb_serial_memory_chip_select_t chip_select);
  312. /**
  313. * \brief Returns the number of memory devices successfully initialized.
  314. * \param obj Pointer to the mtb_serial_memory_t object to get chip count for.
  315. * \returns Number of memory devices successfully initialized.
  316. */
  317. uint32_t mtb_serial_memory_get_chip_count(mtb_serial_memory_t* obj);
  318. /**
  319. * \brief Returns the active chip select.
  320. * \param obj Pointer to the mtb_serial_memory_t object to get the active chip for.
  321. * \returns Returns the active memory chip.
  322. */
  323. uint32_t mtb_serial_memory_get_active_chip(mtb_serial_memory_t* obj);
  324. /** Send the Write Enable or Write Disable command to the external memory
  325. *
  326. * \param obj Pointer to the mtb_serial_memory_t object to send write
  327. * enable/disable command to.
  328. * \param enable if true the command to be sent is Write Enable, if false the
  329. * command to be sent is Write Disable.
  330. * \returns CY_RSLT_SUCCESS if the operation was successful, an error code
  331. * therwise.
  332. */
  333. cy_rslt_t mtb_serial_memory_set_write_enable(mtb_serial_memory_t* obj, bool enable);
  334. #if defined(__cplusplus)
  335. }
  336. #endif
  337. #endif // CY_IP_MXSMIF
  338. /** \} group_board_libs */