1 /***************************************************************************//**
2 * \file cyhal_nvm.c
3 *
4 * Description:
5 * Provides a high level interface for interacting with the Infineon embedded
6 * non-volatile memory (NVM). This is wrapper around the lower level PDL API.
7 *
8 ********************************************************************************
9 * \copyright
10 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
11 * an affiliate of Cypress Semiconductor Corporation
12 *
13 * SPDX-License-Identifier: Apache-2.0
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 *******************************************************************************/
27
28 #include "cyhal_hwmgr.h"
29 #include "cyhal_hw_types.h"
30 #include "cyhal_nvm.h"
31 #include "cy_utils.h"
32 #include "cyhal_syspm.h"
33 #include "cyhal_utils_impl.h"
34 #include "cyhal_irq_impl.h"
35 #include <string.h>
36
37 #if (CYHAL_DRIVER_AVAILABLE_FLASH)
38 #include "cyhal_flash.h"
39 #endif /* (CYHAL_DRIVER_AVAILABLE_FLASH) */
40
41
42 #if (CYHAL_DRIVER_AVAILABLE_NVM)
43
44 #if defined(__cplusplus)
45 extern "C" {
46 #endif /* __cplusplus */
47
48 #if (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
49 static uint16_t _cyhal_nvm_init_count = 0;
50 typedef cy_en_flashdrv_status_t (*_cyhal_flash_operation)(uint32_t rowAddr, const uint32_t* data);
51
52 static bool _cyhal_flash_pm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void* callback_arg);
53
54 #if defined(CPUSS_FLASHC_ECT)
55 #define _CYHAL_USES_ECT_FLASH (CPUSS_FLASHC_ECT == 1)
56 #else
57 #define _CYHAL_USES_ECT_FLASH (0u)
58 #endif
59
60 #if (_CYHAL_USES_ECT_FLASH)
61 #define _CYHAL_INTERNAL_FLASH_MEMORY_BLOCKS (4u)
62 #elif (CY_EM_EEPROM_SIZE > 0)
63 #define _CYHAL_INTERNAL_FLASH_MEMORY_BLOCKS (2u)
64 #else
65 #define _CYHAL_INTERNAL_FLASH_MEMORY_BLOCKS (1u)
66 #endif
67
68 static bool _cyhal_flash_pending_pm_change = false;
69
70 static cyhal_syspm_callback_data_t _cyhal_flash_internal_pm_cb = {
71 .callback = _cyhal_flash_pm_callback,
72 .states = (cyhal_syspm_callback_state_t)(CYHAL_SYSPM_CB_CPU_SLEEP | CYHAL_SYSPM_CB_CPU_DEEPSLEEP | CYHAL_SYSPM_CB_CPU_DEEPSLEEP_RAM | CYHAL_SYSPM_CB_SYSTEM_HIBERNATE | CYHAL_SYSPM_CB_SYSTEM_LOW),
73 .next = NULL,
74 .args = NULL,
75 .ignore_modes = (cyhal_syspm_callback_mode_t)(CYHAL_SYSPM_AFTER_DS_WFI_TRANSITION),
76 };
77
_cyhal_flash_convert_status(uint32_t pdl_status)78 static inline cy_rslt_t _cyhal_flash_convert_status(uint32_t pdl_status)
79 {
80 return (pdl_status == CY_FLASH_DRV_OPERATION_STARTED) ? CY_RSLT_SUCCESS : pdl_status;
81 }
82
83 #if defined(CY_IP_S8SRSSLT) && CY_FLASH_NON_BLOCKING_SUPPORTED
_cyhal_flash_irq_handler(void)84 static void _cyhal_flash_irq_handler(void)
85 {
86 (void) Cy_Flash_ResumeWrite();
87 }
88 #endif
89
_cyhal_flash_pm_callback(cyhal_syspm_callback_state_t state,cyhal_syspm_callback_mode_t mode,void * callback_arg)90 static bool _cyhal_flash_pm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void* callback_arg)
91 {
92 CY_UNUSED_PARAMETER(state);
93 CY_UNUSED_PARAMETER(callback_arg);
94 bool allow = true;
95
96 switch (mode)
97 {
98 case CYHAL_SYSPM_CHECK_READY:
99 _cyhal_flash_pending_pm_change = true;
100 #if defined(CY_IP_MXS40SRSS) || (_CYHAL_USES_ECT_FLASH) || CY_FLASH_NON_BLOCKING_SUPPORTED
101 if (CY_RSLT_SUCCESS != Cy_Flash_IsOperationComplete())
102 {
103 #if (_CYHAL_USES_ECT_FLASH)
104 /* The SROM API response is invalid unless a flash operation has occurred at least once.
105 Therefore allow that case as an exception. */
106 un_srom_api_resps_t resp = {{ 0UL }};
107 cy_en_srom_api_status_t status = Cy_Srom_GetApiResponse(&resp);
108 if(CY_SROM_STATUS_INVALID != status)
109 #endif
110 {
111 _cyhal_flash_pending_pm_change = false;
112 allow = false;
113 }
114 }
115 #endif
116 break;
117 case CYHAL_SYSPM_BEFORE_TRANSITION:
118 case CYHAL_SYSPM_AFTER_TRANSITION:
119 case CYHAL_SYSPM_CHECK_FAIL:
120 _cyhal_flash_pending_pm_change = false;
121 break;
122 default:
123 /* Don't care */
124 break;
125 }
126
127 return allow;
128 }
129
_cyhal_flash_is_sram_address(uint32_t address)130 static inline bool _cyhal_flash_is_sram_address(uint32_t address)
131 {
132 return ((CY_SRAM_BASE <= address) && (address < (CY_SRAM_BASE + CY_SRAM_SIZE)));
133 }
134
_cyhal_flash_run_operation(_cyhal_flash_operation operation,uint32_t address,const uint32_t * data,bool clearCache)135 static cy_rslt_t _cyhal_flash_run_operation(
136 _cyhal_flash_operation operation, uint32_t address, const uint32_t* data, bool clearCache)
137 {
138 cy_rslt_t status;
139 if (_cyhal_flash_pending_pm_change)
140 status = CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
141 else
142 {
143 status = (_cyhal_flash_is_sram_address((uint32_t)data))
144 ? (cy_rslt_t)_cyhal_flash_convert_status((cy_rslt_t)operation(address, data))
145 : CYHAL_NVM_RSLT_ERR_ADDRESS;
146 #if defined(CY_IP_M7CPUSS) /* PDL automatically clears cache when necessary in M7 devices */
147 CY_UNUSED_PARAMETER(clearCache);
148 #else
149 if (clearCache)
150 {
151 Cy_SysLib_ClearFlashCacheAndBuffer();
152 }
153 #endif
154 }
155
156 return status;
157 }
158
159 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
160
161 #if (_CYHAL_DRIVER_AVAILABLE_NVM_OTP)
162
163 #if (CY_RRAM_PROTECTED_OTP_SIZE > 0) && (CY_RRAM_GENERAL_OTP_SIZE > 0)
164 #define _CYHAL_INTERNAL_OTP_MEMORY_BLOCKS (2u)
165 #else
166 #define _CYHAL_INTERNAL_OTP_MEMORY_BLOCKS (1u)
167 #endif
168
169 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_OTP) */
170
171 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
172
173 enum {
174 #if (CY_RRAM_WORK_REGION_SIZE > 0)
175 _CYHAL_RRAM_WORK_REGION,
176 #endif
177 #if (CY_RRAM_SFLASH_REGION_SIZE > 0)
178 _CYHAL_RRAM_SFLASH_REGION,
179 #endif
180 #if (CY_RRAM_PROTECTED_REGION_SIZE > 0)
181 _CYHAL_RRAM_PROTECTED_REGION,
182 #endif
183 #if (CY_RRAM_MAIN_REGION_SIZE > 0)
184 _CYHAL_RRAM_MAIN_REGION,
185 #endif
186 _CYHAL_RRAM_REGION_COUNT
187 } _cyhal_rram_regions_count;
188
189 #define _CYHAL_INTERNAL_RRAM_MEMORY_BLOCKS (_CYHAL_RRAM_REGION_COUNT)
190
_cyhal_rram_is_busy()191 __STATIC_INLINE bool _cyhal_rram_is_busy()
192 {
193 return (bool)_FLD2VAL(RRAMC_RRAM_SFR_NVM_STATUS_BUSY, RRAM_NVM_STATUS(RRAMC0));
194 }
195
196 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
197
198
199 #ifndef _CYHAL_INTERNAL_FLASH_MEMORY_BLOCKS
200 #define _CYHAL_INTERNAL_FLASH_MEMORY_BLOCKS (0)
201 #endif /* (_CYHAL_INTERNAL_FLASH_MEMORY_BLOCKS) */
202
203 #ifndef _CYHAL_INTERNAL_RRAM_MEMORY_BLOCKS
204 #define _CYHAL_INTERNAL_RRAM_MEMORY_BLOCKS (0)
205 #endif /* (_CYHAL_INTERNAL_RRAM_MEMORY_BLOCKS) */
206
207 #ifndef _CYHAL_INTERNAL_OTP_MEMORY_BLOCKS
208 #define _CYHAL_INTERNAL_OTP_MEMORY_BLOCKS (0)
209 #endif /* (_CYHAL_INTERNAL_OTP_MEMORY_BLOCKS) */
210
211
212 #define _CYHAL_NVM_MEMORY_BLOCKS_COUNT (_CYHAL_INTERNAL_FLASH_MEMORY_BLOCKS + \
213 _CYHAL_INTERNAL_RRAM_MEMORY_BLOCKS + \
214 _CYHAL_INTERNAL_OTP_MEMORY_BLOCKS)
215
216
217 static const cyhal_nvm_region_info_t _cyhal_nvm_mem_regions[_CYHAL_NVM_MEMORY_BLOCKS_COUNT] = {
218 #if (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
219 #if _CYHAL_USES_ECT_FLASH
220 /* Each flash area is divided into two regions: A "large" region with 2KB sectors and a
221 * "small" region with 128b sectors. The flash can be configured in either single- or
222 * double-bank mode. In double-bank mode, the flash is divided into two sub-regions such
223 * that it is possible to read from one region while writing to another region. Because
224 * dual-bank mode is highly device specific, for simplicity we stick to single-bank mode
225 * in the portable HAL driver */
226 // Large main flash region, 32KB sectors
227 {
228 .nvm_type = CYHAL_NVM_TYPE_FLASH,
229 .start_address = CY_FLASH_LG_SBM_BASE,
230 .size = CY_FLASH_LG_SBM_SIZE,
231 .sector_size = 32768u,
232 .block_size = 8u,
233 .is_erase_required = true,
234 .erase_value = 0xFFU,
235 },
236 // Small main flash region, 8KB sectors
237 {
238 .nvm_type = CYHAL_NVM_TYPE_FLASH,
239 .start_address = CY_FLASH_SM_SBM_BASE,
240 .size = CY_FLASH_SM_SBM_SIZE,
241 .sector_size = 8192u,
242 .block_size = 8u,
243 .is_erase_required = true,
244 .erase_value = 0xFFU,
245 },
246 // Large wflash region, 32KB sectors
247 {
248 .nvm_type = CYHAL_NVM_TYPE_FLASH,
249 .start_address = CY_WFLASH_LG_SBM_BASE,
250 .size = CY_WFLASH_LG_SBM_SIZE,
251 .sector_size = 2048u, /* Hard-coded in the IP */
252 .block_size = 4u,
253 .is_erase_required = true,
254 .erase_value = 0xFFU,
255 },
256 // Small wflash region, 128B sectors
257 {
258 .nvm_type = CYHAL_NVM_TYPE_FLASH,
259 .start_address = CY_WFLASH_SM_SBM_BASE,
260 .size = CY_WFLASH_SM_SBM_SIZE,
261 .sector_size = 128u,
262 .block_size = 4u,
263 .is_erase_required = true,
264 .erase_value = 0xFFU,
265 },
266 #else
267 // Main Flash
268 {
269 .nvm_type = CYHAL_NVM_TYPE_FLASH,
270 .start_address = CY_FLASH_BASE,
271 .size = CY_FLASH_SIZE,
272 .sector_size = CY_FLASH_SIZEOF_ROW,
273 .block_size = CY_FLASH_SIZEOF_ROW,
274 .is_erase_required = true,
275 .erase_value = 0x00U,
276 },
277 // Working Flash
278 #if (CY_EM_EEPROM_SIZE > 0)
279 {
280 .nvm_type = CYHAL_NVM_TYPE_FLASH,
281 .start_address = CY_EM_EEPROM_BASE,
282 .size = CY_EM_EEPROM_SIZE,
283 .sector_size = CY_FLASH_SIZEOF_ROW,
284 .block_size = CY_FLASH_SIZEOF_ROW,
285 .is_erase_required = true,
286 .erase_value = 0x00U,
287 },
288 #endif
289 #endif /* CY_IP_M7CPUSS or other */
290 #endif /* (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
291
292 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
293 #if (CY_RRAM_MAIN_REGION_SIZE > 0)
294 // Main RRAM region, 8KB sectors
295 {
296 .nvm_type = CYHAL_NVM_TYPE_RRAM,
297 .start_address = CY_RRAM_MAIN_HOST_NS_START_ADDRESS,
298 .size = CY_RRAM_MAIN_REGION_SIZE,
299 .sector_size = CY_RRAM_REGION_SIZE_UNIT,
300 .block_size = CY_RRAM_BLOCK_SIZE_BYTES,
301 .is_erase_required = false,
302 .erase_value = 0x00U,
303 },
304 #endif /* (CY_RRAM_MAIN_REGION_SIZE > 0) */
305 #if (CY_RRAM_WORK_REGION_SIZE > 0)
306 // Work RRAM region, 8KB sectors
307 {
308 .nvm_type = CYHAL_NVM_TYPE_RRAM,
309 .start_address = CY_RRAM_WORK_HOST_NS_START_ADDRESS,
310 .size = CY_RRAM_WORK_REGION_SIZE,
311 .sector_size = CY_RRAM_REGION_SIZE_UNIT,
312 .block_size = CY_RRAM_BLOCK_SIZE_BYTES,
313 .is_erase_required = false,
314 .erase_value = 0x00U,
315 },
316 #endif /* (CY_RRAM_WORK_REGION_SIZE > 0) */
317 #if (CY_RRAM_SFLASH_REGION_SIZE > 0)
318 // SFALSH RRAM region, 8KB sectors
319 {
320 .nvm_type = CYHAL_NVM_TYPE_RRAM,
321 .start_address = CY_RRAM_SFLASH_HOST_NS_START_ADDRESS,
322 .size = CY_RRAM_SFLASH_REGION_SIZE,
323 .sector_size = CY_RRAM_REGION_SIZE_UNIT,
324 .block_size = CY_RRAM_BLOCK_SIZE_BYTES,
325 .is_erase_required = false,
326 .erase_value = 0x00U,
327 },
328 #endif /* (CY_RRAM_SFLASH_REGION_SIZE > 0) */
329 #if (CY_RRAM_PROTECTED_REGION_SIZE > 0)
330 // SFALSH RRAM region, 8KB sectors
331 {
332 .nvm_type = CYHAL_NVM_TYPE_RRAM,
333 .start_address = CY_RRAM_PROTECTED_HOST_NS_START_ADDRESS,
334 .size = CY_RRAM_PROTECTED_REGION_SIZE,
335 .sector_size = CY_RRAM_REGION_SIZE_UNIT,
336 .block_size = CY_RRAM_BLOCK_SIZE_BYTES,
337 .is_erase_required = false,
338 .erase_value = 0x00U,
339 },
340 #endif /* (CY_RRAM_PROTECTED_REGION_SIZE > 0) */
341 #endif /* (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
342
343 #if (_CYHAL_DRIVER_AVAILABLE_NVM_OTP)
344 #if (CY_RRAM_GENERAL_OTP_SIZE > 0)
345 // General RRAM OTP region, 5.5KB sector
346 {
347 .nvm_type = CYHAL_NVM_TYPE_OTP,
348 .start_address = CY_RRAM_GENERAL_OTP_MMIO_NS_START_ADDRESS,
349 .size = CY_RRAM_GENERAL_OTP_SIZE,
350 .sector_size = 5632u,
351 .block_size = CY_RRAM_BLOCK_SIZE_BYTES,
352 .is_erase_required = false,
353 .erase_value = 0xFFU,
354 },
355 #endif /* (CY_RRAM_GENERAL_OTP_SIZE > 0) */
356 #if (CY_RRAM_PROTECTED_OTP_SIZE > 0)
357 // Protected RRAM OTP region, 8KB sector
358 {
359 .nvm_type = CYHAL_NVM_TYPE_OTP,
360 .start_address = CY_RRAM_PROTECTED_OTP_PROTECTED_NS_START_ADDRESS,
361 .size = CY_RRAM_PROTECTED_OTP_SIZE,
362 .sector_size = 8192u,
363 .block_size = CY_RRAM_BLOCK_SIZE_BYTES,
364 .is_erase_required = false,
365 .erase_value = 0xFFU,
366 },
367 #endif /* (CY_RRAM_PROTECTED_OTP_SIZE > 0) */
368 #endif /* (_CYHAL_DRIVER_AVAILABLE_NVM_OTP) */
369 };
370
371
_cyhal_nvm_address_in_region(uint32_t address,const cyhal_nvm_region_info_t * region_info)372 static inline bool _cyhal_nvm_address_in_region(uint32_t address, const cyhal_nvm_region_info_t* region_info)
373 {
374 return (address >= region_info->start_address && address < (region_info->start_address + region_info->size));
375 }
376
_cyhal_nvm_get_nvm_region_by_boundaries(uint32_t start_address,uint32_t end_address,cyhal_nvm_region_info_t * block_info)377 static bool _cyhal_nvm_get_nvm_region_by_boundaries(uint32_t start_address, uint32_t end_address, cyhal_nvm_region_info_t *block_info)
378 {
379 bool start_address_valid = false;
380 bool end_address_valid = false;
381 bool end_address_check_need = (end_address == 0) ? false : true;
382 memset(block_info, 0, sizeof(*block_info));
383
384 for (uint32_t region_id = 0; region_id < _CYHAL_NVM_MEMORY_BLOCKS_COUNT; region_id++)
385 {
386 start_address_valid = _cyhal_nvm_address_in_region(start_address, &_cyhal_nvm_mem_regions[region_id]);
387 end_address_valid = (!end_address_check_need) ? true :
388 _cyhal_nvm_address_in_region(end_address, &_cyhal_nvm_mem_regions[region_id]);
389 if (start_address_valid && end_address_valid)
390 {
391 *block_info = _cyhal_nvm_mem_regions[region_id];
392 block_info->offset = start_address - _cyhal_nvm_mem_regions[region_id].start_address;
393 break;
394 }
395 }
396
397 return (start_address_valid && end_address_valid);
398 }
399
_cyhal_nvm_get_nvm_region_by_address(uint32_t address,cyhal_nvm_region_info_t * region_info)400 static inline bool _cyhal_nvm_get_nvm_region_by_address(uint32_t address, cyhal_nvm_region_info_t *region_info)
401 {
402 return _cyhal_nvm_get_nvm_region_by_boundaries(address, 0, region_info);
403 }
404
405 /*******************************************************************************
406 * Functions
407 *******************************************************************************/
408
cyhal_nvm_init(cyhal_nvm_t * obj)409 cy_rslt_t cyhal_nvm_init(cyhal_nvm_t *obj)
410 {
411 CY_ASSERT(NULL != obj);
412 CY_UNUSED_PARAMETER(obj);
413
414 cy_rslt_t status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
415
416 #if (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
417 #if defined(CY_IP_S8SRSSLT) && CY_FLASH_NON_BLOCKING_SUPPORTED
418 /* Configure Flash interrupt */
419 _cyhal_irq_register(cpuss_interrupt_spcif_IRQn, 0u, &_cyhal_flash_irq_handler);
420 _cyhal_irq_enable(cpuss_interrupt_spcif_IRQn);
421 #endif /* defined(CY_IP_S8SRSSLT) && CY_FLASH_NON_BLOCKING_SUPPORTED */
422 if(_cyhal_nvm_init_count == 0)
423 {
424 #if _CYHAL_USES_ECT_FLASH
425 // Cy_Flash_Init is only safe to call a single time after the SysPm HAL
426 // has been initialized (or anything else in the application has registered
427 // a callback). It unconditionally re-initializes its callback struct each
428 // time, which would remove any callbacks registered with lower priority.
429 static bool flash_initialized = false;
430 if(false == flash_initialized)
431 {
432 flash_initialized = true;
433 Cy_Flash_Init();
434 }
435 // Always call this, because `cyhal_nvm_free` disables the work flash write
436 Cy_Flashc_WorkWriteEnable();
437 #endif /* _CYHAL_USES_ECT_FLASH */
438 _cyhal_syspm_register_peripheral_callback(&_cyhal_flash_internal_pm_cb);
439 }
440 _cyhal_nvm_init_count++;
441 status = CY_RSLT_SUCCESS;
442 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
443
444 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
445 /* Nothing to do for RRAM initialization */
446 status = CY_RSLT_SUCCESS;
447 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
448
449 #if (_CYHAL_DRIVER_AVAILABLE_NVM_OTP)
450 /* Nothing to do for RRAM initialization */
451 status = CY_RSLT_SUCCESS;
452 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_OTP) */
453
454 return status;
455 }
456
cyhal_nvm_free(cyhal_nvm_t * obj)457 void cyhal_nvm_free(cyhal_nvm_t *obj)
458 {
459 CY_ASSERT(NULL != obj);
460 CY_UNUSED_PARAMETER(obj);
461
462 #if (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
463 #if defined(CY_IP_S8SRSSLT) && CY_FLASH_NON_BLOCKING_SUPPORTED
464 _cyhal_irq_free(cpuss_interrupt_spcif_IRQn);
465 #endif /* defined(CY_IP_S8SRSSLT) && CY_FLASH_NON_BLOCKING_SUPPORTED */
466 CY_ASSERT(_cyhal_nvm_init_count > 0);
467 _cyhal_nvm_init_count--;
468 if(_cyhal_nvm_init_count == 0)
469 {
470 _cyhal_syspm_unregister_peripheral_callback(&_cyhal_flash_internal_pm_cb);
471 #if _CYHAL_USES_ECT_FLASH
472 Cy_Flashc_WorkWriteDisable();
473 #endif /* _CYHAL_USES_ECT_FLASH */
474 }
475 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
476
477 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
478 /* Nothing to do for RRAM deinitialization */
479 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
480
481 #if (_CYHAL_DRIVER_AVAILABLE_NVM_OTP)
482 /* Nothing to do for OTP deinitialization */
483 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_OTP) */
484 }
485
cyhal_nvm_get_info(cyhal_nvm_t * obj,cyhal_nvm_info_t * info)486 void cyhal_nvm_get_info(cyhal_nvm_t *obj, cyhal_nvm_info_t *info)
487 {
488 CY_ASSERT(NULL != obj);
489 CY_ASSERT(NULL != info);
490 CY_UNUSED_PARAMETER(obj);
491
492 info->region_count = _CYHAL_NVM_MEMORY_BLOCKS_COUNT;
493 info->regions = &_cyhal_nvm_mem_regions[0];
494 }
495
cyhal_nvm_read(cyhal_nvm_t * obj,uint32_t address,uint8_t * data,size_t size)496 cy_rslt_t cyhal_nvm_read(cyhal_nvm_t *obj, uint32_t address, uint8_t *data, size_t size)
497 {
498 CY_ASSERT(NULL != obj);
499 CY_UNUSED_PARAMETER(obj);
500
501 cyhal_nvm_region_info_t _cyhal_nvm_current_block_info;
502 cy_rslt_t status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
503
504 bool is_address_valid = false;
505 is_address_valid = _cyhal_nvm_get_nvm_region_by_boundaries(address, (address + size - 1), &_cyhal_nvm_current_block_info);
506
507 if (!is_address_valid)
508 {
509 status = CYHAL_NVM_RSLT_ERR_ADDRESS;
510 }
511 else
512 {
513 if (CYHAL_NVM_TYPE_FLASH == _cyhal_nvm_current_block_info.nvm_type)
514 {
515 #if (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
516 memcpy((void *)data, (void *)address, size);
517 status = CY_RSLT_SUCCESS;
518 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
519 }
520 else if (CYHAL_NVM_TYPE_RRAM == _cyhal_nvm_current_block_info.nvm_type)
521 {
522 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
523 status = (cy_rslt_t)Cy_RRAM_NvmReadByteArray(RRAMC0, address, data, size);
524 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
525 }
526 else if (CYHAL_NVM_TYPE_OTP == _cyhal_nvm_current_block_info.nvm_type)
527 {
528 #if (_CYHAL_DRIVER_AVAILABLE_NVM_OTP)
529 status = (cy_rslt_t)Cy_RRAM_OtpReadByteArray(RRAMC0, address, data, size);
530 #endif /* (_CYHAL_DRIVER_AVAILABLE_NVM_OTP) */
531 }
532 else
533 {
534 /* Not supported type of NVM */
535 CY_UNUSED_PARAMETER(address);
536 CY_UNUSED_PARAMETER(data);
537 CY_UNUSED_PARAMETER(size);
538 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
539 }
540 }
541 return status;
542 }
543
cyhal_nvm_erase(cyhal_nvm_t * obj,uint32_t address)544 cy_rslt_t cyhal_nvm_erase(cyhal_nvm_t *obj, uint32_t address)
545 {
546 CY_ASSERT(NULL != obj);
547 CY_UNUSED_PARAMETER(obj);
548
549 cyhal_nvm_region_info_t _cyhal_nvm_current_block_info;
550 cy_rslt_t status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
551
552 bool is_address_valid = false;
553 is_address_valid = _cyhal_nvm_get_nvm_region_by_address(address, &_cyhal_nvm_current_block_info);
554
555 if (!is_address_valid)
556 {
557 status = CYHAL_NVM_RSLT_ERR_ADDRESS;
558 }
559 else
560 {
561 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
562 SCB_InvalidateDCache_by_Addr((void *)address, _cyhal_nvm_current_block_info.sector_size);
563 #endif
564 if (CYHAL_NVM_TYPE_FLASH == _cyhal_nvm_current_block_info.nvm_type)
565 {
566 #if (defined(CY_IP_MXS40SRSS) || (_CYHAL_USES_ECT_FLASH)) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
567 if (_cyhal_flash_pending_pm_change)
568 {
569 status = CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
570 }
571 else
572 {
573 #if (_CYHAL_USES_ECT_FLASH)
574 /* This IP does not support row-at-a-time erase */
575 status = (cy_rslt_t)_cyhal_flash_convert_status(Cy_Flash_EraseSector(address));
576 #else
577 status = (cy_rslt_t)_cyhal_flash_convert_status(Cy_Flash_EraseRow(address));
578 #endif
579
580 #if !defined(CY_IP_M7CPUSS)
581 Cy_SysLib_ClearFlashCacheAndBuffer();
582 #endif
583 /* PDL automatically clears cache when necessary in M7 devices */
584 }
585 #else
586 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
587 #endif /* (defined(CY_IP_MXS40SRSS) || (_CYHAL_USES_ECT_FLASH)) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
588 }
589 else if (CYHAL_NVM_TYPE_RRAM == _cyhal_nvm_current_block_info.nvm_type)
590 {
591 /* Erase operation not needed for RRAM */
592 status = CY_RSLT_SUCCESS;
593 }
594 else if (CYHAL_NVM_TYPE_OTP == _cyhal_nvm_current_block_info.nvm_type)
595 {
596 /* Not supported for OTP */
597 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
598 }
599 else
600 {
601 /* Not supported type of NVM */
602 CY_UNUSED_PARAMETER(address);
603 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
604 }
605 }
606 return status;
607 }
608
cyhal_nvm_write(cyhal_nvm_t * obj,uint32_t address,const uint32_t * data)609 cy_rslt_t cyhal_nvm_write(cyhal_nvm_t *obj, uint32_t address, const uint32_t* data)
610 {
611 CY_ASSERT(NULL != obj);
612 CY_UNUSED_PARAMETER(obj);
613
614 cyhal_nvm_region_info_t _cyhal_nvm_current_block_info;
615 cy_rslt_t status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
616
617 bool is_address_valid = false;
618 is_address_valid = _cyhal_nvm_get_nvm_region_by_address(address, &_cyhal_nvm_current_block_info);
619
620 if (!is_address_valid)
621 {
622 status = CYHAL_NVM_RSLT_ERR_ADDRESS;
623 }
624 else
625 {
626 if (CYHAL_NVM_TYPE_FLASH == _cyhal_nvm_current_block_info.nvm_type)
627 {
628 #if !(_CYHAL_USES_ECT_FLASH) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
629 status = _cyhal_flash_run_operation(Cy_Flash_WriteRow, address, data, true);
630 #else
631 /* CY_IP_M7CPUSS does not support a bundled write (erase + program) operation. Instead,
632 * it is necessary to perform an erase operation followed by a program operation.
633 */
634 CY_UNUSED_PARAMETER(address);
635 CY_UNUSED_PARAMETER(data);
636 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
637 #endif /* !(_CYHAL_USES_ECT_FLASH) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
638 }
639 else if (CYHAL_NVM_TYPE_RRAM == _cyhal_nvm_current_block_info.nvm_type)
640 {
641 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
642 status = (cy_rslt_t)Cy_RRAM_NvmWriteBlock(RRAMC0, address, (uint8_t *)data);
643 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
644 }
645 else if (CYHAL_NVM_TYPE_OTP == _cyhal_nvm_current_block_info.nvm_type)
646 {
647 /* Not supported for OTP */
648 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
649 }
650 else
651 {
652 /* Not supported type of NVM */
653 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
654 }
655 }
656 return status;
657 }
658
cyhal_nvm_otp_write(cyhal_nvm_t * obj,uint32_t address,uint8_t data)659 cy_rslt_t cyhal_nvm_otp_write(cyhal_nvm_t* obj, uint32_t address, uint8_t data)
660 {
661 CY_ASSERT(NULL != obj);
662 CY_UNUSED_PARAMETER(obj);
663
664 cyhal_nvm_region_info_t _cyhal_nvm_current_block_info;
665 cy_rslt_t status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
666
667 bool is_address_valid = false;
668 is_address_valid = _cyhal_nvm_get_nvm_region_by_address(address, &_cyhal_nvm_current_block_info);
669
670 if (!is_address_valid)
671 {
672 status = CYHAL_NVM_RSLT_ERR_ADDRESS;
673 }
674 else
675 {
676 if (CYHAL_NVM_TYPE_OTP == _cyhal_nvm_current_block_info.nvm_type)
677 {
678 #if (_CYHAL_DRIVER_AVAILABLE_NVM_OTP)
679 status = (cy_rslt_t)Cy_RRAM_OtpWriteByteArray(RRAMC0, address, (const uint8_t *)&data, 1UL);
680 #endif /* (_CYHAL_DRIVER_AVAILABLE_NVM_OTP) */
681 }
682 else
683 {
684 /* Not supported type of NVM */
685 CY_UNUSED_PARAMETER(data);
686 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
687 }
688 }
689 return status;
690 }
691
cyhal_nvm_program(cyhal_nvm_t * obj,uint32_t address,const uint32_t * data)692 cy_rslt_t cyhal_nvm_program(cyhal_nvm_t *obj, uint32_t address, const uint32_t *data)
693 {
694 CY_ASSERT(NULL != obj);
695 CY_UNUSED_PARAMETER(obj);
696
697 cyhal_nvm_region_info_t _cyhal_nvm_current_block_info;
698 cy_rslt_t status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
699
700 bool is_address_valid = false;
701 is_address_valid = _cyhal_nvm_get_nvm_region_by_address(address, &_cyhal_nvm_current_block_info);
702
703 if (!is_address_valid)
704 {
705 status = CYHAL_NVM_RSLT_ERR_ADDRESS;
706 }
707 else
708 {
709 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
710 SCB_CleanDCache_by_Addr((void *)data, _cyhal_nvm_current_block_info.block_size);
711 SCB_InvalidateDCache_by_Addr((void *)address, _cyhal_nvm_current_block_info.block_size);
712 #endif
713 if (CYHAL_NVM_TYPE_FLASH == _cyhal_nvm_current_block_info.nvm_type)
714 {
715 #if (defined(CY_IP_MXS40SRSS) || (_CYHAL_USES_ECT_FLASH)) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
716 status = _cyhal_flash_run_operation(Cy_Flash_ProgramRow, address, data, true);
717 #endif /* (defined(CY_IP_MXS40SRSS) || (_CYHAL_USES_ECT_FLASH)) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
718 }
719 else if (CYHAL_NVM_TYPE_RRAM == _cyhal_nvm_current_block_info.nvm_type)
720 {
721 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
722 status = (cy_rslt_t)Cy_RRAM_NvmWriteBlock(RRAMC0, address, (uint8_t *)data);
723 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
724 }
725 else if (CYHAL_NVM_TYPE_OTP == _cyhal_nvm_current_block_info.nvm_type)
726 {
727 /* Not supported for OTP */
728 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
729 }
730 else
731 {
732 /* Not supported type of NVM */
733 CY_UNUSED_PARAMETER(address);
734 CY_UNUSED_PARAMETER(data);
735 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
736 }
737 }
738 return status;
739 }
740
cyhal_nvm_start_erase(cyhal_nvm_t * obj,uint32_t address)741 cy_rslt_t cyhal_nvm_start_erase(cyhal_nvm_t *obj, uint32_t address)
742 {
743 CY_ASSERT(NULL != obj);
744 CY_UNUSED_PARAMETER(obj);
745
746 cyhal_nvm_region_info_t _cyhal_nvm_current_block_info;
747 cy_rslt_t status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
748
749 bool is_address_valid = false;
750 is_address_valid = _cyhal_nvm_get_nvm_region_by_address(address, &_cyhal_nvm_current_block_info);
751
752 if (!is_address_valid)
753 {
754 status = CYHAL_NVM_RSLT_ERR_ADDRESS;
755 }
756 else
757 {
758 if (CYHAL_NVM_TYPE_FLASH == _cyhal_nvm_current_block_info.nvm_type)
759 {
760 #if defined(CY_IP_MXS40SRSS) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
761 if (_cyhal_flash_pending_pm_change)
762 {
763 status = CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
764 }
765 else
766 {
767 status = (cy_rslt_t)_cyhal_flash_convert_status(
768 #if _CYHAL_USES_ECT_FLASH
769 Cy_Flash_StartEraseSector(address)
770 #else
771 Cy_Flash_StartEraseRow(address)
772 #endif
773 );
774 }
775 #endif /* defined(CY_IP_MXS40SRSS) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
776 }
777 else if (CYHAL_NVM_TYPE_RRAM == _cyhal_nvm_current_block_info.nvm_type)
778 {
779 /* Erase operation not needed for RRAM */
780 status = CY_RSLT_SUCCESS;
781 }
782 else if (CYHAL_NVM_TYPE_OTP == _cyhal_nvm_current_block_info.nvm_type)
783 {
784 /* Not supported for OTP */
785 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
786 }
787 else
788 {
789 /* Not supported type of NVM */
790 CY_UNUSED_PARAMETER(address);
791 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
792 }
793 }
794 return status;
795 }
796
cyhal_nvm_start_write(cyhal_nvm_t * obj,uint32_t address,const uint32_t * data)797 cy_rslt_t cyhal_nvm_start_write(cyhal_nvm_t *obj, uint32_t address, const uint32_t* data)
798 {
799 CY_ASSERT(NULL != obj);
800 CY_UNUSED_PARAMETER(obj);
801
802 cyhal_nvm_region_info_t _cyhal_nvm_current_block_info;
803 cy_rslt_t status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
804
805 bool is_address_valid = false;
806 is_address_valid = _cyhal_nvm_get_nvm_region_by_address(address, &_cyhal_nvm_current_block_info);
807
808 if (!is_address_valid)
809 {
810 status = CYHAL_NVM_RSLT_ERR_ADDRESS;
811 }
812 else
813 {
814 if (CYHAL_NVM_TYPE_FLASH == _cyhal_nvm_current_block_info.nvm_type)
815 {
816 /* M7CPUSS does not support write, only erase + program */
817 #if ((defined(CY_IP_MXS40SRSS) && !(_CYHAL_USES_ECT_FLASH)) || CY_FLASH_NON_BLOCKING_SUPPORTED) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
818 status = _cyhal_flash_run_operation(Cy_Flash_StartWrite, address, data, false);
819 #else
820 CY_UNUSED_PARAMETER(address);
821 CY_UNUSED_PARAMETER(data);
822 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
823 #endif /* ((defined(CY_IP_MXS40SRSS) && !(_CYHAL_USES_ECT_FLASH)) || CY_FLASH_NON_BLOCKING_SUPPORTED) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)*/
824 }
825 else if (CYHAL_NVM_TYPE_RRAM == _cyhal_nvm_current_block_info.nvm_type)
826 {
827 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
828 status = (cy_rslt_t)Cy_RRAM_NonBlockingNvmWriteByteArray(
829 RRAMC0, address, (const uint8_t *)data, _cyhal_nvm_current_block_info.block_size);
830 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
831 }
832 else if (CYHAL_NVM_TYPE_OTP == _cyhal_nvm_current_block_info.nvm_type)
833 {
834 /* Not supported for OTP */
835 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
836 }
837 else
838 {
839 /* Not supported type of NVM */
840 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
841 }
842 }
843 return status;
844 }
845
cyhal_nvm_start_program(cyhal_nvm_t * obj,uint32_t address,const uint32_t * data)846 cy_rslt_t cyhal_nvm_start_program(cyhal_nvm_t *obj, uint32_t address, const uint32_t* data)
847 {
848 CY_ASSERT(NULL != obj);
849 CY_UNUSED_PARAMETER(obj);
850
851 cyhal_nvm_region_info_t _cyhal_nvm_current_block_info;
852 cy_rslt_t status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
853
854 bool is_address_valid = false;
855 is_address_valid = _cyhal_nvm_get_nvm_region_by_address(address, &_cyhal_nvm_current_block_info);
856
857 if (!is_address_valid)
858 {
859 status = CYHAL_NVM_RSLT_ERR_ADDRESS;
860 }
861 else
862 {
863 if (CYHAL_NVM_TYPE_FLASH == _cyhal_nvm_current_block_info.nvm_type)
864 {
865 #if defined(CY_IP_MXS40SRSS) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
866 #if _CYHAL_USES_ECT_FLASH /* StartWrite on this device behaves the same as StartProgram on others */
867 status = _cyhal_flash_run_operation(Cy_Flash_StartWrite, address, data, false);
868 #else
869 status = _cyhal_flash_run_operation(Cy_Flash_StartProgram, address, data, false);
870 #endif
871 #else
872 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
873 #endif /* defined(CY_IP_MXS40SRSS) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)*/
874 }
875 else if (CYHAL_NVM_TYPE_RRAM == _cyhal_nvm_current_block_info.nvm_type)
876 {
877 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
878 status = (cy_rslt_t)Cy_RRAM_NonBlockingNvmWriteByteArray(
879 RRAMC0, address, (const uint8_t *)data, _cyhal_nvm_current_block_info.block_size);
880 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
881 }
882 else if (CYHAL_NVM_TYPE_OTP == _cyhal_nvm_current_block_info.nvm_type)
883 {
884 /* Not supported for OTP */
885 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
886 }
887 else
888 {
889 /* Not supported type of NVM */
890 CY_UNUSED_PARAMETER(address);
891 CY_UNUSED_PARAMETER(data);
892 status = CYHAL_NVM_RSLT_ERR_NOT_SUPPORTED;
893 }
894 }
895 return status;
896 }
897
cyhal_nvm_is_operation_complete(cyhal_nvm_t * obj)898 bool cyhal_nvm_is_operation_complete(cyhal_nvm_t *obj)
899 {
900 CY_ASSERT(NULL != obj);
901 CY_UNUSED_PARAMETER(obj);
902
903 bool complete = true;
904
905 #if (defined(CY_IP_MXS40SRSS) || (_CYHAL_USES_ECT_FLASH) || CY_FLASH_NON_BLOCKING_SUPPORTED) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH)
906 complete = (CY_FLASH_DRV_SUCCESS == Cy_Flash_IsOperationComplete());
907 #if !defined(CY_IP_M7CPUSS) /* PDL automatically clears cache when necessary in M7 devices */
908 if (complete)
909 Cy_SysLib_ClearFlashCacheAndBuffer();
910 #endif
911 #else
912 complete = true;
913 #endif /* (defined(CY_IP_MXS40SRSS) || (_CYHAL_USES_ECT_FLASH) || CY_FLASH_NON_BLOCKING_SUPPORTED) && (_CYHAL_DRIVER_AVAILABLE_NVM_FLASH) */
914
915 #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM)
916 if (complete)
917 {
918 complete = !_cyhal_rram_is_busy();
919 }
920 #endif /* #if (_CYHAL_DRIVER_AVAILABLE_NVM_RRAM) */
921
922 return complete;
923 }
924
925 /*
926 * BWC for Flash HAL
927 * DO NOT USE IN THE NEW DESIGN
928 */
929
930 #if (CYHAL_DRIVER_AVAILABLE_FLASH)
931 static cyhal_flash_block_info_t _flash_blocks[_CYHAL_INTERNAL_FLASH_MEMORY_BLOCKS] = {0};
932
cyhal_flash_get_info(const cyhal_flash_t * obj,cyhal_flash_info_t * info)933 void cyhal_flash_get_info(const cyhal_flash_t *obj, cyhal_flash_info_t *info)
934 {
935 CY_UNUSED_PARAMETER(obj);
936
937 cyhal_nvm_info_t nvm_info;
938 uint32_t flash_region_count = 0;
939
940 nvm_info.region_count = _CYHAL_NVM_MEMORY_BLOCKS_COUNT;
941 nvm_info.regions = &_cyhal_nvm_mem_regions[0];
942
943 for (uint32_t i = 0; i < nvm_info.region_count; i++)
944 {
945 if (CYHAL_NVM_TYPE_FLASH == nvm_info.regions[i].nvm_type)
946 {
947 _flash_blocks[flash_region_count].start_address = nvm_info.regions[i].start_address;
948 _flash_blocks[flash_region_count].size = nvm_info.regions[i].size;
949 _flash_blocks[flash_region_count].sector_size = nvm_info.regions[i].sector_size;
950 _flash_blocks[flash_region_count].page_size = nvm_info.regions[i].block_size;
951 _flash_blocks[flash_region_count].erase_value = nvm_info.regions[i].erase_value;
952 flash_region_count++;
953 }
954 }
955 info->block_count = flash_region_count;
956 info->blocks = &_flash_blocks[0];
957 }
958
959 #endif /* (CYHAL_DRIVER_AVAILABLE_FLASH) */
960
961
962 #if defined(__cplusplus)
963 }
964 #endif /* __cplusplus */
965
966 #endif /* (CYHAL_DRIVER_AVAILABLE_NVM) */
967