mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-27 07:40:59 +00:00
Merge branch 'sdcard-dma'
This commit is contained in:
commit
046ff607d3
@ -280,6 +280,7 @@ SOURCE_MICROPYTHON_SPEED = [
|
|||||||
SOURCE_STMHAL = [
|
SOURCE_STMHAL = [
|
||||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c',
|
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c',
|
||||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c',
|
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c',
|
||||||
|
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c',
|
||||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c',
|
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c',
|
||||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c',
|
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c',
|
||||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c',
|
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c',
|
||||||
@ -309,6 +310,7 @@ SOURCE_FIRMWARE = [
|
|||||||
|
|
||||||
SOURCE_TREZORHAL = [
|
SOURCE_TREZORHAL = [
|
||||||
'embed/trezorhal/common.c',
|
'embed/trezorhal/common.c',
|
||||||
|
'embed/trezorhal/dma.c',
|
||||||
'embed/trezorhal/flash.c',
|
'embed/trezorhal/flash.c',
|
||||||
'embed/trezorhal/mini_printf.c',
|
'embed/trezorhal/mini_printf.c',
|
||||||
'embed/trezorhal/mpu.c',
|
'embed/trezorhal/mpu.c',
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "mpu.h"
|
#include "mpu.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
|
#include "supervise.h"
|
||||||
#include "touch.h"
|
#include "touch.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
@ -108,11 +109,66 @@ int main(void) {
|
|||||||
// MicroPython default exception handler
|
// MicroPython default exception handler
|
||||||
|
|
||||||
void __attribute__((noreturn)) nlr_jump_fail(void *val) {
|
void __attribute__((noreturn)) nlr_jump_fail(void *val) {
|
||||||
ensure(secfalse, "uncaught exception");
|
error_shutdown("Internal error", "(UE)", NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// interrupt handlers
|
||||||
|
|
||||||
|
void NMI_Handler(void) {
|
||||||
|
// Clock Security System triggered NMI
|
||||||
|
if ((RCC->CIR & RCC_CIR_CSSF) != 0) {
|
||||||
|
error_shutdown("Internal error", "(CS)", NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HardFault_Handler(void) {
|
||||||
|
error_shutdown("Internal error", "(HF)", NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemManage_Handler(void) {
|
||||||
|
error_shutdown("Internal error", "(MM)", NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusFault_Handler(void) {
|
||||||
|
error_shutdown("Internal error", "(BF)", NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsageFault_Handler(void) {
|
||||||
|
error_shutdown("Internal error", "(UF)", NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PendSV_Handler(void) { pendsv_isr_handler(); }
|
void PendSV_Handler(void) { pendsv_isr_handler(); }
|
||||||
|
|
||||||
|
void SVC_C_Handler(uint32_t *stack) {
|
||||||
|
uint8_t svc_number = ((uint8_t *)stack[6])[-2];
|
||||||
|
switch (svc_number) {
|
||||||
|
case SVC_ENABLE_IRQ:
|
||||||
|
HAL_NVIC_EnableIRQ(stack[0]);
|
||||||
|
break;
|
||||||
|
case SVC_DISABLE_IRQ:
|
||||||
|
HAL_NVIC_DisableIRQ(stack[0]);
|
||||||
|
break;
|
||||||
|
case SVC_SET_PRIORITY:
|
||||||
|
NVIC_SetPriority(stack[0], stack[1]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stack[0] = 0xffffffff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((naked)) void SVC_Handler(void) {
|
||||||
|
__asm volatile(
|
||||||
|
" tst lr, #4 \n" // Test Bit 3 to see which stack pointer we should
|
||||||
|
// use.
|
||||||
|
" ite eq \n" // Tell the assembler that the nest 2 instructions
|
||||||
|
// are if-then-else
|
||||||
|
" mrseq r0, msp \n" // Make R0 point to main stack pointer
|
||||||
|
" mrsne r0, psp \n" // Make R0 point to process stack pointer
|
||||||
|
" b SVC_C_Handler \n" // Off to C land
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// MicroPython builtin stubs
|
// MicroPython builtin stubs
|
||||||
|
|
||||||
mp_import_stat_t mp_import_stat(const char *path) {
|
mp_import_stat_t mp_import_stat(const char *path) {
|
||||||
|
@ -211,6 +211,7 @@ static inline mp_uint_t disable_irq(void) {
|
|||||||
#define MICROPY_HW_BOARD_NAME "TREZORv2"
|
#define MICROPY_HW_BOARD_NAME "TREZORv2"
|
||||||
#define MICROPY_HW_MCU_NAME "STM32F427xx"
|
#define MICROPY_HW_MCU_NAME "STM32F427xx"
|
||||||
#define MICROPY_PY_SYS_PLATFORM "trezor"
|
#define MICROPY_PY_SYS_PLATFORM "trezor"
|
||||||
|
#define MICROPY_HW_HAS_SDCARD 1
|
||||||
|
|
||||||
// There is no classical C heap in bare-metal ports, only Python
|
// There is no classical C heap in bare-metal ports, only Python
|
||||||
// garbage-collected heap. For completeness, emulate C heap via
|
// garbage-collected heap. For completeness, emulate C heap via
|
||||||
|
22
core/embed/firmware/supervise.h
Normal file
22
core/embed/firmware/supervise.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// supervisor call functions
|
||||||
|
|
||||||
|
#define SVC_ENABLE_IRQ 0
|
||||||
|
#define SVC_DISABLE_IRQ 1
|
||||||
|
#define SVC_SET_PRIORITY 2
|
||||||
|
|
||||||
|
inline void svc_enableIRQ(uint32_t IRQn) {
|
||||||
|
register uint32_t r0 __asm__("r0") = IRQn;
|
||||||
|
__asm__ __volatile__("svc %0" ::"i"(SVC_ENABLE_IRQ), "r"(r0) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void svc_disableIRQ(uint32_t IRQn) {
|
||||||
|
register uint32_t r0 __asm__("r0") = IRQn;
|
||||||
|
__asm__ __volatile__("svc %0" ::"i"(SVC_DISABLE_IRQ), "r"(r0) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void svc_setpriority(uint32_t IRQn, uint32_t priority) {
|
||||||
|
register uint32_t r0 __asm__("r0") = IRQn;
|
||||||
|
register uint32_t r1 __asm__("r1") = priority;
|
||||||
|
__asm__ __volatile__("svc %0" ::"i"(SVC_SET_PRIORITY), "r"(r0), "r"(r1)
|
||||||
|
: "memory");
|
||||||
|
}
|
@ -163,7 +163,7 @@ void clear_otg_hs_memory(void) {
|
|||||||
uint32_t __stack_chk_guard = 0;
|
uint32_t __stack_chk_guard = 0;
|
||||||
|
|
||||||
void __attribute__((noreturn)) __stack_chk_fail(void) {
|
void __attribute__((noreturn)) __stack_chk_fail(void) {
|
||||||
ensure(secfalse, "Stack smashing detected");
|
error_shutdown("Internal error", "(SS)", NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
|
uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
|
||||||
|
306
core/embed/trezorhal/dma.c
Normal file
306
core/embed/trezorhal/dma.c
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
// clang-format off
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2019 Damien P. George
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "py/obj.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "irq.h"
|
||||||
|
#include "systick.h"
|
||||||
|
#include "supervise.h"
|
||||||
|
|
||||||
|
#define DMA_IDLE_ENABLED() (dma_idle.enabled != 0)
|
||||||
|
#define DMA_SYSTICK_LOG2 (3)
|
||||||
|
#define DMA_SYSTICK_MASK ((1 << DMA_SYSTICK_LOG2) - 1)
|
||||||
|
#define DMA_IDLE_TICK_MAX (8) // 8*8 = 64 msec
|
||||||
|
#define DMA_IDLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & DMA_SYSTICK_MASK) == 0)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
dma_id_not_defined=-1,
|
||||||
|
dma_id_0,
|
||||||
|
dma_id_1,
|
||||||
|
dma_id_2,
|
||||||
|
dma_id_3,
|
||||||
|
dma_id_4,
|
||||||
|
dma_id_5,
|
||||||
|
dma_id_6,
|
||||||
|
dma_id_7,
|
||||||
|
dma_id_8,
|
||||||
|
dma_id_9,
|
||||||
|
dma_id_10,
|
||||||
|
dma_id_11,
|
||||||
|
dma_id_12,
|
||||||
|
dma_id_13,
|
||||||
|
dma_id_14,
|
||||||
|
dma_id_15,
|
||||||
|
} dma_id_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint16_t enabled; // Used to test if both counters are == 0
|
||||||
|
uint8_t counter[2];
|
||||||
|
} dma_idle_count_t;
|
||||||
|
|
||||||
|
struct _dma_descr_t {
|
||||||
|
DMA_Stream_TypeDef *instance;
|
||||||
|
uint32_t sub_instance;
|
||||||
|
dma_id_t id;
|
||||||
|
const DMA_InitTypeDef *init;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parameters to dma_init() for SDIO tx and rx.
|
||||||
|
static const DMA_InitTypeDef dma_init_struct_sdio = {
|
||||||
|
.Channel = 0,
|
||||||
|
.Direction = 0,
|
||||||
|
.PeriphInc = DMA_PINC_DISABLE,
|
||||||
|
.MemInc = DMA_MINC_ENABLE,
|
||||||
|
.PeriphDataAlignment = DMA_PDATAALIGN_WORD,
|
||||||
|
.MemDataAlignment = DMA_MDATAALIGN_WORD,
|
||||||
|
.Mode = DMA_PFCTRL,
|
||||||
|
.Priority = DMA_PRIORITY_VERY_HIGH,
|
||||||
|
.FIFOMode = DMA_FIFOMODE_ENABLE,
|
||||||
|
.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL,
|
||||||
|
.MemBurst = DMA_MBURST_INC4,
|
||||||
|
.PeriphBurst = DMA_PBURST_INC4,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NCONTROLLERS (2)
|
||||||
|
#define NSTREAMS_PER_CONTROLLER (8)
|
||||||
|
#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER)
|
||||||
|
|
||||||
|
#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (((dma_channel) & DMA_SxCR_CHSEL) >> 25)
|
||||||
|
|
||||||
|
#define DMA1_ENABLE_MASK (0x00ff) // Bits in dma_enable_mask corresponding to DMA1
|
||||||
|
#define DMA2_ENABLE_MASK (0xff00) // Bits in dma_enable_mask corresponding to DMA2
|
||||||
|
|
||||||
|
const dma_descr_t dma_SDIO_0 = { DMA2_Stream3, DMA_CHANNEL_4, dma_id_11, &dma_init_struct_sdio };
|
||||||
|
|
||||||
|
static const uint8_t dma_irqn[NSTREAM] = {
|
||||||
|
DMA1_Stream0_IRQn,
|
||||||
|
DMA1_Stream1_IRQn,
|
||||||
|
DMA1_Stream2_IRQn,
|
||||||
|
DMA1_Stream3_IRQn,
|
||||||
|
DMA1_Stream4_IRQn,
|
||||||
|
DMA1_Stream5_IRQn,
|
||||||
|
DMA1_Stream6_IRQn,
|
||||||
|
DMA1_Stream7_IRQn,
|
||||||
|
DMA2_Stream0_IRQn,
|
||||||
|
DMA2_Stream1_IRQn,
|
||||||
|
DMA2_Stream2_IRQn,
|
||||||
|
DMA2_Stream3_IRQn,
|
||||||
|
DMA2_Stream4_IRQn,
|
||||||
|
DMA2_Stream5_IRQn,
|
||||||
|
DMA2_Stream6_IRQn,
|
||||||
|
DMA2_Stream7_IRQn,
|
||||||
|
};
|
||||||
|
|
||||||
|
static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL};
|
||||||
|
static uint8_t dma_last_sub_instance[NSTREAM];
|
||||||
|
static volatile uint32_t dma_enable_mask = 0;
|
||||||
|
volatile dma_idle_count_t dma_idle;
|
||||||
|
|
||||||
|
#define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid
|
||||||
|
|
||||||
|
#define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0)
|
||||||
|
#define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0)
|
||||||
|
|
||||||
|
void DMA1_Stream0_IRQHandler(void) { IRQ_ENTER(DMA1_Stream0_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Stream0_IRQn); }
|
||||||
|
void DMA1_Stream1_IRQHandler(void) { IRQ_ENTER(DMA1_Stream1_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Stream1_IRQn); }
|
||||||
|
void DMA1_Stream2_IRQHandler(void) { IRQ_ENTER(DMA1_Stream2_IRQn); if (dma_handle[dma_id_2] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_2]); } IRQ_EXIT(DMA1_Stream2_IRQn); }
|
||||||
|
void DMA1_Stream3_IRQHandler(void) { IRQ_ENTER(DMA1_Stream3_IRQn); if (dma_handle[dma_id_3] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_3]); } IRQ_EXIT(DMA1_Stream3_IRQn); }
|
||||||
|
void DMA1_Stream4_IRQHandler(void) { IRQ_ENTER(DMA1_Stream4_IRQn); if (dma_handle[dma_id_4] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_4]); } IRQ_EXIT(DMA1_Stream4_IRQn); }
|
||||||
|
void DMA1_Stream5_IRQHandler(void) { IRQ_ENTER(DMA1_Stream5_IRQn); if (dma_handle[dma_id_5] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_5]); } IRQ_EXIT(DMA1_Stream5_IRQn); }
|
||||||
|
void DMA1_Stream6_IRQHandler(void) { IRQ_ENTER(DMA1_Stream6_IRQn); if (dma_handle[dma_id_6] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_6]); } IRQ_EXIT(DMA1_Stream6_IRQn); }
|
||||||
|
void DMA1_Stream7_IRQHandler(void) { IRQ_ENTER(DMA1_Stream7_IRQn); if (dma_handle[dma_id_7] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_7]); } IRQ_EXIT(DMA1_Stream7_IRQn); }
|
||||||
|
void DMA2_Stream0_IRQHandler(void) { IRQ_ENTER(DMA2_Stream0_IRQn); if (dma_handle[dma_id_8] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_8]); } IRQ_EXIT(DMA2_Stream0_IRQn); }
|
||||||
|
void DMA2_Stream1_IRQHandler(void) { IRQ_ENTER(DMA2_Stream1_IRQn); if (dma_handle[dma_id_9] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_9]); } IRQ_EXIT(DMA2_Stream1_IRQn); }
|
||||||
|
void DMA2_Stream2_IRQHandler(void) { IRQ_ENTER(DMA2_Stream2_IRQn); if (dma_handle[dma_id_10] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_10]); } IRQ_EXIT(DMA2_Stream2_IRQn); }
|
||||||
|
void DMA2_Stream3_IRQHandler(void) { IRQ_ENTER(DMA2_Stream3_IRQn); if (dma_handle[dma_id_11] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_11]); } IRQ_EXIT(DMA2_Stream3_IRQn); }
|
||||||
|
void DMA2_Stream4_IRQHandler(void) { IRQ_ENTER(DMA2_Stream4_IRQn); if (dma_handle[dma_id_12] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_12]); } IRQ_EXIT(DMA2_Stream4_IRQn); }
|
||||||
|
void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handle[dma_id_13] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_13]); } IRQ_EXIT(DMA2_Stream5_IRQn); }
|
||||||
|
void DMA2_Stream6_IRQHandler(void) { IRQ_ENTER(DMA2_Stream6_IRQn); if (dma_handle[dma_id_14] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_14]); } IRQ_EXIT(DMA2_Stream6_IRQn); }
|
||||||
|
void DMA2_Stream7_IRQHandler(void) { IRQ_ENTER(DMA2_Stream7_IRQn); if (dma_handle[dma_id_15] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_15]); } IRQ_EXIT(DMA2_Stream7_IRQn); }
|
||||||
|
|
||||||
|
static void dma_idle_handler(uint32_t tick);
|
||||||
|
|
||||||
|
// Resets the idle counter for the DMA controller associated with dma_id.
|
||||||
|
static void dma_tickle(dma_id_t dma_id) {
|
||||||
|
dma_idle.counter[(dma_id < NSTREAMS_PER_CONTROLLER) ? 0 : 1] = 1;
|
||||||
|
systick_enable_dispatch(SYSTICK_DISPATCH_DMA, dma_idle_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dma_enable_clock(dma_id_t dma_id) {
|
||||||
|
// We don't want dma_tick_handler() to turn off the clock right after we
|
||||||
|
// enable it, so we need to mark the channel in use in an atomic fashion.
|
||||||
|
mp_uint_t irq_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||||
|
uint32_t old_enable_mask = dma_enable_mask;
|
||||||
|
dma_enable_mask |= (1 << dma_id);
|
||||||
|
MICROPY_END_ATOMIC_SECTION(irq_state);
|
||||||
|
|
||||||
|
if (dma_id < NSTREAMS_PER_CONTROLLER) {
|
||||||
|
if (((old_enable_mask & DMA1_ENABLE_MASK) == 0) && !DMA1_IS_CLK_ENABLED()) {
|
||||||
|
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||||
|
|
||||||
|
// We just turned on the clock. This means that anything stored
|
||||||
|
// in dma_last_channel (for DMA1) needs to be invalidated.
|
||||||
|
|
||||||
|
for (int channel = 0; channel < NSTREAMS_PER_CONTROLLER; channel++) {
|
||||||
|
dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(DMA2)
|
||||||
|
else {
|
||||||
|
if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) {
|
||||||
|
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||||
|
|
||||||
|
// We just turned on the clock. This means that anything stored
|
||||||
|
// in dma_last_channel (for DMA2) needs to be invalidated.
|
||||||
|
|
||||||
|
for (int channel = NSTREAMS_PER_CONTROLLER; channel < NSTREAM; channel++) {
|
||||||
|
dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dma_disable_clock(dma_id_t dma_id) {
|
||||||
|
// We just mark the clock as disabled here, but we don't actually disable it.
|
||||||
|
// We wait for the timer to expire first, which means that back-to-back
|
||||||
|
// transfers don't have to initialize as much.
|
||||||
|
dma_tickle(dma_id);
|
||||||
|
dma_enable_mask &= ~(1 << dma_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data) {
|
||||||
|
// initialise parameters
|
||||||
|
dma->Instance = dma_descr->instance;
|
||||||
|
dma->Init = *dma_descr->init;
|
||||||
|
dma->Init.Direction = dir;
|
||||||
|
dma->Init.Channel = dma_descr->sub_instance;
|
||||||
|
// half of __HAL_LINKDMA(data, xxx, *dma)
|
||||||
|
// caller must implement other half by doing: data->xxx = dma
|
||||||
|
dma->Parent = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data){
|
||||||
|
// Some drivers allocate the DMA_HandleTypeDef from the stack
|
||||||
|
// (i.e. dac, i2c, spi) and for those cases we need to clear the
|
||||||
|
// structure so we don't get random values from the stack)
|
||||||
|
memset(dma, 0, sizeof(*dma));
|
||||||
|
|
||||||
|
if (dma_descr != NULL) {
|
||||||
|
dma_id_t dma_id = dma_descr->id;
|
||||||
|
|
||||||
|
dma_init_handle(dma, dma_descr, dir, data);
|
||||||
|
// set global pointer for IRQ handler
|
||||||
|
dma_handle[dma_id] = dma;
|
||||||
|
|
||||||
|
dma_enable_clock(dma_id);
|
||||||
|
|
||||||
|
// if this stream was previously configured for this channel/request and direction then we
|
||||||
|
// can skip most of the initialisation
|
||||||
|
uint8_t sub_inst = DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance) | (dir == DMA_PERIPH_TO_MEMORY) << 7;
|
||||||
|
if (dma_last_sub_instance[dma_id] != sub_inst) {
|
||||||
|
dma_last_sub_instance[dma_id] = sub_inst;
|
||||||
|
|
||||||
|
// reset and configure DMA peripheral
|
||||||
|
// (dma->State is set to HAL_DMA_STATE_RESET by memset above)
|
||||||
|
HAL_DMA_DeInit(dma);
|
||||||
|
HAL_DMA_Init(dma);
|
||||||
|
svc_setpriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA);
|
||||||
|
} else {
|
||||||
|
// only necessary initialization
|
||||||
|
dma->State = HAL_DMA_STATE_READY;
|
||||||
|
// calculate DMA base address and bitshift to be used in IRQ handler
|
||||||
|
extern uint32_t DMA_CalcBaseAndBitshift(DMA_HandleTypeDef *hdma);
|
||||||
|
DMA_CalcBaseAndBitshift(dma);
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_enableIRQ(dma_irqn[dma_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dma_deinit(const dma_descr_t *dma_descr) {
|
||||||
|
if (dma_descr != NULL) {
|
||||||
|
svc_disableIRQ(dma_irqn[dma_descr->id]);
|
||||||
|
dma_handle[dma_descr->id] = NULL;
|
||||||
|
|
||||||
|
dma_disable_clock(dma_descr->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dma_invalidate_channel(const dma_descr_t *dma_descr) {
|
||||||
|
if (dma_descr != NULL) {
|
||||||
|
dma_id_t dma_id = dma_descr->id;
|
||||||
|
// Only compare the sub-instance, not the direction bit (MSB)
|
||||||
|
if ((dma_last_sub_instance[dma_id] & 0x7f) == DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance) ) {
|
||||||
|
dma_last_sub_instance[dma_id] = DMA_INVALID_CHANNEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Called from the SysTick handler
|
||||||
|
// We use LSB of tick to select which controller to process
|
||||||
|
static void dma_idle_handler(uint32_t tick) {
|
||||||
|
if (!DMA_IDLE_ENABLED() || !DMA_IDLE_TICK(tick)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint32_t controller_mask[] = {
|
||||||
|
DMA1_ENABLE_MASK,
|
||||||
|
#if defined(DMA2)
|
||||||
|
DMA2_ENABLE_MASK,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
{
|
||||||
|
int controller = (tick >> DMA_SYSTICK_LOG2) & 1;
|
||||||
|
if (dma_idle.counter[controller] == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (++dma_idle.counter[controller] > DMA_IDLE_TICK_MAX) {
|
||||||
|
if ((dma_enable_mask & controller_mask[controller]) == 0) {
|
||||||
|
// Nothing is active and we've reached our idle timeout,
|
||||||
|
// Now we'll really disable the clock.
|
||||||
|
dma_idle.counter[controller] = 0;
|
||||||
|
if (controller == 0) {
|
||||||
|
__HAL_RCC_DMA1_CLK_DISABLE();
|
||||||
|
}
|
||||||
|
#if defined(DMA2)
|
||||||
|
else {
|
||||||
|
__HAL_RCC_DMA2_CLK_DISABLE();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
// Something is still active, but the counter never got
|
||||||
|
// reset, so we'll reset the counter here.
|
||||||
|
dma_idle.counter[controller] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
core/embed/trezorhal/dma.h
Normal file
46
core/embed/trezorhal/dma.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// clang-format off
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Damien P. George
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef MICROPY_INCLUDED_STM32_DMA_H
|
||||||
|
#define MICROPY_INCLUDED_STM32_DMA_H
|
||||||
|
|
||||||
|
#include STM32_HAL_H
|
||||||
|
|
||||||
|
typedef struct _dma_descr_t dma_descr_t;
|
||||||
|
|
||||||
|
extern const dma_descr_t dma_SDIO_0;
|
||||||
|
|
||||||
|
void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data);
|
||||||
|
void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir, void *data);
|
||||||
|
void dma_deinit(const dma_descr_t *dma_descr);
|
||||||
|
void dma_invalidate_channel(const dma_descr_t *dma_descr);
|
||||||
|
|
||||||
|
void dma_nohal_init(const dma_descr_t *descr, uint32_t config);
|
||||||
|
void dma_nohal_deinit(const dma_descr_t *descr);
|
||||||
|
void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_addr, uint16_t len);
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_STM32_DMA_H
|
150
core/embed/trezorhal/irq.h
Normal file
150
core/embed/trezorhal/irq.h
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// clang-format off
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, 2014 Damien P. George
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef MICROPY_INCLUDED_STM32_IRQ_H
|
||||||
|
#define MICROPY_INCLUDED_STM32_IRQ_H
|
||||||
|
|
||||||
|
// Use this macro together with NVIC_SetPriority to indicate that an IRQn is non-negative,
|
||||||
|
// which helps the compiler optimise the resulting inline function.
|
||||||
|
#define IRQn_NONNEG(pri) ((pri) & 0x7f)
|
||||||
|
|
||||||
|
// these states correspond to values from query_irq, enable_irq and disable_irq
|
||||||
|
#define IRQ_STATE_DISABLED (0x00000001)
|
||||||
|
#define IRQ_STATE_ENABLED (0x00000000)
|
||||||
|
|
||||||
|
// Enable this to get a count for the number of times each irq handler is called,
|
||||||
|
// accessible via pyb.irq_stats().
|
||||||
|
#define IRQ_ENABLE_STATS (0)
|
||||||
|
|
||||||
|
#if IRQ_ENABLE_STATS
|
||||||
|
#define IRQ_STATS_MAX (128)
|
||||||
|
extern uint32_t irq_stats[IRQ_STATS_MAX];
|
||||||
|
#define IRQ_ENTER(irq) ++irq_stats[irq]
|
||||||
|
#define IRQ_EXIT(irq)
|
||||||
|
#else
|
||||||
|
#define IRQ_ENTER(irq)
|
||||||
|
#define IRQ_EXIT(irq)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline uint32_t query_irq(void) {
|
||||||
|
return __get_PRIMASK();
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable_irq and disable_irq are defined inline in mpconfigport.h
|
||||||
|
|
||||||
|
#if __CORTEX_M >= 0x03
|
||||||
|
|
||||||
|
// irqs with a priority value greater or equal to "pri" will be disabled
|
||||||
|
// "pri" should be between 1 and 15 inclusive
|
||||||
|
static inline uint32_t raise_irq_pri(uint32_t pri) {
|
||||||
|
uint32_t basepri = __get_BASEPRI();
|
||||||
|
// If non-zero, the processor does not process any exception with a
|
||||||
|
// priority value greater than or equal to BASEPRI.
|
||||||
|
// When writing to BASEPRI_MAX the write goes to BASEPRI only if either:
|
||||||
|
// - Rn is non-zero and the current BASEPRI value is 0
|
||||||
|
// - Rn is non-zero and less than the current BASEPRI value
|
||||||
|
pri <<= (8 - __NVIC_PRIO_BITS);
|
||||||
|
__ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory");
|
||||||
|
return basepri;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "basepri" should be the value returned from raise_irq_pri
|
||||||
|
static inline void restore_irq_pri(uint32_t basepri) {
|
||||||
|
__set_BASEPRI(basepri);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline uint32_t raise_irq_pri(uint32_t pri) {
|
||||||
|
return disable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
// "state" should be the value returned from raise_irq_pri
|
||||||
|
static inline void restore_irq_pri(uint32_t state) {
|
||||||
|
enable_irq(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// IRQ priority definitions.
|
||||||
|
//
|
||||||
|
// Lower number implies higher interrupt priority.
|
||||||
|
//
|
||||||
|
// The default priority grouping is set to NVIC_PRIORITYGROUP_4 in the
|
||||||
|
// HAL_Init function. This corresponds to 4 bits for the priority field
|
||||||
|
// and 0 bits for the sub-priority field (which means that for all intensive
|
||||||
|
// purposes that the sub-priorities below are ignored).
|
||||||
|
//
|
||||||
|
// While a given interrupt is being processed, only higher priority (lower number)
|
||||||
|
// interrupts will preempt a given interrupt. If sub-priorities are active
|
||||||
|
// then the sub-priority determines the order that pending interrupts of
|
||||||
|
// a given priority are executed. This is only meaningful if 2 or more
|
||||||
|
// interrupts of the same priority are pending at the same time.
|
||||||
|
//
|
||||||
|
// The priority of the SysTick timer is determined from the TICK_INT_PRIORITY
|
||||||
|
// value which is normally set to 0 in the stm32f4xx_hal_conf.h file.
|
||||||
|
//
|
||||||
|
// The following interrupts are arranged from highest priority to lowest
|
||||||
|
// priority to make it a bit easier to figure out.
|
||||||
|
|
||||||
|
//#def IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0)
|
||||||
|
|
||||||
|
// The UARTs have no FIFOs, so if they don't get serviced quickly then characters
|
||||||
|
// get dropped. The handling for each character only consumes about 0.5 usec
|
||||||
|
#define IRQ_PRI_UART NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0)
|
||||||
|
|
||||||
|
// SDIO must be higher priority than DMA for SDIO DMA transfers to work.
|
||||||
|
#define IRQ_PRI_SDIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 4, 0)
|
||||||
|
|
||||||
|
// DMA should be higher priority than USB, since USB Mass Storage calls
|
||||||
|
// into the sdcard driver which waits for the DMA to complete.
|
||||||
|
#define IRQ_PRI_DMA NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 5, 0)
|
||||||
|
|
||||||
|
// Flash IRQ (used for flushing storage cache) must be at the same priority as
|
||||||
|
// the USB IRQs, so that the IRQ priority can be raised to this level to disable
|
||||||
|
// both the USB and cache flushing, when storage transfers are in progress.
|
||||||
|
#define IRQ_PRI_FLASH NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
|
||||||
|
|
||||||
|
#define IRQ_PRI_OTG_FS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
|
||||||
|
#define IRQ_PRI_OTG_HS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
|
||||||
|
#define IRQ_PRI_TIM5 NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
|
||||||
|
|
||||||
|
#define IRQ_PRI_CAN NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 7, 0)
|
||||||
|
|
||||||
|
#define IRQ_PRI_SPI NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 8, 0)
|
||||||
|
|
||||||
|
// Interrupt priority for non-special timers.
|
||||||
|
#define IRQ_PRI_TIMX NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 13, 0)
|
||||||
|
|
||||||
|
#define IRQ_PRI_EXTINT NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0)
|
||||||
|
|
||||||
|
// PENDSV should be at the lowst priority so that other interrupts complete
|
||||||
|
// before exception is raised.
|
||||||
|
#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
|
||||||
|
#define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_STM32_IRQ_H
|
@ -46,9 +46,18 @@
|
|||||||
#include STM32_HAL_H
|
#include STM32_HAL_H
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "mpconfigport.h"
|
||||||
|
|
||||||
|
#include "dma.h"
|
||||||
|
#include "irq.h"
|
||||||
#include "sdcard-set_clr_card_detect.h"
|
#include "sdcard-set_clr_card_detect.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
|
#include "supervise.h"
|
||||||
|
|
||||||
|
#define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC1_CLK_ENABLE()
|
||||||
|
#define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC1_CLK_DISABLE()
|
||||||
|
#define SDMMC_IRQn SDMMC1_IRQn
|
||||||
|
#define SDMMC_DMA dma_SDIO_0
|
||||||
|
|
||||||
static SD_HandleTypeDef sd_handle;
|
static SD_HandleTypeDef sd_handle;
|
||||||
|
|
||||||
@ -109,12 +118,24 @@ static inline void sdcard_active_pin_state(void) {
|
|||||||
void sdcard_init(void) { sdcard_default_pin_state(); }
|
void sdcard_init(void) { sdcard_default_pin_state(); }
|
||||||
|
|
||||||
void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
|
void HAL_SD_MspInit(SD_HandleTypeDef *hsd) {
|
||||||
// enable SDIO clock
|
if (hsd->Instance == sd_handle.Instance) {
|
||||||
__HAL_RCC_SDIO_CLK_ENABLE();
|
// enable SDIO clock
|
||||||
|
SDMMC_CLK_ENABLE();
|
||||||
|
|
||||||
|
// NVIC configuration for SDIO interrupts
|
||||||
|
svc_setpriority(SDMMC_IRQn, IRQ_PRI_SDIO);
|
||||||
|
svc_enableIRQ(SDMMC_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
// GPIO have already been initialised by sdcard_init
|
// GPIO have already been initialised by sdcard_init
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { __HAL_RCC_SDIO_CLK_DISABLE(); }
|
void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) {
|
||||||
|
if (hsd->Instance == sd_handle.Instance) {
|
||||||
|
svc_disableIRQ(SDMMC_IRQn);
|
||||||
|
SDMMC_CLK_DISABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
secbool sdcard_power_on(void) {
|
secbool sdcard_power_on(void) {
|
||||||
if (sectrue != sdcard_is_present()) {
|
if (sectrue != sdcard_is_present()) {
|
||||||
@ -192,15 +213,40 @@ uint64_t sdcard_get_capacity_in_bytes(void) {
|
|||||||
return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize;
|
return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDIO_IRQHandler(void) {
|
||||||
|
IRQ_ENTER(SDIO_IRQn);
|
||||||
|
HAL_SD_IRQHandler(&sd_handle);
|
||||||
|
IRQ_EXIT(SDIO_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdcard_reset_periph(void) {
|
||||||
|
// Fully reset the SDMMC peripheral before calling HAL SD DMA functions.
|
||||||
|
// (There could be an outstanding DTIMEOUT event from a previous call and the
|
||||||
|
// HAL function enables IRQs before fully configuring the SDMMC peripheral.)
|
||||||
|
SDIO->DTIMER = 0;
|
||||||
|
SDIO->DLEN = 0;
|
||||||
|
SDIO->DCTRL = 0;
|
||||||
|
SDIO->ICR = SDMMC_STATIC_FLAGS;
|
||||||
|
}
|
||||||
|
|
||||||
static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd,
|
static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
// Wait for HAL driver to be ready (eg for DMA to finish)
|
// Wait for HAL driver to be ready (eg for DMA to finish)
|
||||||
uint32_t start = HAL_GetTick();
|
uint32_t start = HAL_GetTick();
|
||||||
while (sd->State == HAL_SD_STATE_BUSY) {
|
for (;;) {
|
||||||
|
// Do an atomic check of the state; WFI will exit even if IRQs are disabled
|
||||||
|
uint32_t irq_state = disable_irq();
|
||||||
|
if (sd->State != HAL_SD_STATE_BUSY) {
|
||||||
|
enable_irq(irq_state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
__WFI();
|
||||||
|
enable_irq(irq_state);
|
||||||
if (HAL_GetTick() - start >= timeout) {
|
if (HAL_GetTick() - start >= timeout) {
|
||||||
return HAL_TIMEOUT;
|
return HAL_TIMEOUT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for SD card to complete the operation
|
// Wait for SD card to complete the operation
|
||||||
for (;;) {
|
for (;;) {
|
||||||
HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd);
|
HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd);
|
||||||
@ -214,6 +260,7 @@ static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd,
|
|||||||
if (HAL_GetTick() - start >= timeout) {
|
if (HAL_GetTick() - start >= timeout) {
|
||||||
return HAL_TIMEOUT;
|
return HAL_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
__WFI();
|
||||||
}
|
}
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
@ -232,12 +279,33 @@ secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num,
|
|||||||
|
|
||||||
HAL_StatusTypeDef err = HAL_OK;
|
HAL_StatusTypeDef err = HAL_OK;
|
||||||
|
|
||||||
err = HAL_SD_ReadBlocks(&sd_handle, (uint8_t *)dest, block_num, num_blocks,
|
// we must disable USB irqs to prevent MSC contention with SD card
|
||||||
60000);
|
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
|
||||||
|
|
||||||
|
DMA_HandleTypeDef sd_dma;
|
||||||
|
dma_init(&sd_dma, &SDMMC_DMA, DMA_PERIPH_TO_MEMORY, &sd_handle);
|
||||||
|
sd_handle.hdmarx = &sd_dma;
|
||||||
|
|
||||||
|
// we need to assign hdmatx even though it's unused
|
||||||
|
// because STMHAL tries to access its error code in SD_DMAError()
|
||||||
|
// even though it shouldn't :-/
|
||||||
|
// this will get removed eventually when we update to new STMHAL
|
||||||
|
DMA_HandleTypeDef dummy_dma;
|
||||||
|
memset(&dummy_dma, 0, sizeof(dummy_dma));
|
||||||
|
sd_handle.hdmatx = &dummy_dma;
|
||||||
|
|
||||||
|
sdcard_reset_periph();
|
||||||
|
err =
|
||||||
|
HAL_SD_ReadBlocks_DMA(&sd_handle, (uint8_t *)dest, block_num, num_blocks);
|
||||||
if (err == HAL_OK) {
|
if (err == HAL_OK) {
|
||||||
err = sdcard_wait_finished(&sd_handle, 60000);
|
err = sdcard_wait_finished(&sd_handle, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dma_deinit(&SDMMC_DMA);
|
||||||
|
sd_handle.hdmarx = NULL;
|
||||||
|
|
||||||
|
restore_irq_pri(basepri);
|
||||||
|
|
||||||
return sectrue * (err == HAL_OK);
|
return sectrue * (err == HAL_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,11 +323,32 @@ secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num,
|
|||||||
|
|
||||||
HAL_StatusTypeDef err = HAL_OK;
|
HAL_StatusTypeDef err = HAL_OK;
|
||||||
|
|
||||||
err = HAL_SD_WriteBlocks(&sd_handle, (uint8_t *)src, block_num, num_blocks,
|
// we must disable USB irqs to prevent MSC contention with SD card
|
||||||
60000);
|
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
|
||||||
|
|
||||||
|
DMA_HandleTypeDef sd_dma;
|
||||||
|
dma_init(&sd_dma, &SDMMC_DMA, DMA_MEMORY_TO_PERIPH, &sd_handle);
|
||||||
|
sd_handle.hdmatx = &sd_dma;
|
||||||
|
|
||||||
|
// we need to assign hdmarx even though it's unused
|
||||||
|
// because HAL tries to access its error code in SD_DMAError()
|
||||||
|
// even though it shouldn't :-/
|
||||||
|
// this will get removed eventually when we update to new STMHAL
|
||||||
|
DMA_HandleTypeDef dummy_dma;
|
||||||
|
memset(&dummy_dma, 0, sizeof(dummy_dma));
|
||||||
|
sd_handle.hdmarx = &dummy_dma;
|
||||||
|
|
||||||
|
sdcard_reset_periph();
|
||||||
|
err =
|
||||||
|
HAL_SD_WriteBlocks_DMA(&sd_handle, (uint8_t *)src, block_num, num_blocks);
|
||||||
if (err == HAL_OK) {
|
if (err == HAL_OK) {
|
||||||
err = sdcard_wait_finished(&sd_handle, 60000);
|
err = sdcard_wait_finished(&sd_handle, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dma_deinit(&SDMMC_DMA);
|
||||||
|
sd_handle.hdmatx = NULL;
|
||||||
|
|
||||||
|
restore_irq_pri(basepri);
|
||||||
|
|
||||||
return sectrue * (err == HAL_OK);
|
return sectrue * (err == HAL_OK);
|
||||||
}
|
}
|
||||||
|
@ -86,14 +86,6 @@ void SystemInit(void) {
|
|||||||
SCB->CPACR |= ((3U << 22) | (3U << 20));
|
SCB->CPACR |= ((3U << 22) | (3U << 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern volatile uint32_t uwTick;
|
|
||||||
|
|
||||||
void SysTick_Handler(void) {
|
|
||||||
// this is a millisecond tick counter that wraps after approximately
|
|
||||||
// 49.71 days = (0xffffffff / (24 * 60 * 60 * 1000))
|
|
||||||
uwTick++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// from util.s
|
// from util.s
|
||||||
extern void shutdown(void);
|
extern void shutdown(void);
|
||||||
|
|
||||||
|
@ -47,12 +47,24 @@
|
|||||||
|
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "ports/stm32/irq.h"
|
#include "irq.h"
|
||||||
#include "ports/stm32/systick.h"
|
#include "systick.h"
|
||||||
#include "ports/stm32/pybthread.h"
|
|
||||||
|
|
||||||
extern __IO uint32_t uwTick;
|
extern __IO uint32_t uwTick;
|
||||||
|
|
||||||
|
systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS];
|
||||||
|
|
||||||
|
void SysTick_Handler(void) {
|
||||||
|
// this is a millisecond tick counter that wraps after approximately
|
||||||
|
// 49.71 days = (0xffffffff / (24 * 60 * 60 * 1000))
|
||||||
|
uint32_t uw_tick = uwTick + 1;
|
||||||
|
uwTick = uw_tick;
|
||||||
|
systick_dispatch_t f = systick_dispatch_table[uw_tick & (SYSTICK_DISPATCH_NUM_SLOTS - 1)];
|
||||||
|
if (f != NULL) {
|
||||||
|
f(uw_tick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We provide our own version of HAL_Delay that calls __WFI while waiting,
|
// We provide our own version of HAL_Delay that calls __WFI while waiting,
|
||||||
// and works when interrupts are disabled. This function is intended to be
|
// and works when interrupts are disabled. This function is intended to be
|
||||||
// used only by the ST HAL functions.
|
// used only by the ST HAL functions.
|
||||||
|
56
core/embed/trezorhal/systick.h
Normal file
56
core/embed/trezorhal/systick.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// clang-format off
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013, 2014 Damien P. George
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef MICROPY_INCLUDED_STM32_SYSTICK_H
|
||||||
|
#define MICROPY_INCLUDED_STM32_SYSTICK_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// Works for x between 0 and 16 inclusive
|
||||||
|
#define POW2_CEIL(x) ((((x) - 1) | ((x) - 1) >> 1 | ((x) - 1) >> 2 | ((x) - 1) >> 3) + 1)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SYSTICK_DISPATCH_DMA = 0,
|
||||||
|
SYSTICK_DISPATCH_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SYSTICK_DISPATCH_NUM_SLOTS POW2_CEIL(SYSTICK_DISPATCH_MAX)
|
||||||
|
|
||||||
|
typedef void (*systick_dispatch_t)(uint32_t);
|
||||||
|
|
||||||
|
extern systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS];
|
||||||
|
|
||||||
|
static inline void systick_enable_dispatch(size_t slot, systick_dispatch_t f) {
|
||||||
|
systick_dispatch_table[slot] = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void systick_disable_dispatch(size_t slot) {
|
||||||
|
systick_dispatch_table[slot] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_STM32_SYSTICK_H
|
Loading…
Reference in New Issue
Block a user