2016-11-21 04:15:37 -05:00
|
|
|
// Copyright 2013-2016 Espressif Systems (Shanghai) PTE LTD
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2017-03-01 07:42:46 -05:00
|
|
|
#include <string.h>
|
|
|
|
|
2016-11-21 04:15:37 -05:00
|
|
|
#include "esp_system.h"
|
|
|
|
#include "esp_attr.h"
|
|
|
|
#include "esp_wifi.h"
|
2019-03-22 02:21:15 -04:00
|
|
|
#include "esp_private/wifi.h"
|
2016-11-21 04:15:37 -05:00
|
|
|
#include "esp_log.h"
|
2017-01-15 19:52:15 -05:00
|
|
|
#include "sdkconfig.h"
|
2019-03-14 05:29:32 -04:00
|
|
|
#include "esp32/rom/efuse.h"
|
|
|
|
#include "esp32/rom/cache.h"
|
|
|
|
#include "esp32/rom/uart.h"
|
2016-11-21 04:15:37 -05:00
|
|
|
#include "soc/dport_reg.h"
|
2017-09-04 07:00:47 -04:00
|
|
|
#include "soc/gpio_reg.h"
|
2016-11-21 04:15:37 -05:00
|
|
|
#include "soc/efuse_reg.h"
|
|
|
|
#include "soc/rtc_cntl_reg.h"
|
|
|
|
#include "soc/timer_group_reg.h"
|
|
|
|
#include "soc/timer_group_struct.h"
|
|
|
|
#include "soc/cpu.h"
|
2017-04-11 03:44:43 -04:00
|
|
|
#include "soc/rtc.h"
|
2018-07-23 06:59:37 -04:00
|
|
|
#include "soc/rtc_wdt.h"
|
2016-11-21 04:15:37 -05:00
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
#include "freertos/task.h"
|
|
|
|
#include "freertos/xtensa_api.h"
|
2017-05-03 04:03:28 -04:00
|
|
|
#include "esp_heap_caps.h"
|
2019-03-21 00:21:01 -04:00
|
|
|
#include "esp_private/system_internal.h"
|
2018-11-18 22:38:05 -05:00
|
|
|
#include "esp_efuse.h"
|
|
|
|
#include "esp_efuse_table.h"
|
2016-11-21 04:15:37 -05:00
|
|
|
|
|
|
|
static const char* TAG = "system_api";
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
static uint8_t base_mac_addr[6] = { 0 };
|
2017-04-19 09:00:00 -04:00
|
|
|
|
2017-08-07 06:30:46 -04:00
|
|
|
#define SHUTDOWN_HANDLERS_NO 2
|
|
|
|
static shutdown_handler_t shutdown_handlers[SHUTDOWN_HANDLERS_NO];
|
|
|
|
|
2016-11-21 10:05:23 -05:00
|
|
|
void system_init()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
esp_err_t esp_base_mac_addr_set(uint8_t *mac)
|
2017-04-19 09:00:00 -04:00
|
|
|
{
|
|
|
|
if (mac == NULL) {
|
2017-05-05 10:24:56 -04:00
|
|
|
ESP_LOGE(TAG, "Base MAC address is NULL");
|
2017-04-19 09:00:00 -04:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
memcpy(base_mac_addr, mac, 6);
|
2017-04-19 09:00:00 -04:00
|
|
|
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
esp_err_t esp_base_mac_addr_get(uint8_t *mac)
|
2017-04-19 09:00:00 -04:00
|
|
|
{
|
|
|
|
uint8_t null_mac[6] = {0};
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
if (memcmp(base_mac_addr, null_mac, 6) == 0) {
|
|
|
|
ESP_LOGI(TAG, "Base MAC address is not set, read default base MAC address from BLK0 of EFUSE");
|
|
|
|
return ESP_ERR_INVALID_MAC;
|
2017-04-19 09:00:00 -04:00
|
|
|
}
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
memcpy(mac, base_mac_addr, 6);
|
2017-04-19 09:00:00 -04:00
|
|
|
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
esp_err_t esp_efuse_mac_get_custom(uint8_t *mac)
|
2016-11-21 04:15:37 -05:00
|
|
|
{
|
2018-11-18 22:38:05 -05:00
|
|
|
uint8_t version;
|
|
|
|
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM_VER, &version, 8);
|
2017-04-17 09:16:16 -04:00
|
|
|
if (version != 1) {
|
2017-05-05 10:24:56 -04:00
|
|
|
ESP_LOGE(TAG, "Base MAC address from BLK3 of EFUSE version error, version = %d", version);
|
|
|
|
return ESP_ERR_INVALID_VERSION;
|
2017-04-17 09:16:16 -04:00
|
|
|
}
|
|
|
|
|
2018-11-18 22:38:05 -05:00
|
|
|
uint8_t efuse_crc;
|
|
|
|
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48);
|
|
|
|
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM_CRC, &efuse_crc, 8);
|
|
|
|
uint8_t calc_crc = esp_crc8(mac, 6);
|
2017-05-05 10:24:56 -04:00
|
|
|
|
|
|
|
if (efuse_crc != calc_crc) {
|
|
|
|
ESP_LOGE(TAG, "Base MAC address from BLK3 of EFUSE CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc);
|
|
|
|
return ESP_ERR_INVALID_CRC;
|
|
|
|
}
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t esp_efuse_mac_get_default(uint8_t* mac)
|
|
|
|
{
|
|
|
|
uint8_t efuse_crc;
|
2018-11-18 22:38:05 -05:00
|
|
|
esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, 48);
|
|
|
|
esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY_CRC, &efuse_crc, 8);
|
|
|
|
uint8_t calc_crc = esp_crc8(mac, 6);
|
2016-11-21 04:15:37 -05:00
|
|
|
|
|
|
|
if (efuse_crc != calc_crc) {
|
|
|
|
// Small range of MAC addresses are accepted even if CRC is invalid.
|
|
|
|
// These addresses are reserved for Espressif internal use.
|
2018-11-18 22:38:05 -05:00
|
|
|
uint32_t mac_high = ((uint32_t)mac[0] << 8) | mac[1];
|
2016-11-21 04:15:37 -05:00
|
|
|
if ((mac_high & 0xFFFF) == 0x18fe) {
|
2018-11-18 22:38:05 -05:00
|
|
|
uint32_t mac_low = ((uint32_t)mac[2] << 24) | ((uint32_t)mac[3] << 16) | ((uint32_t)mac[4] << 8) | mac[5];
|
2016-11-21 04:15:37 -05:00
|
|
|
if ((mac_low >= 0x346a85c7) && (mac_low <= 0x346a85f8)) {
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
} else {
|
2017-05-05 10:24:56 -04:00
|
|
|
ESP_LOGE(TAG, "Base MAC address from BLK0 of EFUSE CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc);
|
2016-11-21 04:15:37 -05:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
esp_err_t system_efuse_read_mac(uint8_t *mac) __attribute__((alias("esp_efuse_mac_get_default")));
|
|
|
|
esp_err_t esp_efuse_read_mac(uint8_t *mac) __attribute__((alias("esp_efuse_mac_get_default")));
|
2016-11-21 10:05:23 -05:00
|
|
|
|
2018-09-05 02:17:05 -04:00
|
|
|
esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac)
|
2017-03-02 01:57:45 -05:00
|
|
|
{
|
|
|
|
uint8_t idx;
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
if (local_mac == NULL || universal_mac == NULL) {
|
2017-03-02 01:57:45 -05:00
|
|
|
ESP_LOGE(TAG, "mac address param is NULL");
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
memcpy(local_mac, universal_mac, 6);
|
2017-03-02 01:57:45 -05:00
|
|
|
for (idx = 0; idx < 64; idx++) {
|
2017-05-05 10:24:56 -04:00
|
|
|
local_mac[0] = universal_mac[0] | 0x02;
|
|
|
|
local_mac[0] ^= idx << 2;
|
2017-03-02 01:57:45 -05:00
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
if (memcmp(local_mac, universal_mac, 6)) {
|
2017-03-02 01:57:45 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type)
|
2017-03-01 07:42:46 -05:00
|
|
|
{
|
|
|
|
uint8_t efuse_mac[6];
|
|
|
|
|
|
|
|
if (mac == NULL) {
|
|
|
|
ESP_LOGE(TAG, "mac address param is NULL");
|
2017-03-02 01:57:45 -05:00
|
|
|
return ESP_ERR_INVALID_ARG;
|
2017-03-01 07:42:46 -05:00
|
|
|
}
|
|
|
|
|
2017-03-02 01:57:45 -05:00
|
|
|
if (type < ESP_MAC_WIFI_STA || type > ESP_MAC_ETH) {
|
2017-05-05 10:24:56 -04:00
|
|
|
ESP_LOGE(TAG, "mac type is incorrect");
|
2017-03-02 01:57:45 -05:00
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
_Static_assert(UNIVERSAL_MAC_ADDR_NUM == FOUR_UNIVERSAL_MAC_ADDR \
|
|
|
|
|| UNIVERSAL_MAC_ADDR_NUM == TWO_UNIVERSAL_MAC_ADDR, \
|
2017-03-02 01:57:45 -05:00
|
|
|
"incorrect NUM_MAC_ADDRESS_FROM_EFUSE value");
|
|
|
|
|
2017-05-05 10:24:56 -04:00
|
|
|
if (esp_base_mac_addr_get(efuse_mac) != ESP_OK) {
|
|
|
|
esp_efuse_mac_get_default(efuse_mac);
|
|
|
|
}
|
2017-03-01 07:42:46 -05:00
|
|
|
|
2017-03-02 01:57:45 -05:00
|
|
|
switch (type) {
|
2017-03-01 07:42:46 -05:00
|
|
|
case ESP_MAC_WIFI_STA:
|
|
|
|
memcpy(mac, efuse_mac, 6);
|
|
|
|
break;
|
|
|
|
case ESP_MAC_WIFI_SOFTAP:
|
2017-05-05 10:24:56 -04:00
|
|
|
if (UNIVERSAL_MAC_ADDR_NUM == FOUR_UNIVERSAL_MAC_ADDR) {
|
2017-03-02 01:57:45 -05:00
|
|
|
memcpy(mac, efuse_mac, 6);
|
|
|
|
mac[5] += 1;
|
|
|
|
}
|
2017-05-05 10:24:56 -04:00
|
|
|
else if (UNIVERSAL_MAC_ADDR_NUM == TWO_UNIVERSAL_MAC_ADDR) {
|
2018-09-05 02:17:05 -04:00
|
|
|
esp_derive_local_mac(mac, efuse_mac);
|
2017-03-02 01:57:45 -05:00
|
|
|
}
|
2017-03-01 07:42:46 -05:00
|
|
|
break;
|
|
|
|
case ESP_MAC_BT:
|
|
|
|
memcpy(mac, efuse_mac, 6);
|
2017-05-05 10:24:56 -04:00
|
|
|
if (UNIVERSAL_MAC_ADDR_NUM == FOUR_UNIVERSAL_MAC_ADDR) {
|
2017-03-02 01:57:45 -05:00
|
|
|
mac[5] += 2;
|
|
|
|
}
|
2017-05-05 10:24:56 -04:00
|
|
|
else if (UNIVERSAL_MAC_ADDR_NUM == TWO_UNIVERSAL_MAC_ADDR) {
|
2017-03-02 01:57:45 -05:00
|
|
|
mac[5] += 1;
|
|
|
|
}
|
2017-03-01 07:42:46 -05:00
|
|
|
break;
|
|
|
|
case ESP_MAC_ETH:
|
2017-05-05 10:24:56 -04:00
|
|
|
if (UNIVERSAL_MAC_ADDR_NUM == FOUR_UNIVERSAL_MAC_ADDR) {
|
2017-03-02 01:57:45 -05:00
|
|
|
memcpy(mac, efuse_mac, 6);
|
|
|
|
mac[5] += 3;
|
|
|
|
}
|
2017-05-05 10:24:56 -04:00
|
|
|
else if (UNIVERSAL_MAC_ADDR_NUM == TWO_UNIVERSAL_MAC_ADDR) {
|
2017-03-02 01:57:45 -05:00
|
|
|
efuse_mac[5] += 1;
|
2018-09-05 02:17:05 -04:00
|
|
|
esp_derive_local_mac(mac, efuse_mac);
|
2017-03-02 01:57:45 -05:00
|
|
|
}
|
2017-03-01 07:42:46 -05:00
|
|
|
break;
|
|
|
|
default:
|
2017-03-02 01:57:45 -05:00
|
|
|
ESP_LOGW(TAG, "incorrect mac type");
|
2017-03-01 07:42:46 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
2016-11-21 04:15:37 -05:00
|
|
|
|
2017-08-07 06:30:46 -04:00
|
|
|
esp_err_t esp_register_shutdown_handler(shutdown_handler_t handler)
|
2017-06-15 06:00:49 -04:00
|
|
|
{
|
2019-04-08 07:30:07 -04:00
|
|
|
for (int i = 0; i < SHUTDOWN_HANDLERS_NO; i++) {
|
|
|
|
if (shutdown_handlers[i] == handler) {
|
|
|
|
return ESP_ERR_INVALID_STATE;
|
|
|
|
} else if (shutdown_handlers[i] == NULL) {
|
|
|
|
shutdown_handlers[i] = handler;
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ESP_ERR_NO_MEM;
|
2017-06-15 06:00:49 -04:00
|
|
|
}
|
|
|
|
|
2019-04-08 07:29:44 -04:00
|
|
|
esp_err_t esp_unregister_shutdown_handler(shutdown_handler_t handler)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < SHUTDOWN_HANDLERS_NO; i++) {
|
|
|
|
if (shutdown_handlers[i] == handler) {
|
|
|
|
shutdown_handlers[i] = NULL;
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ESP_ERR_INVALID_STATE;
|
|
|
|
}
|
|
|
|
|
2017-08-07 06:30:46 -04:00
|
|
|
void esp_restart_noos() __attribute__ ((noreturn));
|
2017-06-15 06:00:49 -04:00
|
|
|
|
2016-11-21 10:05:23 -05:00
|
|
|
void IRAM_ATTR esp_restart(void)
|
2016-11-21 04:15:37 -05:00
|
|
|
{
|
2017-08-07 06:30:46 -04:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < SHUTDOWN_HANDLERS_NO; i++) {
|
|
|
|
if (shutdown_handlers[i]) {
|
|
|
|
shutdown_handlers[i]();
|
|
|
|
}
|
|
|
|
}
|
2016-11-21 04:15:37 -05:00
|
|
|
|
|
|
|
// Disable scheduler on this core.
|
|
|
|
vTaskSuspendAll();
|
2017-01-12 22:30:00 -05:00
|
|
|
|
|
|
|
esp_restart_noos();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* "inner" restart function for after RTOS, interrupts & anything else on this
|
|
|
|
* core are already stopped. Stalls other core, resets hardware,
|
|
|
|
* triggers restart.
|
|
|
|
*/
|
|
|
|
void IRAM_ATTR esp_restart_noos()
|
|
|
|
{
|
esp_restart: fix possible race while stalling other CPU, enable WDT early
Previously esp_restart would stall the other CPU before enabling RTC_WDT.
If the other CPU was executing an s32c1i instruction, the lock signal
from CPU to the arbiter would still be held after CPU was stalled. If
the CPU running esp_restart would then try to access the same locked
memory pool, it would be stuck, because lock signal would never be
released.
With this change, esp_restart resets the other CPU before stalling it.
Ideally, we would want to reset the CPU and keep it in reset, but the
hardware doesn't have such feature for PRO_CPU (it is possible to hold
APP_CPU in reset using DPORT register). Given that ROM code will not use
s32c1i in the first few hundred cycles, doing reset and then stall seems
to be safe.
In addition to than, RTC_WDT initialization is moved to the beginning of
the function, to prevent possible lock-up if CPU stalling still has any
issue.
2017-10-26 07:11:47 -04:00
|
|
|
// Disable interrupts
|
|
|
|
xt_ints_off(0xFFFFFFFF);
|
2017-06-14 06:00:26 -04:00
|
|
|
|
esp_restart: fix possible race while stalling other CPU, enable WDT early
Previously esp_restart would stall the other CPU before enabling RTC_WDT.
If the other CPU was executing an s32c1i instruction, the lock signal
from CPU to the arbiter would still be held after CPU was stalled. If
the CPU running esp_restart would then try to access the same locked
memory pool, it would be stuck, because lock signal would never be
released.
With this change, esp_restart resets the other CPU before stalling it.
Ideally, we would want to reset the CPU and keep it in reset, but the
hardware doesn't have such feature for PRO_CPU (it is possible to hold
APP_CPU in reset using DPORT register). Given that ROM code will not use
s32c1i in the first few hundred cycles, doing reset and then stall seems
to be safe.
In addition to than, RTC_WDT initialization is moved to the beginning of
the function, to prevent possible lock-up if CPU stalling still has any
issue.
2017-10-26 07:11:47 -04:00
|
|
|
// Enable RTC watchdog for 1 second
|
2018-07-23 06:59:37 -04:00
|
|
|
rtc_wdt_protect_off();
|
|
|
|
rtc_wdt_disable();
|
|
|
|
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
|
|
|
|
rtc_wdt_set_stage(RTC_WDT_STAGE1, RTC_WDT_STAGE_ACTION_RESET_SYSTEM);
|
|
|
|
rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_200ns);
|
|
|
|
rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_200ns);
|
|
|
|
rtc_wdt_set_time(RTC_WDT_STAGE0, 1000);
|
2019-01-10 07:17:04 -05:00
|
|
|
rtc_wdt_flashboot_mode_enable();
|
2016-11-21 04:15:37 -05:00
|
|
|
|
esp_restart: fix possible race while stalling other CPU, enable WDT early
Previously esp_restart would stall the other CPU before enabling RTC_WDT.
If the other CPU was executing an s32c1i instruction, the lock signal
from CPU to the arbiter would still be held after CPU was stalled. If
the CPU running esp_restart would then try to access the same locked
memory pool, it would be stuck, because lock signal would never be
released.
With this change, esp_restart resets the other CPU before stalling it.
Ideally, we would want to reset the CPU and keep it in reset, but the
hardware doesn't have such feature for PRO_CPU (it is possible to hold
APP_CPU in reset using DPORT register). Given that ROM code will not use
s32c1i in the first few hundred cycles, doing reset and then stall seems
to be safe.
In addition to than, RTC_WDT initialization is moved to the beginning of
the function, to prevent possible lock-up if CPU stalling still has any
issue.
2017-10-26 07:11:47 -04:00
|
|
|
// Reset and stall the other CPU.
|
|
|
|
// CPU must be reset before stalling, in case it was running a s32c1i
|
|
|
|
// instruction. This would cause memory pool to be locked by arbiter
|
|
|
|
// to the stalled CPU, preventing current CPU from accessing this pool.
|
|
|
|
const uint32_t core_id = xPortGetCoreID();
|
|
|
|
const uint32_t other_core_id = (core_id == 0) ? 1 : 0;
|
|
|
|
esp_cpu_reset(other_core_id);
|
|
|
|
esp_cpu_stall(other_core_id);
|
|
|
|
|
|
|
|
// Other core is now stalled, can access DPORT registers directly
|
|
|
|
esp_dport_access_int_abort();
|
|
|
|
|
2016-11-21 04:15:37 -05:00
|
|
|
// Disable TG0/TG1 watchdogs
|
|
|
|
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
|
|
|
TIMERG0.wdt_config0.en = 0;
|
|
|
|
TIMERG0.wdt_wprotect=0;
|
|
|
|
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
|
|
|
TIMERG1.wdt_config0.en = 0;
|
|
|
|
TIMERG1.wdt_wprotect=0;
|
|
|
|
|
esp_restart: fix possible race while stalling other CPU, enable WDT early
Previously esp_restart would stall the other CPU before enabling RTC_WDT.
If the other CPU was executing an s32c1i instruction, the lock signal
from CPU to the arbiter would still be held after CPU was stalled. If
the CPU running esp_restart would then try to access the same locked
memory pool, it would be stuck, because lock signal would never be
released.
With this change, esp_restart resets the other CPU before stalling it.
Ideally, we would want to reset the CPU and keep it in reset, but the
hardware doesn't have such feature for PRO_CPU (it is possible to hold
APP_CPU in reset using DPORT register). Given that ROM code will not use
s32c1i in the first few hundred cycles, doing reset and then stall seems
to be safe.
In addition to than, RTC_WDT initialization is moved to the beginning of
the function, to prevent possible lock-up if CPU stalling still has any
issue.
2017-10-26 07:11:47 -04:00
|
|
|
// Flush any data left in UART FIFOs
|
|
|
|
uart_tx_wait_idle(0);
|
|
|
|
uart_tx_wait_idle(1);
|
|
|
|
uart_tx_wait_idle(2);
|
2016-11-21 04:15:37 -05:00
|
|
|
|
|
|
|
// Disable cache
|
|
|
|
Cache_Read_Disable(0);
|
|
|
|
Cache_Read_Disable(1);
|
|
|
|
|
2017-11-06 03:44:26 -05:00
|
|
|
// 2nd stage bootloader reconfigures SPI flash signals.
|
|
|
|
// Reset them to the defaults expected by ROM.
|
2017-09-04 07:00:47 -04:00
|
|
|
WRITE_PERI_REG(GPIO_FUNC0_IN_SEL_CFG_REG, 0x30);
|
|
|
|
WRITE_PERI_REG(GPIO_FUNC1_IN_SEL_CFG_REG, 0x30);
|
|
|
|
WRITE_PERI_REG(GPIO_FUNC2_IN_SEL_CFG_REG, 0x30);
|
|
|
|
WRITE_PERI_REG(GPIO_FUNC3_IN_SEL_CFG_REG, 0x30);
|
|
|
|
WRITE_PERI_REG(GPIO_FUNC4_IN_SEL_CFG_REG, 0x30);
|
|
|
|
WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30);
|
|
|
|
|
2017-01-06 00:49:42 -05:00
|
|
|
// Reset wifi/bluetooth/ethernet/sdio (bb/mac)
|
2017-05-08 08:03:04 -04:00
|
|
|
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG,
|
2017-01-06 00:49:42 -05:00
|
|
|
DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST |
|
|
|
|
DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST |
|
|
|
|
DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST |
|
2017-02-28 20:01:07 -05:00
|
|
|
DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST);
|
2017-05-08 08:03:04 -04:00
|
|
|
DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0);
|
2016-11-21 04:15:37 -05:00
|
|
|
|
|
|
|
// Reset timer/spi/uart
|
2017-05-08 08:03:04 -04:00
|
|
|
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,
|
2018-04-24 04:38:46 -04:00
|
|
|
DPORT_TIMERS_RST | DPORT_SPI01_RST | DPORT_UART_RST);
|
2017-05-08 08:03:04 -04:00
|
|
|
DPORT_REG_WRITE(DPORT_PERIP_RST_EN_REG, 0);
|
2016-11-21 04:15:37 -05:00
|
|
|
|
2017-01-03 23:36:40 -05:00
|
|
|
// Set CPU back to XTAL source, no PLL, same as hard reset
|
2018-07-29 03:50:49 -04:00
|
|
|
rtc_clk_cpu_freq_set_xtal();
|
2017-01-03 23:36:40 -05:00
|
|
|
|
2017-06-14 06:07:15 -04:00
|
|
|
// Clear entry point for APP CPU
|
|
|
|
DPORT_REG_WRITE(DPORT_APPCPU_CTRL_D_REG, 0);
|
|
|
|
|
2016-11-21 04:15:37 -05:00
|
|
|
// Reset CPUs
|
|
|
|
if (core_id == 0) {
|
|
|
|
// Running on PRO CPU: APP CPU is stalled. Can reset both CPUs.
|
esp_restart: fix possible race while stalling other CPU, enable WDT early
Previously esp_restart would stall the other CPU before enabling RTC_WDT.
If the other CPU was executing an s32c1i instruction, the lock signal
from CPU to the arbiter would still be held after CPU was stalled. If
the CPU running esp_restart would then try to access the same locked
memory pool, it would be stuck, because lock signal would never be
released.
With this change, esp_restart resets the other CPU before stalling it.
Ideally, we would want to reset the CPU and keep it in reset, but the
hardware doesn't have such feature for PRO_CPU (it is possible to hold
APP_CPU in reset using DPORT register). Given that ROM code will not use
s32c1i in the first few hundred cycles, doing reset and then stall seems
to be safe.
In addition to than, RTC_WDT initialization is moved to the beginning of
the function, to prevent possible lock-up if CPU stalling still has any
issue.
2017-10-26 07:11:47 -04:00
|
|
|
esp_cpu_reset(1);
|
|
|
|
esp_cpu_reset(0);
|
2016-11-21 04:15:37 -05:00
|
|
|
} else {
|
|
|
|
// Running on APP CPU: need to reset PRO CPU and unstall it,
|
2017-06-14 06:07:15 -04:00
|
|
|
// then reset APP CPU
|
esp_restart: fix possible race while stalling other CPU, enable WDT early
Previously esp_restart would stall the other CPU before enabling RTC_WDT.
If the other CPU was executing an s32c1i instruction, the lock signal
from CPU to the arbiter would still be held after CPU was stalled. If
the CPU running esp_restart would then try to access the same locked
memory pool, it would be stuck, because lock signal would never be
released.
With this change, esp_restart resets the other CPU before stalling it.
Ideally, we would want to reset the CPU and keep it in reset, but the
hardware doesn't have such feature for PRO_CPU (it is possible to hold
APP_CPU in reset using DPORT register). Given that ROM code will not use
s32c1i in the first few hundred cycles, doing reset and then stall seems
to be safe.
In addition to than, RTC_WDT initialization is moved to the beginning of
the function, to prevent possible lock-up if CPU stalling still has any
issue.
2017-10-26 07:11:47 -04:00
|
|
|
esp_cpu_reset(0);
|
2016-11-21 04:15:37 -05:00
|
|
|
esp_cpu_unstall(0);
|
esp_restart: fix possible race while stalling other CPU, enable WDT early
Previously esp_restart would stall the other CPU before enabling RTC_WDT.
If the other CPU was executing an s32c1i instruction, the lock signal
from CPU to the arbiter would still be held after CPU was stalled. If
the CPU running esp_restart would then try to access the same locked
memory pool, it would be stuck, because lock signal would never be
released.
With this change, esp_restart resets the other CPU before stalling it.
Ideally, we would want to reset the CPU and keep it in reset, but the
hardware doesn't have such feature for PRO_CPU (it is possible to hold
APP_CPU in reset using DPORT register). Given that ROM code will not use
s32c1i in the first few hundred cycles, doing reset and then stall seems
to be safe.
In addition to than, RTC_WDT initialization is moved to the beginning of
the function, to prevent possible lock-up if CPU stalling still has any
issue.
2017-10-26 07:11:47 -04:00
|
|
|
esp_cpu_reset(1);
|
2016-11-21 04:15:37 -05:00
|
|
|
}
|
|
|
|
while(true) {
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-21 10:05:23 -05:00
|
|
|
void system_restart(void) __attribute__((alias("esp_restart")));
|
|
|
|
|
2017-05-03 04:03:28 -04:00
|
|
|
uint32_t esp_get_free_heap_size( void )
|
|
|
|
{
|
2017-09-22 04:02:39 -04:00
|
|
|
return heap_caps_get_free_size( MALLOC_CAP_DEFAULT );
|
2017-05-03 04:03:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t esp_get_minimum_free_heap_size( void )
|
|
|
|
{
|
2017-09-22 04:02:39 -04:00
|
|
|
return heap_caps_get_minimum_free_size( MALLOC_CAP_DEFAULT );
|
2016-11-21 04:15:37 -05:00
|
|
|
}
|
|
|
|
|
2016-11-21 10:05:23 -05:00
|
|
|
uint32_t system_get_free_heap_size(void) __attribute__((alias("esp_get_free_heap_size")));
|
2016-11-21 04:15:37 -05:00
|
|
|
|
|
|
|
const char* system_get_sdk_version(void)
|
|
|
|
{
|
|
|
|
return "master";
|
|
|
|
}
|
|
|
|
|
2017-01-17 03:52:42 -05:00
|
|
|
const char* esp_get_idf_version(void)
|
|
|
|
{
|
|
|
|
return IDF_VER;
|
|
|
|
}
|
2016-11-21 04:15:37 -05:00
|
|
|
|
2017-03-02 07:51:37 -05:00
|
|
|
static void get_chip_info_esp32(esp_chip_info_t* out_info)
|
|
|
|
{
|
|
|
|
uint32_t reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
|
|
|
|
memset(out_info, 0, sizeof(*out_info));
|
2018-03-22 07:55:52 -04:00
|
|
|
|
|
|
|
out_info->model = CHIP_ESP32;
|
2017-03-02 07:51:37 -05:00
|
|
|
if ((reg & EFUSE_RD_CHIP_VER_REV1_M) != 0) {
|
|
|
|
out_info->revision = 1;
|
|
|
|
}
|
|
|
|
if ((reg & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) {
|
|
|
|
out_info->cores = 2;
|
|
|
|
} else {
|
|
|
|
out_info->cores = 1;
|
|
|
|
}
|
|
|
|
out_info->features = CHIP_FEATURE_WIFI_BGN;
|
|
|
|
if ((reg & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) {
|
|
|
|
out_info->features |= CHIP_FEATURE_BT | CHIP_FEATURE_BLE;
|
|
|
|
}
|
2017-11-03 02:54:02 -04:00
|
|
|
int package = (reg & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S;
|
|
|
|
if (package == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 ||
|
|
|
|
package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 ||
|
|
|
|
package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
|
2017-03-02 07:51:37 -05:00
|
|
|
out_info->features |= CHIP_FEATURE_EMB_FLASH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void esp_chip_info(esp_chip_info_t* out_info)
|
|
|
|
{
|
|
|
|
// Only ESP32 is supported now, in the future call one of the
|
|
|
|
// chip-specific functions based on sdkconfig choice
|
|
|
|
return get_chip_info_esp32(out_info);
|
|
|
|
}
|