209 lines
9.6 KiB
C
209 lines
9.6 KiB
C
/*
|
||
* sdmmc_config.c — board-level реализация SDMMC для MIMXRT1052CVJ5B.
|
||
*/
|
||
|
||
#define SD_ENABLED /* нужен для fsl_sd.h, до включений */
|
||
|
||
#include "sdmmc_config.h"
|
||
|
||
#include "fsl_iomuxc.h"
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
* Статические объекты хоста (не экспортируются)
|
||
* ------------------------------------------------------------------------- */
|
||
|
||
/* DMA-дескрипторы: некэшируемая секция, выравнивание по требованию USDHC. */
|
||
AT_NONCACHEABLE_SECTION_ALIGN(
|
||
static uint32_t s_dma_buf[BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE],
|
||
SDMMCHOST_DMA_DESCRIPTOR_BUFFER_ALIGN_SIZE);
|
||
|
||
static sdmmchost_t s_host;
|
||
static sd_detect_card_t s_cd;
|
||
static sd_io_voltage_t s_io_voltage = {
|
||
.type = BOARD_SDMMC_SD_IO_VOLTAGE_TYPE,
|
||
.func = NULL, /* управление через регистры USDHC, не через внешний LDO */
|
||
};
|
||
|
||
/* Debug markers for runtime verification in debugger. */
|
||
volatile uint32_t g_sdmmc_dbg_dma_buf_addr = 0U;
|
||
volatile uint32_t g_sdmmc_dbg_usdhc1_src_clock_hz = 0U;
|
||
|
||
/*
|
||
* Детект карты через USDHC PRES_STATE.CINST — ЕДИНЫЙ механизм и для нашего
|
||
* гейта bsp_sd_is_inserted() (bsp/sd/src/sd.c), и для внутреннего
|
||
* SD_PollingCardInsert() SDK (тот зовёт этот callback при kSD_DetectCardByGpioCD).
|
||
* Не GPIO_PinRead — исторически детект через GPIO2/28 давал ложный "card
|
||
* present" на пустом слоте (Фаза 3, симптом 1; DEBUG_LOG_PHASE3_SD.md, раунд 3).
|
||
* Работает, пока пин D13 замаплен на USDHC1_CD_B (см. BOARD_SD_Config ниже:
|
||
* прежний remux на GPIO2_IO28 убран, пин остаётся на USDHC1_CD_B постоянно —
|
||
* консолидация, item 1). Тактирование USDHC1 включается идемпотентно на случай
|
||
* вызова до полного SD_HostInit().
|
||
*
|
||
* Тот же PRSSTAT-бит читает и штатный host-CD путь SDK
|
||
* (SDMMCHOST_CardDetectStatus), но kSD_DetectCardByHostCD дополнительно взводит
|
||
* USDHC card-detect ПРЕРЫВАНИЯ — не нужны загрузчику (лишний источник IRQ перед
|
||
* прыжком), поэтому оставляем polling через callback (kSD_DetectCardByGpioCD).
|
||
*/
|
||
static bool sd_card_detect_prsstat(void)
|
||
{
|
||
CLOCK_EnableClock(kCLOCK_Usdhc1);
|
||
return (USDHC_GetPresentStatusFlags(BOARD_SDMMC_SD_HOST_BASEADDR) &
|
||
(uint32_t) kUSDHC_CardInsertedFlag) != 0U;
|
||
}
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
* Внутренние функции
|
||
* ------------------------------------------------------------------------- */
|
||
|
||
/*
|
||
* Возвращает частоту источника USDHC1.
|
||
*
|
||
* BOARD_BootClockRUN() уже настроил SysPll и PFD0 → не трогаем PLL.
|
||
* Просто возвращаем известное значение из clock_config.h.
|
||
*/
|
||
static uint32_t get_usdhc1_src_clock_hz(void)
|
||
{
|
||
return BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT;
|
||
}
|
||
|
||
/*
|
||
* Управление питанием карты: GPIO1[19] (SdPwr). Регистрируется как
|
||
* usrParam.pwr — SDK дёргает её из SD_SetCardPower().
|
||
*/
|
||
static void sd_power_control(bool enable)
|
||
{
|
||
#if BOARD_SDMMC_SD_PWR_ACTIVE_HIGH
|
||
GPIO_PinWrite(BOARD_SDMMC_SD_PWR_GPIO_BASE, BOARD_SDMMC_SD_PWR_GPIO_PIN, enable ? 1U : 0U);
|
||
#else
|
||
GPIO_PinWrite(BOARD_SDMMC_SD_PWR_GPIO_BASE, BOARD_SDMMC_SD_PWR_GPIO_PIN, enable ? 0U : 1U);
|
||
#endif
|
||
}
|
||
|
||
/*
|
||
* Инициализация GPIO питания карты как выход, начальное состояние — выкл.
|
||
* Вызывается однократно из BOARD_SD_Config().
|
||
*/
|
||
static void sd_power_init(void)
|
||
{
|
||
const gpio_pin_config_t cfg = {
|
||
.direction = kGPIO_DigitalOutput,
|
||
#if BOARD_SDMMC_SD_PWR_ACTIVE_HIGH
|
||
.outputLogic = 0U, /* питание выключено при старте */
|
||
#else
|
||
.outputLogic = 1U, /* питание выключено при старте */
|
||
#endif
|
||
.interruptMode = kGPIO_NoIntmode,
|
||
};
|
||
GPIO_PinInit(BOARD_SDMMC_SD_PWR_GPIO_BASE, BOARD_SDMMC_SD_PWR_GPIO_PIN, &cfg);
|
||
}
|
||
|
||
/*
|
||
* Динамическая настройка пад-конфигурации линий SD в зависимости от частоты.
|
||
* Вызывается SDMMC стеком при смене скорости (HS, SDR50, SDR104).
|
||
*
|
||
* speed/strength подобраны по таблице EVK — для данной платы проверить
|
||
* при трассировке > 50 MHz.
|
||
*/
|
||
static void sd_pin_config(uint32_t freq)
|
||
{
|
||
uint32_t speed;
|
||
uint32_t strength;
|
||
|
||
if (freq <= 50000000U)
|
||
{
|
||
speed = 0U;
|
||
strength = 7U;
|
||
}
|
||
else if (freq <= 100000000U)
|
||
{
|
||
speed = 2U;
|
||
strength = 7U;
|
||
}
|
||
else
|
||
{
|
||
speed = 3U;
|
||
strength = 7U;
|
||
}
|
||
|
||
const uint32_t pad = IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |
|
||
IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK |
|
||
IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |
|
||
IOMUXC_SW_PAD_CTL_PAD_PUS(1) /* 47k pull-up */
|
||
| IOMUXC_SW_PAD_CTL_PAD_DSE(strength);
|
||
|
||
const uint32_t clk_pad = IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |
|
||
IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |
|
||
IOMUXC_SW_PAD_CTL_PAD_PUS(0) /* no pull on CLK */
|
||
| IOMUXC_SW_PAD_CTL_PAD_DSE(strength);
|
||
|
||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_00_USDHC1_CMD, pad);
|
||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_01_USDHC1_CLK, clk_pad);
|
||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_02_USDHC1_DATA0, pad);
|
||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_03_USDHC1_DATA1, pad);
|
||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_04_USDHC1_DATA2, pad);
|
||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_05_USDHC1_DATA3, pad);
|
||
/*
|
||
* CD (D13) здесь НЕ конфигурируем: пин на USDHC1_CD_B (см. BOARD_SD_Config),
|
||
* pad задан в BOARD_InitPins() и на железе даёт корректный CINST. Прежняя
|
||
* настройка pad'а GPIO2_IO28 убрана вместе с GPIO-детектом (item 1,
|
||
* DEBUG_LOG_PHASE3_SD.md).
|
||
*/
|
||
}
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
* Публичный API
|
||
* ------------------------------------------------------------------------- */
|
||
|
||
#ifdef SD_ENABLED
|
||
void BOARD_SD_Config(void *card, sd_cd_t cd, uint32_t host_irq_priority, void *user_data)
|
||
{
|
||
assert(card != NULL);
|
||
|
||
/* --- host --- */
|
||
s_host.dmaDesBuffer = s_dma_buf;
|
||
s_host.dmaDesBufferWordsNum = BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE;
|
||
s_host.enableCacheControl = BOARD_SDMMC_HOST_CACHE_CONTROL;
|
||
|
||
sd_card_t *sd = (sd_card_t *) card;
|
||
|
||
sd->host = &s_host;
|
||
sd->host->hostController.base = BOARD_SDMMC_SD_HOST_BASEADDR;
|
||
sd->host->hostController.sourceClock_Hz = get_usdhc1_src_clock_hz();
|
||
g_sdmmc_dbg_dma_buf_addr = (uint32_t)(uintptr_t)s_dma_buf;
|
||
g_sdmmc_dbg_usdhc1_src_clock_hz = sd->host->hostController.sourceClock_Hz;
|
||
|
||
/* --- card detect: USDHC PRES_STATE.CINST через callback (polling, без IRQ) --- */
|
||
s_cd.cdDebounce_ms = BOARD_SDMMC_SD_CD_DEBOUNCE_MS;
|
||
s_cd.type = BOARD_SDMMC_SD_CD_TYPE; /* kSD_DetectCardByGpioCD → callback ниже */
|
||
s_cd.cardDetected = sd_card_detect_prsstat;
|
||
s_cd.callback = cd; /* обычно NULL из bsp_sd */
|
||
s_cd.userData = user_data;
|
||
|
||
sd->usrParam.cd = &s_cd;
|
||
sd->usrParam.pwr = sd_power_control;
|
||
sd->usrParam.ioStrength = sd_pin_config;
|
||
sd->usrParam.ioVoltage = &s_io_voltage;
|
||
sd->usrParam.maxFreq = BOARD_SDMMC_SD_HOST_SUPPORT_SDR104_FREQ;
|
||
|
||
/* --- GPIO питания --- */
|
||
sd_power_init();
|
||
/*
|
||
* CD_B (GPIO_B1_12 / physical D13) остаётся на USDHC1_CD_B постоянно —
|
||
* единый механизм детекта через PRES_STATE.CINST (sd_card_detect_prsstat
|
||
* выше + гейт bsp_sd_is_inserted). Прежней двойной маршрутизации
|
||
* (remux на GPIO2_IO28 для GPIO-чтения внутри f_mount) больше нет —
|
||
* см. DEBUG_LOG_PHASE3_SD.md, раунд 3 «консолидация детекта» (item 1);
|
||
* она убирала латентную хрупкость: после первого bsp_sd_init() пин уходил
|
||
* на GPIO2_IO28 и повторный PRSSTAT-скан ослеп бы. Явно переустанавливаем
|
||
* альт-функцию (BOARD_InitPins() её тоже ставит — так модуль не зависит от
|
||
* порядка инициализации). Pad этого пина оставляем как задал BOARD_InitPins:
|
||
* на железе CINST на нём читается корректно (Фаза 3, все сценарии).
|
||
*/
|
||
IOMUXC_SetPinMux(IOMUXC_GPIO_B1_12_USDHC1_CD_B, 0U);
|
||
/* Pad-конфиг линий SD (CMD/CLK/DATA) сразу для ранних CMD (CMD0/CMD8/CMD55/ACMD41). */
|
||
sd_pin_config(400000U);
|
||
|
||
/* --- приоритет прерывания хоста --- */
|
||
NVIC_SetPriority(BOARD_SDMMC_SD_HOST_IRQ, host_irq_priority);
|
||
}
|
||
#endif /* SD_ENABLED */
|