/** * * \file * * \brief This module contains WINC3400 M2M driver APIs implementation. * * Copyright (c) 2017-2018 Microchip Technology Inc. and its subsidiaries. * * \asf_license_start * * \page License * * 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. * * \asf_license_stop * */ #include "common/include/nm_common.h" #include "driver/source/nmbus.h" #include "bsp/include/nm_bsp.h" #include "driver/source/nmdrv.h" #include "driver/source/nmasic.h" #include "driver/include/m2m_types.h" #ifdef CONF_WINC_USE_SPI #include "driver/source/nmspi.h" #endif /** * @fn nm_get_hif_info(uint16 *pu16FwHifInfo, uint16 *pu16OtaHifInfo); * @brief Get Hif info of images in both partitions (Firmware and Ota). * @param [out] pu16FwHifInfo * Pointer holding Hif info of image in the active partition. * @param [out] pu16OtaHifInfo * Pointer holding Hif info of image in the inactive partition. * @return ZERO in case of success and Negative error code in case of failure */ sint8 nm_get_hif_info(uint16 *pu16FwHifInfo, uint16 *pu16OtaHifInfo) { sint8 ret = M2M_SUCCESS; uint32 reg = 0; ret = nm_read_reg_with_ret(NMI_REV_REG, ®); if(ret == M2M_SUCCESS) { if(pu16FwHifInfo != NULL) { *pu16FwHifInfo = (uint16)reg; } if(pu16OtaHifInfo) { *pu16OtaHifInfo = (uint16)(reg>>16); } } return ret; } /** * @fn nm_get_firmware_full_info(tstrM2mRev* M2mRev) * @brief Get Firmware version info * @param [out] M2mRev * pointer holds address of structure "tstrM2mRev" that contains the firmware version parameters * @version 1.0 */ sint8 nm_get_firmware_full_info(tstrM2mRev* pstrRev) { uint16 fw_hif_info = 0; uint32 reg = 0; sint8 ret = M2M_SUCCESS; tstrGpRegs strgp = {0}; m2m_memset((uint8*)pstrRev,0,sizeof(tstrM2mRev)); nm_get_hif_info(&fw_hif_info, NULL); M2M_INFO("Fw HIF: %04x\n", fw_hif_info); if(M2M_GET_HIF_BLOCK(fw_hif_info) == M2M_HIF_BLOCK_VALUE) { ret = nm_read_reg_with_ret(rNMI_GP_REG_0, ®); if(ret == M2M_SUCCESS) { if(reg != 0) { ret = nm_read_block(reg|0x30000,(uint8*)&strgp,sizeof(tstrGpRegs)); if(ret == M2M_SUCCESS) { reg = strgp.u32Firmware_Ota_rev; reg &= 0x0000ffff; if(reg != 0) { ret = nm_read_block(reg|0x30000,(uint8*)pstrRev,sizeof(tstrM2mRev)); if(ret == M2M_SUCCESS) { M2M_INFO("Firmware HIF (%u) : %u.%u \n", M2M_GET_HIF_BLOCK(pstrRev->u16FirmwareHifInfo), M2M_GET_HIF_MAJOR(pstrRev->u16FirmwareHifInfo), M2M_GET_HIF_MINOR(pstrRev->u16FirmwareHifInfo)); M2M_INFO("Firmware ver : %u.%u.%u \n", pstrRev->u8FirmwareMajor, pstrRev->u8FirmwareMinor, pstrRev->u8FirmwarePatch); M2M_INFO("Firmware Build %s Time %s\n", pstrRev->BuildDate, pstrRev->BuildTime); /* Check Hif info is consistent */ if(fw_hif_info != pstrRev->u16FirmwareHifInfo) { ret = M2M_ERR_FAIL; M2M_ERR("Inconsistent Firmware Version\n"); } } } else { ret = M2M_ERR_FAIL; } } } else { ret = M2M_ERR_FAIL; } } } else { ret = M2M_ERR_FAIL; } if(ret != M2M_SUCCESS) { M2M_ERR("Unknown Firmware Version\n"); } return ret; } /** * @fn nm_get_ota_firmware_info(tstrM2mRev* pstrRev) * @brief Get Firmware version info * @param [out] M2mRev * pointer holds address of structure "tstrM2mRev" that contains the firmware version parameters * @version 1.0 */ sint8 nm_get_ota_firmware_info(tstrM2mRev* pstrRev) { uint16 ota_hif_info = 0; uint32 reg = 0; sint8 ret = M2M_SUCCESS; tstrGpRegs strgp = {0}; m2m_memset((uint8*)pstrRev,0,sizeof(tstrM2mRev)); nm_get_hif_info(NULL, &ota_hif_info); M2M_INFO("Ota HIF: %04x\n", ota_hif_info); if(M2M_GET_HIF_BLOCK(ota_hif_info) == M2M_HIF_BLOCK_VALUE) { ret = nm_read_reg_with_ret(rNMI_GP_REG_0, ®); if(ret == M2M_SUCCESS) { if(reg != 0) { ret = nm_read_block(reg|0x30000,(uint8*)&strgp,sizeof(tstrGpRegs)); if(ret == M2M_SUCCESS) { reg = strgp.u32Firmware_Ota_rev; reg >>= 16; if(reg != 0) { ret = nm_read_block(reg|0x30000,(uint8*)pstrRev,sizeof(tstrM2mRev)); if(ret == M2M_SUCCESS) { M2M_INFO("OTA HIF (%u) : %u.%u \n", M2M_GET_HIF_BLOCK(pstrRev->u16FirmwareHifInfo), M2M_GET_HIF_MAJOR(pstrRev->u16FirmwareHifInfo), M2M_GET_HIF_MINOR(pstrRev->u16FirmwareHifInfo)); M2M_INFO("OTA ver : %u.%u.%u \n", pstrRev->u8FirmwareMajor, pstrRev->u8FirmwareMinor, pstrRev->u8FirmwarePatch); M2M_INFO("OTA Build %s Time %s\n", pstrRev->BuildDate, pstrRev->BuildTime); /* Check Hif info is consistent */ if(ota_hif_info != pstrRev->u16FirmwareHifInfo) { ret = M2M_ERR_FAIL; M2M_ERR("Inconsistent OTA Version\n"); } } } else { ret = M2M_ERR_FAIL; } } } else { ret = M2M_ERR_FAIL; } } } else { ret = M2M_ERR_FAIL; } if(ret != M2M_SUCCESS) { M2M_INFO("No valid Ota image\n"); } return ret; } /* * @fn nm_drv_init_download_mode * @brief Initialize NMC1000 driver * @return M2M_SUCCESS in case of success and Negative error code in case of failure * @param [in] arg * Generic argument * @author Viswanathan Murugesan * @date 10 Oct 2014 * @version 1.0 */ sint8 nm_drv_init_download_mode(uint32 req_serial_number) { sint8 ret = M2M_SUCCESS; ret = nm_bus_iface_init(NULL, req_serial_number); if (M2M_SUCCESS != ret) { M2M_ERR("[nmi start]: fail init bus\n"); goto ERR1; } #ifdef CONF_WINC_USE_SPI /* Must do this after global reset to set SPI data packet size. */ nm_spi_init(); #endif M2M_INFO("Chip ID %lx\n", nmi_get_chipid()); /*disable all interrupt in ROM (to disable uart) in 2b0 chip*/ nm_write_reg(0x20300,0); ERR1: return ret; } sint8 nm_drv_init_hold(uint32 req_serial_number) { sint8 ret = M2M_SUCCESS; ret = nm_bus_iface_init(NULL, req_serial_number); if (M2M_SUCCESS != ret) { M2M_ERR("[nmi start]: fail init bus\n"); goto ERR1; } #ifdef BUS_ONLY return; #endif ret = chip_wake(); nm_bsp_sleep(10); if (M2M_SUCCESS != ret) { M2M_ERR("[nmi start]: fail chip_wakeup\n"); goto ERR2; } /** Go... **/ //JFM 2021-02-07 //chip_reset disbled because it failed. Probably because not RTC installed on the board //retry when available... // ret = chip_reset(); // if (M2M_SUCCESS != ret) { // goto ERR2; // } M2M_INFO("Chip ID %lx\n", nmi_get_chipid()); #ifdef CONF_WINC_USE_SPI /* Must do this after global reset to set SPI data packet size. */ nm_spi_init(); #endif /*return power save to default value*/ chip_idle(); return ret; ERR2: nm_bus_iface_deinit(); ERR1: return ret; } sint8 nm_drv_init_start(void * arg) { sint8 ret = M2M_SUCCESS; uint8 u8Mode = M2M_WIFI_MODE_NORMAL; if(NULL != arg) { if(M2M_WIFI_MODE_CONFIG == *((uint8 *)arg)) { u8Mode = M2M_WIFI_MODE_CONFIG; } else { /*continue running*/ } } else { /*continue running*/ } ret = cpu_start(); if (M2M_SUCCESS != ret) { goto ERR2; } ret = wait_for_bootrom(u8Mode); if (M2M_SUCCESS != ret) { goto ERR2; } ret = wait_for_firmware_start(u8Mode); if (M2M_SUCCESS != ret) { goto ERR2; } if(M2M_WIFI_MODE_CONFIG == u8Mode) { goto ERR1; } else { /*continue running*/ } ret = enable_interrupts(); if (M2M_SUCCESS != ret) { M2M_ERR("failed to enable interrupts..\n"); goto ERR2; } return ret; ERR2: nm_bus_iface_deinit(); #ifdef CONF_WINC_USE_SPI nm_spi_deinit(); #endif ERR1: return ret; } /* * @fn nm_drv_init * @brief Initialize NMC1000 driver * @return M2M_SUCCESS in case of success and Negative error code in case of failure * @param [in] arg - Generic argument passed on to nm_drv_init_start * @author M. Abdelmawla * @date 15 July 2012 * @version 1.0 */ sint8 nm_drv_init(void * arg, uint32 req_serial_number) { sint8 ret = M2M_SUCCESS; ret = nm_drv_init_hold(req_serial_number); if(ret == M2M_SUCCESS) ret = nm_drv_init_start(arg); return ret; } /* * @fn nm_drv_deinit * @brief Deinitialize NMC1000 driver * @author M. Abdelmawla * @date 17 July 2012 * @version 1.0 */ sint8 nm_drv_deinit(void * arg) { sint8 ret; ret = chip_deinit(); if (M2M_SUCCESS != ret) { M2M_ERR("[nmi stop]: chip_deinit fail\n"); goto ERR1; } ret = nm_bus_iface_deinit(); if (M2M_SUCCESS != ret) { M2M_ERR("[nmi stop]: fail init bus\n"); goto ERR1; } #ifdef CONF_WINC_USE_SPI /* Must do this after global reset to set SPI data packet size. */ nm_spi_deinit(); #endif ERR1: return ret; } /** * @fn nm_cpu_start(void) * @brief Start CPU from the WINC module * @return ZERO in case of success and Negative error code in case of failure */ sint8 nm_cpu_start(void) { sint8 ret; ret = cpu_start(); return ret; }