|
- /*******************************************************************************
- File Name:
- m2m_flash.c
-
- Summary:
- This module contains the WINC flash interface.
-
- Description:
- This module contains the WINC flash interface.
- *******************************************************************************/
-
- //DOM-IGNORE-BEGIN
- /*******************************************************************************
- * Copyright (C) 2021 Microchip Technology Inc. and its subsidiaries.
- *
- * Subject to your compliance with these terms, you may use Microchip software
- * and any derivatives exclusively with Microchip products. It is your
- * responsibility to comply with third party license terms applicable to your
- * use of third party software (including open source software) that may
- * accompany Microchip software.
- *
- * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
- * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
- * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
- * PARTICULAR PURPOSE.
- *
- * IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
- * INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
- * WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
- * BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
- * FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
- * ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
- * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
- *******************************************************************************/
-
- /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
- INCLUDES
- *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
- #include "m2m_flash.h"
- #include "spi_flash.h"
- #include "spi_flash_map.h"
- #include "nmdrv.h"
-
- /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
- TYPEDEFS
- *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
-
- typedef struct
- {
- uint32_t address;
- uint32_t size;
- } tstrFlashMapEntry;
-
- /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
- GLOBALS
- *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
-
- static const tstrFlashMapEntry flashMap[] =
- {
- {0 , 0 }, // WINC_FLASH_REGION_RAW,
- {0 , OTA_IMAGE_SIZE }, // WINC_FLASH_REGION_FIRMWARE_ACTIVE,
- {0 , OTA_IMAGE_SIZE }, // WINC_FLASH_REGION_FIRMWARE_INACTIVE,
- {M2M_PLL_FLASH_OFFSET , M2M_PLL_FLASH_SZ }, // WINC_FLASH_REGION_PLL_TABLE,
- {M2M_GAIN_FLASH_OFFSET , M2M_GAIN_FLASH_SZ }, // WINC_FLASH_REGION_GAIN_TABLE,
- {M2M_PLL_FLASH_OFFSET , M2M_PLL_FLASH_SZ+M2M_GAIN_FLASH_SZ}, // WINC_FLASH_REGION_PLL_AND_GAIN_TABLES,
- {M2M_TLS_ROOTCER_FLASH_OFFSET , M2M_TLS_ROOTCER_FLASH_SZ }, // WINC_FLASH_REGION_ROOT_CERTS,
- {M2M_TLS_SERVER_FLASH_OFFSET , M2M_TLS_SERVER_FLASH_SZ }, // WINC_FLASH_REGION_LOCAL_CERTS,
- {M2M_CACHED_CONNS_FLASH_OFFSET , M2M_CACHED_CONNS_FLASH_SZ }, // WINC_FLASH_REGION_CONN_PARAM,
- {0 , M2M_HTTP_MEM_FLASH_SZ }, // WINC_FLASH_REGION_HTTP_FILES,
- };
-
- /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
- FUNCTIONS
- *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
-
- static int8_t winc_flash_compare(uint8_t *pu8Buf, uint32_t u32Offset, uint32_t u32Size)
- {
- int8_t ret = M2M_SUCCESS;
- uint8_t buf[128];
- uint32_t offset = 0;
-
- while(offset < u32Size)
- {
- uint32_t chunk_sz = sizeof(buf);
- if(chunk_sz > u32Size - offset)
- chunk_sz = u32Size - offset;
- ret = spi_flash_read(buf, u32Offset + offset, chunk_sz);
- if(ret != M2M_SUCCESS)
- break;
- ret = memcmp(buf, pu8Buf + offset, chunk_sz);
- if(ret != 0)
- break;
- offset += chunk_sz;
- }
- return ret;
- }
- static int8_t winc_flash_write_verify(uint8_t *pu8Buf, uint32_t u32Offset, uint32_t u32Size)
- {
- int8_t ret = M2M_ERR_FAIL;
- uint8_t count = 20;
-
- while((ret != M2M_SUCCESS) && (count-- > 0))
- {
- ret = spi_flash_write(pu8Buf, u32Offset, u32Size);
- if(ret == M2M_SUCCESS)
- ret = winc_flash_compare(pu8Buf, u32Offset, u32Size);
- }
- return ret;
- }
-
- /* Some internal functions for accessing the control structure. */
- static uint8_t crc7(uint8_t crc, const uint8_t *buff, uint16_t len)
- {
- uint8_t reg = crc;
- uint16_t i;
- for(i = 0; i < len; i++)
- {
- uint16_t g;
- for(g = 0; g < 8; g++)
- {
- uint8_t inv = (((buff[i] << g) & 0x80) >> 7) ^ ((reg >> 6) & 1);
- reg = ((reg << 1) & 0x7f) ^ (9 * inv);
- }
- }
- return reg;
- }
- static int8_t verify_control_structure(tstrOtaControlSec *pstrControlSec)
- {
- int8_t s8Ret = M2M_SUCCESS;
-
- if(pstrControlSec->u32OtaMagicValue != OTA_MAGIC_VALUE)
- s8Ret = M2M_ERR_FAIL;
- if(pstrControlSec->u32OtaControlSecCrc != crc7(0x7f, (uint8_t *)pstrControlSec, sizeof(tstrOtaControlSec) - 4))
- s8Ret = M2M_ERR_FAIL;
-
- return s8Ret;
- }
- static int8_t read_control_structure(tstrOtaControlSec *pstrControlSec)
- {
- int8_t s8Ret;
-
- s8Ret = spi_flash_read((uint8_t *)pstrControlSec, M2M_CONTROL_FLASH_OFFSET, sizeof(tstrOtaControlSec));
- if(s8Ret == M2M_SUCCESS)
- s8Ret = verify_control_structure(pstrControlSec);
-
- if(s8Ret != M2M_SUCCESS)
- {
- s8Ret = spi_flash_read((uint8_t *)pstrControlSec, M2M_BACKUP_FLASH_OFFSET, sizeof(tstrOtaControlSec));
- if(s8Ret == M2M_SUCCESS)
- s8Ret = verify_control_structure(pstrControlSec);
- }
-
- return s8Ret;
- }
- static int8_t update_control_structure(tstrOtaControlSec *pstrControlSec)
- {
- int8_t ret = M2M_ERR_FAIL;
-
- ret = spi_flash_erase(M2M_BACKUP_FLASH_OFFSET, M2M_BACKUP_FLASH_SZ);
- if(ret == M2M_SUCCESS)
- {
- pstrControlSec->u32OtaSequenceNumber++;
- pstrControlSec->u32OtaControlSecCrc = crc7(0x7f, (uint8_t *)pstrControlSec, sizeof(tstrOtaControlSec) - 4);
- ret = winc_flash_write_verify((uint8_t *)pstrControlSec, M2M_BACKUP_FLASH_OFFSET, sizeof(tstrOtaControlSec));
- if(ret == M2M_SUCCESS)
- {
- ret = spi_flash_erase(M2M_CONTROL_FLASH_OFFSET, M2M_CONTROL_FLASH_SZ);
- if(ret == M2M_SUCCESS)
- {
- pstrControlSec->u32OtaSequenceNumber++;
- pstrControlSec->u32OtaControlSecCrc = crc7(0x7f, (uint8_t *)pstrControlSec, sizeof(tstrOtaControlSec) - 4);
- ret = winc_flash_write_verify((uint8_t *)pstrControlSec, M2M_CONTROL_FLASH_OFFSET, sizeof(tstrOtaControlSec));
- }
- }
- }
- return ret;
- }
-
- static bool find_flash_section(tenuWincFlashRegion enuRegion, uint32_t *pu32StartAddr, uint32_t *pu32Size)
- {
- /* Ensure the pointers and region are valid. */
- if((NULL == pu32StartAddr) || (NULL == pu32Size) || (enuRegion >= WINC_FLASH_NUM_REGIONS))
- return false;
-
- /* For the raw region resolve the full flash space, otherwise lookup
- the region location and size from the flexible flash map. */
- switch(enuRegion)
- {
- case WINC_FLASH_REGION_RAW:
- *pu32StartAddr = 0;
- *pu32Size = spi_flash_get_size() << 17;
- break;
- case WINC_FLASH_REGION_FIRMWARE_ACTIVE:
- case WINC_FLASH_REGION_FIRMWARE_INACTIVE:
- case WINC_FLASH_REGION_HTTP_FILES:
- {
- /* In these cases we need to read the control structure to find the appropriate flash address. */
- tstrOtaControlSec strControl;
-
- /* Check the WINC is initialised and not running. */
- if (NM_STATE_INIT != nm_get_state())
- return false;
-
- /* Read control structure from flash. */
- if (M2M_SUCCESS != read_control_structure(&strControl))
- return false;
-
- if (WINC_FLASH_REGION_FIRMWARE_INACTIVE == enuRegion)
- *pu32StartAddr = strControl.u32OtaRollbackImageOffset;
- else if (WINC_FLASH_REGION_FIRMWARE_ACTIVE == enuRegion)
- *pu32StartAddr = strControl.u32OtaCurrentWorkingImagOffset;
- else if (WINC_FLASH_REGION_HTTP_FILES == enuRegion)
- *pu32StartAddr = strControl.u32OtaCurrentWorkingImagOffset + (M2M_HTTP_MEM_FLASH_OFFSET - M2M_OTA_IMAGE1_OFFSET);
-
- *pu32Size = flashMap[enuRegion].size;
- break;
- }
- default:
- *pu32StartAddr = flashMap[enuRegion].address;
- *pu32Size = flashMap[enuRegion].size;
- break;
- }
-
- M2M_INFO("Flash lookup %2d: 0x%06" PRIx32 " %0" PRId32 "\r\n", enuRegion, *pu32StartAddr, *pu32Size);
-
- return true;
- }
-
- int8_t m2m_flash_erase_sector(tenuWincFlashRegion enuRegion, uint8_t u8StartSector, uint8_t u8NumSectors)
- {
- uint32_t flashAddress;
- uint32_t flashRegionSize;
-
- /* Check the WINC is initialised and not running. */
- if(NM_STATE_INIT != nm_get_state())
- return M2M_ERR_FAIL;
-
- /* Check the region is valid. */
- if(enuRegion >= WINC_FLASH_NUM_REGIONS)
- return M2M_ERR_INVALID_ARG;
-
- /* Find region address and size. */
- if(false == find_flash_section(enuRegion, &flashAddress, &flashRegionSize))
- return M2M_ERR_FAIL;
-
- /* Erase is only supported for regions which begin on a sector boundary. */
- if(flashAddress & (FLASH_SECTOR_SZ-1))
- return M2M_ERR_INVALID_ARG;
-
- /* Check requested size fits within region size. */
- if((((uint32_t)u8StartSector + u8NumSectors) * FLASH_SECTOR_SZ) > flashRegionSize)
- return M2M_ERR_FAIL;
-
- /* Find start address of area within requested region. */
- flashAddress += (u8StartSector * FLASH_SECTOR_SZ);
-
- /* Erase the requested sectors. */
- if(M2M_SUCCESS != spi_flash_erase(flashAddress, u8NumSectors * FLASH_SECTOR_SZ))
- return M2M_ERR_FAIL;
-
- return M2M_SUCCESS;
- }
-
- int8_t m2m_flash_write(tenuWincFlashRegion enuRegion, void *pvBuffer, uint32_t u32Offset, uint32_t u32Size)
- {
- uint32_t flashAddress;
- uint32_t flashRegionSize;
-
- /* Check the WINC is initialised and not running. */
- if(NM_STATE_INIT != nm_get_state())
- return M2M_ERR_FAIL;
-
- /* Check the buffer pointer and region are valid. */
- if((NULL == pvBuffer) || (enuRegion >= WINC_FLASH_NUM_REGIONS))
- return M2M_ERR_INVALID_ARG;
-
- /* Find region address and size. */
- if(false == find_flash_section(enuRegion, &flashAddress, &flashRegionSize))
- return M2M_ERR_FAIL;
-
- /* Check requested size fits within region size. Also check for wraparound. */
- if(((u32Offset + u32Size) > flashRegionSize) || ((uint32_t)(u32Offset + u32Size) < u32Offset))
- return M2M_ERR_FAIL;
-
- /* Find start address of area within requested region. */
- flashAddress += u32Offset;
-
- /* Write data to flash. */
- if(M2M_SUCCESS != spi_flash_write(pvBuffer, flashAddress, u32Size))
- return M2M_ERR_FAIL;
-
- return M2M_SUCCESS;
- }
-
- int8_t m2m_flash_read(tenuWincFlashRegion enuRegion, void *pvBuffer, uint32_t u32Offset, uint32_t u32Size)
- {
- uint32_t flashAddress;
- uint32_t flashRegionSize;
-
- /* Check the WINC is initialised and not running. */
- if(NM_STATE_INIT != nm_get_state())
- return M2M_ERR_FAIL;
-
- /* Check the buffer pointer and region are valid. */
- if((NULL == pvBuffer) || (enuRegion >= WINC_FLASH_NUM_REGIONS))
- return M2M_ERR_INVALID_ARG;
-
- /* Find region address and size. */
- if(false == find_flash_section(enuRegion, &flashAddress, &flashRegionSize))
- return M2M_ERR_FAIL;
-
- /* Check requested size fits within region size. Also check for wraparound. */
- if(((u32Offset + u32Size) > flashRegionSize) || ((uint32_t)(u32Offset + u32Size) < u32Offset))
- return M2M_ERR_FAIL;
-
- /* Find start address of area within requested region. */
- flashAddress += u32Offset;
-
- /* Read data from flash. */
- if(M2M_SUCCESS != spi_flash_read(pvBuffer, flashAddress, u32Size))
- return M2M_ERR_FAIL;
-
- return M2M_SUCCESS;
- }
-
- int8_t m2m_flash_switch_firmware(void)
- {
- tstrOtaControlSec strControl;
- uint32_t u32Tmp;
-
- /* Check the WINC is initialised and not running. */
- if(NM_STATE_INIT != nm_get_state())
- return M2M_ERR_FAIL;
-
- /* Read control structure from flash. */
- if(M2M_SUCCESS != read_control_structure(&strControl))
- return M2M_ERR_FAIL;
-
- /* Switch active and inactive. */
- u32Tmp = strControl.u32OtaRollbackImageOffset;
- strControl.u32OtaRollbackImageOffset = strControl.u32OtaCurrentWorkingImagOffset;
- strControl.u32OtaCurrentWorkingImagOffset = u32Tmp;
-
- /* Ensure the inactive image is marked as invalid. This protects m2m_ota_switch_firmware from
- switching to an image whose validity is unknown. Switching remains possible via this API. */
- strControl.u32OtaRollbackImageValidStatus = OTA_STATUS_INVALID;
-
- if(M2M_SUCCESS != update_control_structure(&strControl))
- return M2M_ERR_FAIL;
-
- return M2M_SUCCESS;
- }
-
- //DOM-IGNORE-END
|