284 lines
8.6 KiB
C
Executable File
284 lines
8.6 KiB
C
Executable File
/*
|
|
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef CONFIG_BOOTLOADER
|
|
|
|
#include "efpg_i.h"
|
|
#include "efpg_debug.h"
|
|
#include "efpg/efpg.h"
|
|
#include "driver/chip/hal_uart.h"
|
|
#include "driver/chip/hal_efuse.h"
|
|
|
|
static void efpg_task(void *arg)
|
|
{
|
|
uint8_t *buf;
|
|
int32_t recv_len;
|
|
efpg_priv_t *efpg = arg;
|
|
efpg_state_t state = EFPG_STATE_NUM;
|
|
|
|
if (efpg->start_cb) {
|
|
efpg->start_cb();
|
|
}
|
|
|
|
efpg_reset:
|
|
efpg->is_cmd = 1;
|
|
efpg->ext_cmd = EFPG_NORMAL_CMD;
|
|
efpg->expt_len = EFPG_CMD_FRAME_LEN;
|
|
efpg->recv_len = 0;
|
|
efpg->op = EFPG_OP_NUM;
|
|
efpg->field = EFPG_FIELD_NUM;
|
|
efpg->start_bit_addr = 0;
|
|
efpg->bit_length = 0;
|
|
|
|
while (1) {
|
|
efpg_continue:
|
|
if (efpg->is_cmd) {
|
|
if (efpg->ext_cmd == EFPG_EXT_CMD) {
|
|
buf = efpg->ext_cmd_frame;
|
|
} else {
|
|
buf = efpg->cmd_frame;
|
|
}
|
|
} else {
|
|
buf = efpg->data_frame;
|
|
}
|
|
recv_len = 0;
|
|
while (recv_len == 0) {
|
|
recv_len = HAL_UART_Receive_IT(efpg->uart_id, buf, efpg->expt_len, EFPG_RECV_TIMEOUT_MS);
|
|
}
|
|
|
|
if (recv_len == -1) {
|
|
EFPG_ERR("UART receive failed\n");
|
|
goto efpg_stop;
|
|
}
|
|
|
|
if ((uint16_t)recv_len != efpg->expt_len) {
|
|
EFPG_WARN("%s(), %d, recv len %d, expt len %d\n",
|
|
__func__, __LINE__, recv_len, efpg->expt_len);
|
|
goto efpg_reset;
|
|
}
|
|
|
|
efpg->recv_len = (uint16_t)recv_len;
|
|
|
|
if (efpg->is_cmd) {
|
|
state = efpg_cmd_frame_process(efpg);
|
|
} else {
|
|
state = efpg_data_frame_process(efpg);
|
|
}
|
|
|
|
switch (state) {
|
|
case EFPG_STATE_CONTINUE:
|
|
goto efpg_continue;
|
|
case EFPG_STATE_RESET:
|
|
goto efpg_reset;
|
|
case EFPG_STATE_STOP:
|
|
goto efpg_stop;
|
|
default:
|
|
EFPG_ERR("invalid state %d\n", state);
|
|
goto efpg_stop;
|
|
}
|
|
}
|
|
|
|
efpg_stop:
|
|
if (efpg->stop_cb) {
|
|
efpg->stop_cb();
|
|
}
|
|
|
|
if (efpg) {
|
|
efpg_free(efpg);
|
|
}
|
|
|
|
OS_ThreadDelete(NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Start communicating with the OEM programming tool
|
|
* @param[in] key Pointer to the key
|
|
* @param[in] key_len The length of the key
|
|
* @param[in] uart_id ID of the specified UART used to communication
|
|
* @param[in] start_cb Function called when start communication
|
|
* @param[in] stop_cb Function called when stop communication
|
|
* @return 0 on success, -1 on failure
|
|
*
|
|
* @note Just for OEM programming tool to entry eFuse programming mode.
|
|
*/
|
|
int efpg_start(uint8_t *key, uint8_t key_len, UART_ID uart_id, efpg_cb_t start_cb, efpg_cb_t stop_cb)
|
|
{
|
|
efpg_priv_t *efpg;
|
|
OS_Thread_t thread;
|
|
|
|
if ((key == NULL) || (key_len == 0) || (key_len > EFPG_KEY_LEN_MAX) || (uart_id >= UART_NUM)) {
|
|
EFPG_ERR("key %p, key len %d, uart id %d\n", key, key_len, uart_id);
|
|
return -1;
|
|
}
|
|
|
|
efpg = efpg_malloc(sizeof(efpg_priv_t));
|
|
if (efpg == NULL) {
|
|
EFPG_ERR("malloc failed\n");
|
|
return -1;
|
|
}
|
|
|
|
efpg->uart_id = uart_id;
|
|
efpg->start_cb = start_cb;
|
|
efpg->stop_cb = stop_cb;
|
|
|
|
efpg_memcpy(efpg->key, key, key_len);
|
|
efpg->key_len = key_len;
|
|
|
|
OS_ThreadSetInvalid(&thread);
|
|
if (OS_ThreadCreate(&thread,
|
|
"efpg",
|
|
efpg_task,
|
|
efpg,
|
|
OS_THREAD_PRIO_CONSOLE,
|
|
EFPG_THREAD_STACK_SIZE) != OS_OK) {
|
|
EFPG_ERR("create efpg task failed\n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Read data from the specified field in eFuse
|
|
* @param[in] field The filed in eFuse
|
|
* @param[in] data Pointer to the data buffer
|
|
* @return 0 on success, -1 on failure
|
|
*
|
|
* @note The rest bit(s) in data will be cleared to 0.
|
|
*/
|
|
int efpg_read(efpg_field_t field, uint8_t *data)
|
|
{
|
|
if (data == NULL) {
|
|
EFPG_ERR("data %p\n", data);
|
|
return -1;
|
|
}
|
|
|
|
uint16_t ack = efpg_read_field(field, data, 0, 0);
|
|
if (ack != EFPG_ACK_OK) {
|
|
EFPG_WARN("%s(), field %d, ack %d\n", __func__, field, ack);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Read data from user area (OEM reserved field) on EFUSE
|
|
* @param[in] start The first bit to be read in user area (OEM reserved field)
|
|
* @param[in] num Number of bits to be read
|
|
* @param[in] data Pointer to the data buffer
|
|
* @return 0 on success, -1 on failure
|
|
*
|
|
* @note The rest bit(s) in data will be cleared to be 0.
|
|
*/
|
|
int efpg_read_ua(uint32_t start, uint32_t num, uint8_t *data)
|
|
{
|
|
if (data == NULL) {
|
|
EFPG_ERR("data %p\n", data);
|
|
return -1;
|
|
}
|
|
|
|
if (efpg_read_field(EFPG_FIELD_UA, data, start, num) != EFPG_ACK_OK) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Read data from all areas on EFUSE
|
|
* @param[in] start The first bit to be read on EFUSE
|
|
* @param[in] num Number of bits to be read
|
|
* @param[in] data Pointer to the data buffer
|
|
* @return 0 on success, -1 on failure
|
|
*
|
|
* @note The rest bit(s) in data will be cleared to be 0.
|
|
*/
|
|
int efpg_read_all(uint32_t start, uint32_t num, uint8_t *data)
|
|
{
|
|
if (data == NULL) {
|
|
EFPG_ERR("data %p\n", data);
|
|
return -1;
|
|
}
|
|
|
|
if (efpg_read_field(EFPG_FIELD_ALL, data, start, num) != EFPG_ACK_OK) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if (CONFIG_CHIP_ARCH_VER == 3)
|
|
/**
|
|
* @brief Print EFUSE layout
|
|
*/
|
|
void efpg_layout(void)
|
|
{
|
|
printf("--------------- EFUSE layout ---------------\n");
|
|
printf("********* HOSC type *********\n");
|
|
printf("HOSC_TYPE_START:%d bit\n", EFPG_HOSC_TYPE_START);
|
|
printf("HOSC_TYPE_TOTAL_LEN:%d bit\n", EFPG_HOSC_TYPE_NUM);
|
|
printf("********* SECURE BOOT *********\n");
|
|
printf("SECURE_BOOT_START:%d bit\n", EFPG_BOOT_FLAG_START);
|
|
printf("SECURE_BOOT_TOTAL_LEN:%d bit\n", EFPG_MAC_ADDRESS_FLAG_START - EFPG_BOOT_FLAG_START);
|
|
printf("********* MAC address *********\n");
|
|
printf("MAC_ADDR_START:%d bit\n", EFPG_MAC_ADDRESS_FLAG_START);
|
|
printf("MAC_ADDR_NUM:%d\n", EFPG_MAC_ADDRESS_FLAG_NUM);
|
|
printf("MAC_ADDR_TOTAL_LEN:%d bit\n", (EFPG_MAC_ADDRESS_FLAG_NUM + EFPG_MAC_ADDRESS_NUM));
|
|
printf("********* WLAN MAC address *********\n");
|
|
printf("MAC_WLAN_ADDR_START:%d bit\n", EFPG_MAC_WLAN_ADDR_FLAG_START);
|
|
printf("MAC_WLAN_ADDR_NUM:%d\n", EFPG_MAC_WLAN_ADDR_NUM);
|
|
printf("MAC_WLAN_ADDR_TOTAL_LEN:%d bit\n", EFPG_MAC_WLAN_ADDR_NUM * (1 + EFPG_MAC_WLAN_ADDR_LEN));
|
|
printf("********* BT MAC address *********\n");
|
|
printf("MAC_BT_ADDR_START:%d bit\n", EFPG_MAC_BT_ADDR_FLAG_START);
|
|
printf("MAC_BT_ADDR_NUM:%d\n", EFPG_MAC_BT_ADDR_NUM);
|
|
printf("MAC_BT_ADDR_TOTAL_LEN:%d bit\n", EFPG_MAC_BT_ADDR_NUM * (1 + EFPG_MAC_BT_ADDR_LEN));
|
|
printf("********* DCXO TRIM *********\n");
|
|
printf("DCXO_TRIM_START:%d bit\n", EFPG_DCXO_TRIM_FLAG_START);
|
|
printf("DCXO_TRIM_NUM:%d\n", EFPG_DCXO_TRIM_NUM);
|
|
printf("DCXO_TRIM_TOTAL_LEN:%d bit\n", EFPG_DCXO_TRIM_NUM * (1 + EFPG_DCXO_TRIM_LEN));
|
|
printf("********* POUT CAL *********\n");
|
|
printf("POUT_CAL_START:%d bit\n", EFPG_POUT_CAL_FLAG_START);
|
|
printf("POUT_CAL_NUM:%d\n", EFPG_POUT_CAL_NUM);
|
|
printf("POUT_CAL_TOTAL_LEN:%d bit\n", EFPG_POUT_CAL_NUM * (1 + EFPG_POUT_CAL_LEN));
|
|
printf("********* BT POUT CAL *********\n");
|
|
printf("POUT_BT_CAL_START:%d bit\n", EFPG_BT_POUT_CAL_FLAG_START);
|
|
printf("POUT_BT_CAL_NUM:%d\n", EFPG_BT_POUT_CAL_NUM);
|
|
printf("POUT_BT_CAL_TOTAL_LEN:%d bit\n", EFPG_BT_POUT_CAL_NUM * (1 + EFPG_BT_POUT_CAL_LEN));
|
|
printf("********* USER area *********\n");
|
|
printf("USER_AREA_START:%d bit\n", EFPG_USER_AREA_START);
|
|
printf("USER_AREA_LEN:%d bit\n", EFPG_USER_AREA_NUM);
|
|
printf("-----------------------------------------\n");
|
|
}
|
|
|
|
void efpg_update_all(void)
|
|
{
|
|
HAL_EFUSE_UpdateAll();
|
|
}
|
|
#endif
|
|
#endif /* CONFIG_BOOTLOADER */
|