From ce82f53010a593ebd864aad90b7d5b8ab42d1fe8 Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Sat, 25 Nov 2023 12:04:22 +0100 Subject: [PATCH] feat(core): support SD card on STM32U5 [no changelog] --- core/embed/boardloader/main.c | 16 +- core/embed/trezorhal/boards/trezor_t3t1_v4.h | 2 +- core/embed/trezorhal/stm32u5/sdcard.c | 340 ++++++++++++++++++ .../trezorhal/stm32u5/stm32u5xx_hal_conf.h | 2 +- core/site_scons/boards/trezor_t3t1_v4.py | 13 +- 5 files changed, 356 insertions(+), 17 deletions(-) create mode 100644 core/embed/trezorhal/stm32u5/sdcard.c diff --git a/core/embed/boardloader/main.c b/core/embed/boardloader/main.c index 24fbbc832..47eed64d7 100644 --- a/core/embed/boardloader/main.c +++ b/core/embed/boardloader/main.c @@ -117,8 +117,7 @@ struct BoardCapabilities capablities .terminator_length = 0}; // we use SRAM as SD card read buffer (because DMA can't access the CCMRAM) -extern uint32_t sram_start[]; -#define sdcard_buf sram_start +BUFFER_SECTION uint32_t sdcard_buf[IMAGE_HEADER_SIZE / sizeof(uint32_t)]; #if defined USE_SD_CARD static uint32_t check_sdcard(void) { @@ -208,11 +207,14 @@ static secbool copy_sdcard(void) { for (int i = 0; i < (IMAGE_HEADER_SIZE + codelen) / SDCARD_BLOCK_SIZE; i++) { ensure(sdcard_read_blocks(sdcard_buf, i, 1), NULL); - for (int j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) { - ensure(flash_area_write_word(&BOOTLOADER_AREA, - i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), - sdcard_buf[j]), - NULL); + for (int j = 0; + j < SDCARD_BLOCK_SIZE / (FLASH_BURST_LENGTH * sizeof(uint32_t)); j++) { + ensure( + flash_area_write_burst( + &BOOTLOADER_AREA, + i * SDCARD_BLOCK_SIZE + j * FLASH_BURST_LENGTH * sizeof(uint32_t), + &sdcard_buf[j * FLASH_BURST_LENGTH]), + NULL); } } diff --git a/core/embed/trezorhal/boards/trezor_t3t1_v4.h b/core/embed/trezorhal/boards/trezor_t3t1_v4.h index 19f4cc054..836acd9ed 100644 --- a/core/embed/trezorhal/boards/trezor_t3t1_v4.h +++ b/core/embed/trezorhal/boards/trezor_t3t1_v4.h @@ -7,7 +7,7 @@ #define VDD_1V8 1 #define HSE_16MHZ 1 -//#define USE_SD_CARD 1 +#define USE_SD_CARD 1 #define USE_I2C 1 #define USE_TOUCH 1 #define USE_SBU 1 diff --git a/core/embed/trezorhal/stm32u5/sdcard.c b/core/embed/trezorhal/stm32u5/sdcard.c new file mode 100644 index 000000000..3d7aee67a --- /dev/null +++ b/core/embed/trezorhal/stm32u5/sdcard.c @@ -0,0 +1,340 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This file is part of the Micro Python 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. + */ + +#include STM32_HAL_H +#include TREZOR_BOARD + +#include + +#include "irq.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 + +static SD_HandleTypeDef sd_handle = {0}; + +// this function is inspired by functions in stm32f4xx_ll_sdmmc.c +uint32_t SDMMC_CmdSetClrCardDetect(SDMMC_TypeDef *SDMMCx, uint32_t Argument) { + SDMMC_CmdInitTypeDef sdmmc_cmdinit; + uint32_t errorstate = SDMMC_ERROR_NONE; + + sdmmc_cmdinit.Argument = (uint32_t)Argument; + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_SET_CLR_CARD_DETECT; + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_APP_SET_CLR_CARD_DETECT, + SDMMC_CMDTIMEOUT); + + return errorstate; +} + +static inline void sdcard_default_pin_state(void) { + HAL_GPIO_WritePin(SD_ENABLE_PORT, SD_ENABLE_PIN, GPIO_PIN_SET); // SD_ON + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET); // SD_DAT0/PC8 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET); // SD_DAT1/PC9 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SD_DAT2/PC10 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET); // SD_DAT3/PC11 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET); // SD_CLK/PC12 + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // SD_CMD/PD2 + + GPIO_InitTypeDef GPIO_InitStructure; + + // configure the SD card circuitry on/off pin + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = SD_ENABLE_PIN; + HAL_GPIO_Init(SD_ENABLE_PORT, &GPIO_InitStructure); + + // configure SD GPIO + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + GPIO_InitStructure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + + // configure the SD card detect pin + GPIO_InitStructure.Mode = GPIO_MODE_INPUT; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = SD_DETECT_PIN; + HAL_GPIO_Init(SD_DETECT_PORT, &GPIO_InitStructure); +} + +static inline void sdcard_active_pin_state(void) { + HAL_GPIO_WritePin(SD_ENABLE_PORT, SD_ENABLE_PIN, GPIO_PIN_RESET); + HAL_Delay(10); // we need to wait until the circuit fully kicks-in + + GPIO_InitTypeDef GPIO_InitStructure; + + // configure SD GPIO + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = GPIO_AF12_SDMMC1; + GPIO_InitStructure.Pin = + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + GPIO_InitStructure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); +} + +void sdcard_init(void) { sdcard_default_pin_state(); } + +void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { + if (hsd->Instance == sd_handle.Instance) { + // 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 +} + +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) { + if (sectrue != sdcard_is_present()) { + return secfalse; + } + if (sd_handle.Instance) { + return sectrue; + } + // turn on SD card circuitry + sdcard_active_pin_state(); + HAL_Delay(50); + + // SD device interface configuration + sd_handle.Instance = SDMMC1; + sd_handle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + sd_handle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_ENABLE; + sd_handle.Init.BusWide = SDMMC_BUS_WIDE_1B; + sd_handle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + sd_handle.Init.ClockDiv = 0; + + // init the SD interface, with retry if it's not ready yet + for (int retry = 10; HAL_SD_Init(&sd_handle) != HAL_OK; retry--) { + if (retry == 0) { + goto error; + } + HAL_Delay(50); + } + + // disable the card's internal CD/DAT3 card detect pull-up resistor + // to send ACMD42, we have to send CMD55 (APP_CMD) with the card's RCA as + // the argument followed by CMD42 (SET_CLR_CARD_DETECT) + if (SDMMC_CmdAppCommand(sd_handle.Instance, sd_handle.SdCard.RelCardAdd + << 16U) != SDMMC_ERROR_NONE) { + goto error; + } + if (SDMMC_CmdSetClrCardDetect(sd_handle.Instance, 0) != SDMMC_ERROR_NONE) { + goto error; + } + + // configure the SD bus width for wide operation + if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDMMC_BUS_WIDE_4B) != HAL_OK) { + HAL_SD_DeInit(&sd_handle); + goto error; + } + + return sectrue; + +error: + sdcard_power_off(); + return secfalse; +} + +void sdcard_power_off(void) { + if (sd_handle.Instance) { + HAL_SD_DeInit(&sd_handle); + sd_handle.Instance = NULL; + } + // turn off SD card circuitry + HAL_Delay(50); + sdcard_default_pin_state(); + HAL_Delay(100); +} + +secbool sdcard_is_present(void) { + return sectrue * + (GPIO_PIN_RESET == HAL_GPIO_ReadPin(SD_DETECT_PORT, SD_DETECT_PIN)); +} + +uint64_t sdcard_get_capacity_in_bytes(void) { + if (sd_handle.Instance == NULL) { + return 0; + } + HAL_SD_CardInfoTypeDef cardinfo; + HAL_SD_GetCardInfo(&sd_handle, &cardinfo); + return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize; +} + +void SDMMC1_IRQHandler(void) { + IRQ_ENTER(SDIO_IRQn); + if (sd_handle.Instance) { + 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.) + SDMMC1->DTIMER = 0; + SDMMC1->DLEN = 0; + SDMMC1->DCTRL = 0; + SDMMC1->ICR = SDMMC_STATIC_FLAGS; +} + +static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, + uint32_t timeout) { + // Wait for HAL driver to be ready (eg for DMA to finish) + uint32_t start = HAL_GetTick(); + 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) { + return HAL_TIMEOUT; + } + } + + // Wait for SD card to complete the operation + for (;;) { + HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd); + if (state == HAL_SD_CARD_TRANSFER) { + return HAL_OK; + } + if (!(state == HAL_SD_CARD_SENDING || state == HAL_SD_CARD_RECEIVING || + state == HAL_SD_CARD_PROGRAMMING)) { + return HAL_ERROR; + } + if (HAL_GetTick() - start >= timeout) { + return HAL_TIMEOUT; + } + __WFI(); + } + return HAL_OK; +} + +secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, + uint32_t num_blocks) { + // check that SD card is initialised + if (sd_handle.Instance == NULL) { + return secfalse; + } + + // check that dest pointer is aligned on a 4-byte boundary + if (((uint32_t)dest & 3) != 0) { + return secfalse; + } + + HAL_StatusTypeDef err = HAL_OK; + + // we must disable USB irqs to prevent MSC contention with SD card + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + sdcard_reset_periph(); + err = + HAL_SD_ReadBlocks_DMA(&sd_handle, (uint8_t *)dest, block_num, num_blocks); + if (err == HAL_OK) { + err = sdcard_wait_finished(&sd_handle, 5000); + } + restore_irq_pri(basepri); + + return sectrue * (err == HAL_OK); +} + +secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, + uint32_t num_blocks) { + // check that SD card is initialised + if (sd_handle.Instance == NULL) { + return secfalse; + } + + // check that src pointer is aligned on a 4-byte boundary + if (((uint32_t)src & 3) != 0) { + return secfalse; + } + + HAL_StatusTypeDef err = HAL_OK; + + // we must disable USB irqs to prevent MSC contention with SD card + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + sdcard_reset_periph(); + err = + HAL_SD_WriteBlocks_DMA(&sd_handle, (uint8_t *)src, block_num, num_blocks); + if (err == HAL_OK) { + err = sdcard_wait_finished(&sd_handle, 5000); + } + + restore_irq_pri(basepri); + + return sectrue * (err == HAL_OK); +} diff --git a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h index 9cbfb8ff4..884710075 100644 --- a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h +++ b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h @@ -76,7 +76,7 @@ extern "C" { #define HAL_RTC_MODULE_ENABLED /*#define HAL_SAI_MODULE_ENABLED */ #define HAL_CRYP_MODULE_ENABLED -/*#define HAL_SD_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED /*#define HAL_MMC_MODULE_ENABLED */ /*#define HAL_SMARTCARD_MODULE_ENABLED */ /*#define HAL_SMBUS_MODULE_ENABLED */ diff --git a/core/site_scons/boards/trezor_t3t1_v4.py b/core/site_scons/boards/trezor_t3t1_v4.py index 391f47f7a..c6c6e8f6a 100644 --- a/core/site_scons/boards/trezor_t3t1_v4.py +++ b/core/site_scons/boards/trezor_t3t1_v4.py @@ -58,14 +58,11 @@ def configure( ] features_available.append("haptic") - # if "sd_card" in features_wanted: - # sources += ["embed/trezorhal/stm32u5/sdcard.c"] - # sources += ["embed/extmod/modtrezorio/ff.c"] - # sources += ["embed/extmod/modtrezorio/ffunicode.c"] - # sources += [ - # "vendor/stm32cube-u5/Drivers/STM32U5xx_HAL_Driver/Src/stm32u5xx_hal_dma.c" - # ] - # features_available.append("sd_card") + if "sd_card" in features_wanted: + sources += ["embed/trezorhal/stm32u5/sdcard.c"] + sources += ["embed/extmod/modtrezorio/ff.c"] + sources += ["embed/extmod/modtrezorio/ffunicode.c"] + features_available.append("sd_card") if "sbu" in features_wanted: sources += ["embed/trezorhal/stm32u5/sbu.c"]