/*----------------------------------------------------------------------------- * RL-ARM - FlashFS *----------------------------------------------------------------------------- * Name: SDIO_STM32F4xx.c * Purpose: SD/SDIO MMC Interface Driver for ST STM32F4xx * Rev.: V4.60 *----------------------------------------------------------------------------- * This code is part of the RealView Run-Time Library. * Copyright (c) 2004-2012 KEIL - An ARM Company. All rights reserved. *----------------------------------------------------------------------------*/ #include #include "stm32f4xx.h" /* STM32F4xx Definitions */ #include "SDIO_STM32F4xx.h" #include "bsp_task.h" #include "kit_time.h" /*----------------------------------------------------------------------------- Memory Card FAT Driver instance definition mci0_drv: First SD/MMC drive [M0:] mci1_drv: Second SD/MMC drive [M1:] *----------------------------------------------------------------------------*/ #define __DRV_ID mci0_drv #define __SDIOCLK 48000000 #define __CPUCLK 168000000 /* MCI Driver Interface functions */ static BOOL Init (void); static BOOL UnInit (void); static void Delay (U32 us); static BOOL BusMode (U32 mode); static BOOL BusWidth (U32 width); static BOOL BusSpeed (U32 kbaud); static BOOL Command (U8 cmd, U32 arg, U32 resp_type, U32 *rp); static BOOL ReadBlock (U32 bl, U8 *buf, U32 cnt); static BOOL WriteBlock (U32 bl, U8 *buf, U32 cnt); static BOOL SetDma (U32 mode, U8 *buf, U32 cnt); static U32 CheckMedia (void); /* Optional function for SD card check */ /* MCI Device Driver Control Block */ MCI_DRV __DRV_ID = { Init, UnInit, Delay, BusMode, BusWidth, BusSpeed, Command, ReadBlock, WriteBlock, SetDma, CheckMedia /* Can be NULL if not existing */ }; /* Wait time in for loop cycles */ #define DMA_TOUT 10000000 /*--------------------------- Init -------------------------------------------*/ static BOOL Init (void) { /* Initialize SDIO interface. */ /* Enable GPIOH (card detect), GPIOD (command), GPIOC (data) clock */ RCC->AHB1ENR |= RCC_AHB1ENR_GPIOHEN | RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOCEN; RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; /* Enable IO compensation cell */ // SYSCFG->CMPCR |= SYSCFG_CMPCR_CMP_PD; // while (!(SYSCFG->CMPCR & SYSCFG_CMPCR_READY)); /* PC.08, PC.09, PC.10, PC.11, PC.12 pin: D0, D1, D2, D3, CLK pin */ GPIOC->MODER &= ~0x03FF0000; GPIOC->MODER |= 0x02AA0000; /* Pins to alternate function */ GPIOC->OTYPER &= ~0x00001F00; /* Configure as push-pull pins */ GPIOC->PUPDR &= ~0x03FF0000; GPIOC->PUPDR |= 0x01550000; /* Pull-ups on pins */ GPIOC->OSPEEDR |= 0x03FF0000; /* Pins output speed to 100MHz */ GPIOC->AFR[1] &= ~0x000FFFFF; GPIOC->AFR[1] |= 0x000CCCCC; /* Pins assigned to AF12 (SDIO) */ /* Configure PD.02 CMD line */ GPIOD->MODER &= ~0x0000030; GPIOD->MODER |= 0x0000020; /* Pins to alternate function */ GPIOD->OTYPER &= ~0x0000004; /* Configure as push-pull pin */ GPIOD->PUPDR &= ~0x0000030; GPIOD->PUPDR |= 0x0000010; /* Pull-up on pin */ GPIOD->OSPEEDR |= 0x0000030; /* Pins output speed to 100MHz */ GPIOD->AFR[0] &= ~0x00000F00; GPIOD->AFR[0] |= 0x00000C00; /* Pin assigned to AF12 (SDIO) */ // /* Configure PH.15 Card Detect input */ // GPIOH->MODER &= ~0xC0000000; // GPIOH->PUPDR &= ~0xC0000000; /* Pin in Input mode */ /* Enable SDIO clock */ RCC->APB2ENR |= RCC_APB2ENR_SDIOEN; /* Reset/Dereset SDIO */ RCC->APB2RSTR |= RCC_APB2RSTR_SDIORST; RCC->APB2RSTR &= ~RCC_APB2RSTR_SDIORST; /* Power-on, the card is clocked */ SDIO->POWER = SDIO_POWER_PWRCTRL_1 | SDIO_POWER_PWRCTRL_0; /* Enable DMA2 clock */ RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; /* Success, SDIO initialized. */ return (__TRUE); } /*--------------------------- UnInit -----------------------------------------*/ static BOOL UnInit (void) { /* Reset PC.8, PC.9, PC.10, PC.11, PC.12 pins */ GPIOC->MODER &= ~0x03FF0000; /* Reset PD.2 */ GPIOD->MODER &= ~(3 << 4); /* Reset PH.13 */ GPIOH->MODER &= ~(3 << 26); /* Disable SDIO module clock */ RCC->APB2ENR &= ~RCC_APB2ENR_SDIOEN; return (__TRUE); } /*--------------------------- Delay ------------------------------------------*/ static void Delay (U32 us) { /* Approximate delay in micro seconds. */ U32 i; for (i = WAIT_CNT(__CPUCLK, us); i; i--); } /*--------------------------- BusMode ----------------------------------------*/ static BOOL BusMode (U32 mode) { /* Set SDIO Bus mode to Open Drain or Push Pull. */ switch (mode) { case BUS_OPEN_DRAIN: GPIOD->OTYPER |= 0x00000010; /* Configure as open-drain */ return (__TRUE); case BUS_PUSH_PULL: GPIOD->OTYPER &= ~0x00000010; /* Configure as push-pull pin */ return (__TRUE); default: return (__FALSE); } } /*--------------------------- BusWidth ---------------------------------------*/ static BOOL BusWidth (U32 width) { /* Set SDIO Bus width. */ switch (width) { case 1: SDIO->CLKCR &= ~SDIO_CLKCR_WIDBUS; return (__TRUE); case 4: SDIO->CLKCR |= SDIO_CLKCR_WIDBUS_0; return (__TRUE); default: return (__FALSE); } } /*--------------------------- BusSpeed ---------------------------------------*/ static BOOL BusSpeed (U32 kbaud) { /* Set SDIO clock speed to desired value. */ U32 div; /* baud = SDIOCLK / (div + 2) */ div = (__SDIOCLK/1000 + kbaud - 1) / kbaud; if (div < 2) div = 0; else div -= 2; if (div > 0xFF) div = 0xFF; SDIO->CLKCR = (SDIO->CLKCR & ~0xFF) | SDIO_CLKCR_PWRSAV | SDIO_CLKCR_CLKEN | div; return (__TRUE); } /*--------------------------- Command ----------------------------------------*/ static BOOL Command (U8 cmd, U32 arg, U32 resp_type, U32 *rp) { /* Send a Command to Flash card and get a Response. */ U32 cmdval,stat, cnt = 0; cmd &= SDIO_CMD_CMDINDEX; cmdval = SDIO_CMD_CPSMEN | cmd; switch (resp_type) { case RESP_SHORT: cmdval |= SDIO_CMD_WAITRESP_0; break; case RESP_LONG: cmdval |= SDIO_CMD_WAITRESP_1 | SDIO_CMD_WAITRESP_0; break; } /* Send the command. */ SDIO->ARG = arg; SDIO->CMD = cmdval; if (resp_type == RESP_NONE) { /* Wait until command finished. */ while ((SDIO->STA & SDIO_STA_CMDACT) && (cnt++ < DMA_TOUT)) { bsp_task_feed_wdog(1); } if(cnt >= DMA_TOUT) { return (__FALSE); } stat = SDIO->STA; SDIO->ICR = 0x00C007FF; if (stat & SDIO_STA_CMDSENT) { return (__TRUE); } return (__FALSE); } for (cnt = 0; cnt < DMA_TOUT; cnt++) { stat = SDIO->STA; if (stat & SDIO_STA_CTIMEOUT) { SDIO->ICR = stat & SDIO_STA_CLEAR_MASK; return (__FALSE); } if (stat & SDIO_STA_CCRCFAIL) { SDIO->ICR = stat & SDIO_STA_CLEAR_MASK; if ((cmd == SEND_OP_COND) || (cmd == SEND_APP_OP_COND) || (cmd == STOP_TRANS)) { SDIO->CMD = 0; break; } return (__FALSE); } if (stat & SDIO_STA_CMDREND) { SDIO->ICR = stat & SDIO_STA_CLEAR_MASK; break; } bsp_task_feed_wdog(1); } if ((SDIO->RESPCMD & 0x3F) != cmd) { if ((SDIO->RESPCMD & 0x3F) != 0x3F) { return (__FALSE); } } /* Read MCI response registers */ rp[0] = SDIO->RESP1; if (resp_type == RESP_LONG) { rp[1] = SDIO->RESP2; rp[2] = SDIO->RESP3; rp[3] = SDIO->RESP4; } return (__TRUE); } /*--------------------------- ReadBlock --------------------------------------*/ static BOOL ReadBlock (U32 bl, U8 *buf, U32 cnt) { /* Read one or more 512 byte blocks from Flash Card. */ U32 i; SDIO->DLEN = cnt * 512; SDIO->DTIMER = cnt * DATA_RD_TOUT_VALUE; SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN ; for (i = DMA_TOUT; i; i--) { if (DMA2->LISR & DMA_LISR_TEIF3) { break; } if (DMA2->LISR & DMA_LISR_TCIF3) { if ((SDIO->STA & (SDIO_STA_DBCKEND|SDIO_STA_DATAEND)) == (SDIO_STA_DBCKEND|SDIO_STA_DATAEND)) { /* Data transfer finished. */ return (__TRUE); } } bsp_task_feed_wdog(1); } /* DMA Transfer timeout. */ return (__FALSE); } /*--------------------------- WriteBlock -------------------------------------*/ static BOOL WriteBlock (U32 bl, U8 *buf, U32 cnt) { /* Write a cnt number of 512 byte blocks to Flash Card. */ U32 i; SDIO->DLEN = cnt * 512; SDIO->DTIMER = cnt * DATA_WR_TOUT_VALUE; SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN ; for (i = DMA_TOUT; i; i--) { if (DMA2->LISR & DMA_LISR_TEIF3) { break; } if (DMA2->LISR & DMA_LISR_TCIF3) { if ((SDIO->STA & (SDIO_STA_DBCKEND|SDIO_STA_DATAEND)) == (SDIO_STA_DBCKEND|SDIO_STA_DATAEND)) { /* Data transfer finished. */ return (__TRUE); } } bsp_task_feed_wdog(1); } /* DMA Transfer timeout. */ return (__FALSE); } /*--------------------------- DmaStart ---------------------------------------*/ static BOOL SetDma (U32 mode, U8 *buf, U32 cnt) { U32 count = 0; /* Configure DMA Channel 4, Stream 3 for read or write */ DMA2->LIFCR = 0x0F4 << 20; /* Clear all IRQs */ DMA2_Stream3->CR &= ~DMA_SxCR_EN; /* Disable stream 3 */ while ((DMA2_Stream3->CR & DMA_SxCR_EN) && (count++ < DMA_TOUT)) { bsp_task_feed_wdog(1); } /* Wait until stream disabled */ if(count >= DMA_TOUT) { return __FALSE; } count = 0; DMA2_Stream3->FCR |= DMA_SxFCR_DMDIS | /* Disable direct mode */ DMA_SxFCR_FTH ; /* FIFO threshold full */ DMA2_Stream3->PAR = (U32)&(SDIO->FIFO); DMA2_Stream3->M0AR = (U32)buf; if (mode == DMA_READ) { /* Transfer from SDIO-FIFO to memory. */ DMA2_Stream3->CR = (4 << 25) | /* Use channel 4 */ (1 << 23) | /* Memory burst 4 beats */ (1 << 21) | /* Peripheral burst 4 beats */ (3 << 16) | /* Priority level high */ (2 << 13) | /* Memory size 32-bits */ (2 << 11) | /* Peripheral size 32-bits */ (1 << 10) | /* Memory addr increment */ (1 << 5) ; /* Peripheral flow control */ } else { /* Transfer from memory to SDIO-FIFO. */ DMA2_Stream3->CR = (4 << 25) | /* Use channel 4 */ (1 << 23) | /* Memory burst 4 beats */ (1 << 21) | /* Peripheral burst 4 beats */ (3 << 16) | /* Priority level very high */ (2 << 13) | /* Memory size 32-bits */ (2 << 11) | /* Peripheral size 32-bits */ (1 << 10) | /* Memory addr increment */ (1 << 6) | /* Memory-to-peripheral */ (1 << 5) ; /* Peripheral flow control */ } /* Enable DMA channels, little endian */ DMA2_Stream3->CR |= DMA_SxCR_EN; /* Enable stream 3 */ return __TRUE; } /*--------------------------- CheckMedia -------------------------------------*/ static U32 CheckMedia (void) { /* Read CardDetect and WriteProtect SD card socket pins. */ U32 stat = 0; //#ifdef __XYNERGY // if (!(GPIOG->IDR & (1 << 8))) { //#else // if (!(GPIOH->IDR & (1 << 15))) { //#endif // /* Card is inserted (CD=0). */ // stat |= M_INSERTED; // } #if 0 if (/* Write protect switch is active */) { stat |= M_PROTECTED; } #endif //BCE1C NO Card Detect stat |= M_INSERTED; return (stat); } /*----------------------------------------------------------------------------- * end of file *----------------------------------------------------------------------------*/