diff --git a/src/usecfs_dev_sdio.c b/src/usecfs_dev_sdio.c
new file mode 100644
index 0000000..16f6b7e
--- /dev/null
+++ b/src/usecfs_dev_sdio.c
@@ -0,0 +1,803 @@
+
+/*
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ *
+ * This software 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 the software. If not, see .
+ *
+ * Original Author: Chuck M. (see https://github.com/ChuckM/stm32f4-sdio-driver/)
+ * Re-adapted by: Daniele Lacamera
+ *
+ * Permission to release under the terms of GPLv2 are granted by the
+ * copyright holders.
+ *
+ */
+
+/*
+ * SDIO Bus Driver layer. This code sends commands and drives
+ * the SDIO peripheral on the STM32F4xx, there is a layer above
+ * this, the SD Card driver, which uses this driver to talk to
+ * SD Cards. The SPI driver can also talk to SD Cards, hence the
+ * split at this layer.
+ *
+ * Note that the simple implementation for the SDIO driver runs
+ * in a 'polled' mode. This is easier to explain and debug and
+ * sufficient for the first few projects. A more sophisticated
+ * version with DMA and interrupts will follow.
+ *
+
+ *
+ *
+ */
+
+#include
+#include "usecfs_dev_sdio.h"
+#include "system.h"
+
+#if (!defined(BLOCK_SIZE)) || (BLOCK_SIZE != 512)
+# error BLOCK_SIZE undefined or invalid
+#endif
+
+#ifndef NULL
+#define NULL (void *)(0x00000000)
+#endif
+
+/*
+ * Helper defines to pull out various bit fields of the CSD for
+ * the size calculation.
+ */
+#define SDIO_CSD_VERSION(x) stm32_sdio_bit_slice(x->csd, 128, 127, 126)
+#define SDIO_CSD1_CSIZE_MULT(x) stm32_sdio_bit_slice(x->csd, 128, 49, 47)
+#define SDIO_CSD1_RBLKLEN(x) stm32_sdio_bit_slice(x->csd, 128, 83, 80)
+#define SDIO_CSD1_CSIZE(x) stm32_sdio_bit_slice(x->csd, 128, 73, 62)
+#define SDIO_CSD2_CSIZE(x) stm32_sdio_bit_slice(x->csd, 128, 69, 48)
+
+/*
+ * Conveniently swaps the bytes in a long around
+ * used by the SCR code.
+ */
+#define byte_swap(val) \
+ asm("rev %[swap], %[swap]" : [swap] "=r" (val) : "0" (val));
+
+static const uint32_t sdio_pins[5] = { 8, 9, 10, 11, 12}; /* GPIOC */
+static const uint32_t sdio_cmd_pin = 2; /* GPIOD */
+static const uint32_t sdio_detect_pin = 8; /* GPIOA */
+static const uint32_t sdio_af = 12;
+static struct dev_sd SD;
+
+/*
+ * sdio_bus
+ *
+ * Set the bus width and the clock speed for the
+ * SDIO bus.
+ *
+ * Returns 0 on success
+ * -1 illegal bit specification
+ * -2 illegal clock specification
+ */
+int
+stm32_sdio_bus(struct dev_sd *sd, int bits, enum SDIO_CLOCK_DIV freq) {
+ int clkreg = 0;
+
+ switch (bits) {
+ case 1:
+ clkreg |= SDIO_CLKCR_WIDBUS_1;
+ break;
+ case 4:
+ clkreg |= SDIO_CLKCR_WIDBUS_4;
+ break;
+ default:
+ return -1;
+ }
+ switch (freq) {
+ case SDIO_24MHZ:
+ break;
+ case SDIO_16MHZ:
+ clkreg |= 1;
+ break;
+ case SDIO_12MHZ:
+ clkreg |= 2;
+ break;
+ case SDIO_8MHZ:
+ clkreg |= 8;
+ break;
+ case SDIO_4MHZ:
+ clkreg |= 10;
+ break;
+ case SDIO_1MHZ:
+ clkreg |= 46;
+ break;
+ case SDIO_400KHZ:
+ clkreg |= 118;
+ break;
+ default:
+ return -2;
+ }
+ clkreg |= SDIO_CLKCR_CLKEN;
+ SDIO_CLKCR = clkreg;
+ return 0;
+}
+
+/*
+ * Reset the state of the SDIO bus and peripheral. This code tries
+ * to reset the bus *AND* the card if one is plugged in. The bus
+ * can be reset by software but the card is reset by powering it down.
+ *
+ * The SDIO_POWER_STATE tells the code which state to leave the bus in,
+ * powered up or powered down.
+ *
+ * If the state is POWER_ON, then the bus is reset to 400Khz, 1 bit wide
+ * which is what he spec requires. Once the type and capabilities of the
+ * card have been determined, it can be upgraded.
+ */
+void
+stm32_sdio_reset(struct dev_sd *sd, enum SDIO_POWER_STATE state) {
+
+ /* Step 1 power off the interface */
+ SDIO_POWER = SDIO_POWER_PWRCTRL_PWROFF;
+
+ /* reset the SDIO peripheral interface */
+ APB2_CLOCK_RST |= SDIO_APB2_CLOCK_ER_VAL;
+ APB2_CLOCK_RST &= ~SDIO_APB2_CLOCK_ER_VAL;
+
+ if (state == SDIO_POWER_ON) {
+ SDIO_POWER = SDIO_POWER_PWRCTRL_PWRON;
+ stm32_sdio_bus(sd, 1, SDIO_400KHZ); // required by the spec
+ }
+}
+
+/*
+ * The error message catalog.
+ */
+static const char *__sdio_error_msgs[] = {
+ "Success",
+ "Command Timeout", // -1
+ "Command CRC Failure", // -2
+ "Soft Timeout (No Response)", // -3
+ "Data CRC Failure", // -4
+ "RX FIFO Overrun", // -5
+ "TX FIFO Underrun", // -6
+ "Unsupported Card" // -7
+};
+
+#define SDIO_ESUCCESS 0
+#define SDIO_ECTIMEOUT -1
+#define SDIO_ECCRCFAIL -2
+#define SDIO_ENORESP -3
+#define SDIO_EDCRCFAIL -4
+#define SDIO_ERXOVERR -5
+#define SDIO_ETXUNDER -6
+#define SDIO_EBADCARD -7
+#define SDIO_EUNKNOWN -8
+
+/*
+ * Return a text string description of the error code.
+ */
+const char *
+stm32_sdio_errmsg(int err) {
+ return (err <= SDIO_EUNKNOWN) ? (const char *) "Unknown Error" :
+ __sdio_error_msgs[0-err];
+}
+
+/*
+ * stm32_sdio_bit_slice - helper function
+ *
+ * A number of the things the SDIO returns are in bit
+ * fields. This code is designed to slice out a range
+ * of bits and return them as a value (up to 32 bits
+ * worth).
+ */
+uint32_t
+stm32_sdio_bit_slice(uint32_t a[], int bits, int msb, int lsb) {
+ uint32_t t;
+ int i;
+
+ if (((msb >= bits) || (msb < 0)) ||
+ (lsb > msb) ||
+ ((lsb < 0) || (lsb >= bits))) {
+ return 0;
+ }
+ t = 0;
+ for (i = msb; i > lsb; i--) {
+ t |= (a[((bits-1) - i)/32] >> (i % 32)) & 0x1;
+ t <<= 1;
+ }
+ t |= (a[((bits-1) - lsb)/32] >> (lsb % 32)) & 0x1;
+ return t;
+}
+
+/*
+ * A convienence define. These are the flags we care about when
+ * sending a command. During command processing SDIO_STA_CMDACT
+ * will be set.
+ */
+#define COMMAND_FLAGS (SDIO_STA_CMDSENT |\
+ SDIO_STA_CCRCFAIL |\
+ SDIO_STA_CMDREND |\
+ SDIO_STA_CTIMEOUT)
+
+/*
+ * Send a command over the SDIO bus.
+ * Passed a command (8 bit value) and an argument (32 bit value)
+ * This command figures out if the command will return a short (32 bit)
+ * or long (64 bit) response. It is up to the calling program to pull
+ * data from the long response commands.
+ * Passed:
+ * cmd - Command to execute
+ * arg - Argument to pass to the command
+ * buf - pointer to a long aligned buffer if data
+ * len - expected length of buffer (in bytes)
+ */
+int
+stm32_sdio_command(struct dev_sd *sd, uint32_t cmd, uint32_t arg)
+{
+ uint32_t tmp_val;
+ int error = 0;
+
+ tmp_val = SDIO_CMD & ~0x7ff; // Read pre-existing state
+ tmp_val |= (cmd & SDIO_CMD_CMDINDEX_MSK); // Put the Command in
+ tmp_val |= SDIO_CMD_CPSMEN; // We'll be running CPSM
+
+ switch(cmd) {
+ case 0:
+ tmp_val |= SDIO_CMD_WAITRESP_NO_0;
+ break;
+ case 2:
+ case 9:
+ tmp_val |= SDIO_CMD_WAITRESP_LONG;
+ break;
+ default:
+ tmp_val |= SDIO_CMD_WAITRESP_SHORT; // the common case
+ break;
+ }
+ /* If a data transaction is in progress, wait for it to finish */
+
+ while ((cmd != 12) & (SDIO_STA & (SDIO_STA_RXACT | SDIO_STA_TXACT)));;
+
+
+ /*
+ * EXECUTE:
+ * o Reset all status bits
+ * o Put ARG into SDIO ARG
+ * o reset the error indicator
+ * o Enable all interrupts.
+ * o Do the command
+ */
+ SDIO_ICR = 0x7ff; // Reset everything that isn't bolted down.
+ SDIO_ARG = arg;
+ SDIO_CMD = tmp_val;
+ /*
+ * In a polled mode we should be able to just read the status bits
+ * directly.
+ */
+ tmp_val = 0;
+ do {
+ tmp_val |= (SDIO_STA & 0x7ff);
+ } while ((SDIO_STA & SDIO_STA_CMDACT) || (! tmp_val));;
+ SDIO_ICR = tmp_val;
+
+ /*
+ * Compute the error here. Which can be one of
+ * -- Success (either CMDSENT or CMDREND depending on response)
+ * -- Timeout (based on CTIMEOUT)
+ * -- No Response (based on no response in the time alloted)
+ * -- CRC Error (based on CCRCFAIL)
+ */
+ if (! tmp_val) {
+ error = SDIO_ENORESP;
+ } else if (tmp_val & SDIO_STA_CCRCFAIL) {
+ error = SDIO_ECCRCFAIL;
+ } else if (tmp_val & (SDIO_STA_CMDREND | SDIO_STA_CMDSENT)) {
+ error = SDIO_ESUCCESS;
+ } else if (tmp_val & SDIO_STA_CTIMEOUT) {
+ error = SDIO_ECTIMEOUT;
+ } else {
+ error = SDIO_EUNKNOWN;
+ }
+
+ return error;
+}
+
+
+/* our static data buffer we use for data movement commands */
+
+/*
+ * Helper function - sdio_select
+ *
+ * This function "selects" a card using CMD7, note that if
+ * you select card 0 that deselects the card (RCA is not allowed
+ * to be 0)
+ */
+static int
+sdio_select(struct dev_sd *sd, int rca) {
+ int err;
+
+ err = stm32_sdio_command(sd, 7, rca << 16);
+ if ((rca == 0) && (err == SDIO_ECTIMEOUT)) {
+ return 0; // "cheat" a timeout selecting 0 is a successful deselect
+ }
+ return err;
+}
+
+/*
+ * Helper function - sdio_scr
+ *
+ * Unlike the CID and CSD functions this function transfers data
+ * so it needs to use the DPSM.
+ *
+ * Note that data over the wire is byte swapped so we swap it back
+ * to "fix" it.
+ *
+ * Note when this return 0 the first two longs in the data_buf are
+ * the SCR register.
+ */
+
+static uint32_t data_buf[129];
+static int
+sdio_scr(struct dev_sd *sd, SDIO_CARD c) {
+ int err;
+ uint32_t tmp_reg;
+ int ndx;
+ int data_len;
+
+ /* Select the card */
+ err = sdio_select(sd, c->rca);
+ if (! err) {
+ /* Set the Block Size */
+ err = stm32_sdio_command(sd, 16, 8);
+ if (! err) {
+ /* APPCMD (our RCA) */
+ err = stm32_sdio_command(sd, 55, c->rca << 16);
+ if (! err) {
+ SDIO_ICR = 0xFFFFFFFF; /* Clear all status flags */
+ SDIO_DTIMER = 0xffffffff;
+ SDIO_DLEN = 8;
+ SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 |
+ SDIO_DCTRL_DTDIR |
+ SDIO_DCTRL_DTEN;
+ /* ACMD51 - Send SCR */
+ err = stm32_sdio_command(sd, 51, 0);
+ if (! err) {
+ data_len = 0;
+ do {
+ tmp_reg = SDIO_STA;
+ if (tmp_reg & SDIO_STA_RXDAVL) {
+ data_buf[data_len++] = SDIO_FIFO;
+ }
+ } while (tmp_reg & SDIO_STA_RXACT);
+ if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
+ if (tmp_reg & SDIO_STA_DCRCFAIL) {
+ err = SDIO_EDCRCFAIL;
+ } else if (tmp_reg & SDIO_STA_RXOVERR) {
+ err = SDIO_ERXOVERR;
+ } else {
+ err = SDIO_EUNKNOWN; // unknown error
+ }
+ }
+ if (! err) {
+ for (ndx = 0; ndx < 2; ndx++) {
+ byte_swap(data_buf[ndx]);
+ c->scr[ndx] = data_buf[ndx];
+ }
+ }
+ }
+ }
+ }
+ }
+ (void) sdio_select(sd, 0);
+ return err;
+}
+
+/*
+ * Read a Block from our Card
+ *
+ * NB: There is a possibly useless test in this code, during the read
+ * phase it allows that the SDIO card might try to send more than BLOCK_SIZE
+ * bytes (128 32 bit longs) and allows it to do so, constantly over
+ * writing the last long in the just-in-case-over-long-by-1 data buffer.
+ * To compromise the system you would need a borked or custom crafted
+ * sdio card which did that.
+ */
+
+int block_read(void *dev, void *_buf, uint32_t lba)
+{
+ int err;
+ uint32_t tmp_reg;
+ uint32_t addr = lba;
+ uint8_t *t;
+ int ndx, bdx = 0;
+ struct dev_sd *sd = &SD;
+ uint32_t *buf = _buf;
+ uint32_t buf_len = 0;
+
+ if (! SDIO_CARD_CCS(sd->card)) {
+ addr = lba * BLOCK_SIZE; // non HC cards use byte address
+ }
+ err = sdio_select(sd, sd->card->rca);
+ if (! err) {
+ err = stm32_sdio_command(sd, 16, BLOCK_SIZE);
+ if (!err) {
+ SDIO_DTIMER = 0xffffffff;
+ SDIO_DLEN = BLOCK_SIZE;
+ SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_9 |
+ SDIO_DCTRL_DTDIR |
+ SDIO_DCTRL_DTEN;
+ err = stm32_sdio_command(sd, 17, addr);
+ if (! err) {
+ buf_len = 0;
+ do {
+ tmp_reg = SDIO_STA;
+ if (tmp_reg & SDIO_STA_RXDAVL) {
+ buf[buf_len] = SDIO_FIFO;
+ if (buf_len < 128) {
+ ++buf_len;
+ }
+ }
+ } while (tmp_reg & SDIO_STA_RXACT);
+ if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
+ if (tmp_reg & SDIO_STA_DCRCFAIL) {
+ err = SDIO_EDCRCFAIL;
+ } else if (tmp_reg & SDIO_STA_RXOVERR) {
+ err = SDIO_ERXOVERR;
+ } else {
+ err = SDIO_EUNKNOWN; // Unknown Error!
+ }
+ } else {
+ err = BLOCK_SIZE;
+ }
+ }
+ }
+ }
+ // deselect the card
+ (void) sdio_select(sd, 0);
+ return err;
+}
+
+/*
+ * Write a Block from our Card
+ */
+int block_write(void *dev, void *_buf, uint32_t lba)
+{
+ int err;
+ uint32_t tmp_reg;
+ uint32_t addr = lba;
+ uint8_t *t;
+ int ndx;
+ struct dev_sd *sd = &SD;
+ SDIO_CARD c;
+ uint32_t *buf = _buf;
+ uint32_t buf_len = 0;
+
+ c = SD.card;
+
+
+ if (! SDIO_CARD_CCS(c)) {
+ addr = lba * BLOCK_SIZE; // non HC cards use byte address
+ }
+
+ err = sdio_select(sd, c->rca);
+ if (! err) {
+ /* Set Block Size to BLOCK_SIZE */
+ err = stm32_sdio_command(sd, 16, BLOCK_SIZE);
+ if (!err) {
+ SDIO_DTIMER = 0xffffffff;
+ SDIO_DLEN = BLOCK_SIZE;
+ SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_9 |
+ SDIO_DCTRL_DTEN;
+ err = stm32_sdio_command(sd, 24, addr);
+ if (! err) {
+ do {
+ tmp_reg = SDIO_STA;
+ if (tmp_reg & SDIO_STA_TXFIFOHE) {
+ SDIO_FIFO = buf[buf_len];
+ if (buf_len < 128) {
+ ++buf_len;
+ }
+ }
+ } while (tmp_reg & SDIO_STA_TXACT);
+ if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
+ if (tmp_reg & SDIO_STA_DCRCFAIL) {
+ err = SDIO_EDCRCFAIL;
+ } else if (tmp_reg & SDIO_STA_TXUNDERR) {
+ err = SDIO_ETXUNDER;
+ } else {
+ err = SDIO_EUNKNOWN; // Unknown Error!
+ }
+ }
+ }
+ }
+ }
+ // deselect the card
+ (void) sdio_select(sd, 0);
+ if (err == 0)
+ return BLOCK_SIZE;
+ return err;
+}
+
+/*
+ * sdio-status - Get Card Status page
+ *
+ * This function fetches the SD Card Status page and
+ * copies it into the CARD structure.
+ */
+/*
+int
+sdio_status(SDIO_CARD c) {
+ uint32_t tmp_reg;
+ int ndx;
+ int err;
+
+ err = sdio_select(c->rca);
+ if (! err) {
+ err = stm32_sdio_command(16, 64);
+ if (! err) {
+ err = stm32_sdio_command(55, c->rca << 16);
+ if (! err) {
+ SDIO_DTIMER = 0xffffffff;
+ SDIO_DLEN = 64;
+ SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_6 |
+ SDIO_DCTRL_DTDIR |
+ SDIO_DCTRL_DTEN; */
+ /* ACMD13 - Send Status Reg */ /*
+ err = stm32_sdio_command(13, 0);
+ if (! err) {
+ data_len = 0;
+ do {
+ tmp_reg = SDIO_STA;
+ if (tmp_reg & SDIO_STA_RXDAVL) {
+ data_buf[data_len] = SDIO_FIFO;
+ if (data_len < 128) {
+ ++data_len;
+ }
+ }
+ } while (tmp_reg & SDIO_STA_RXACT);
+ if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
+ if (tmp_reg & SDIO_STA_DCRCFAIL) {
+ err = SDIO_EDCRCFAIL;
+ } else if (tmp_reg & SDIO_STA_RXOVERR) {
+ err = SDIO_ERXOVERR;
+ } else {
+ err = SDIO_EUNKNOWN; // Unknown Error!
+ }
+ } else {
+ for (ndx = 0; ndx < 16; ndx++) {
+ byte_swap(data_buf[ndx]);
+ c->status[ndx] = data_buf[ndx];
+ }
+ }
+ (void) sdio_select(0);
+ }
+ }
+ }
+ }
+
+ return err;
+}
+*/
+
+static struct SDIO_CARD_DATA sdio_card_data;
+#define MAX_RETRIES 5
+
+/*
+ * stm32_sdio_open - Prepare to use SDIO card
+ *
+ * This function resets the SDIO bus and identifies the
+ * card (if any) that is plugged in. If there is no card
+ * present, or an error in figuring out what the card is
+ * (for example its an old MMC card) the function returns
+ * NULL. If it fails and you have logging enabled you can
+ * look at the last few commands sent.
+ */
+SDIO_CARD
+stm32_sdio_open(struct dev_sd *sd) {
+ int err;
+ int i;
+ uint8_t *t;
+ uint32_t tmp_reg;
+ SDIO_CARD res = &sdio_card_data;
+
+ // basically bset(0, sdio_card_data)
+ t = (uint8_t *) &sdio_card_data;
+ for (i = 0; i < (int) sizeof(sdio_card_data); i++) {
+ *t++ = 0;
+ }
+ stm32_sdio_reset(sd, SDIO_POWER_ON);
+ err = stm32_sdio_command(sd, 0, 0);
+ if (!err) {
+ err = stm32_sdio_command(sd, 8, 0x1aa);
+ if (!err) {
+ // Woot! We support CMD8 so we're a v2 card at least */
+ tmp_reg = SDIO_RESP1;
+ sdio_card_data.props = 1;
+ i = 0;
+ err = stm32_sdio_command(sd, 5, 0);
+ if (! err) {
+ // It is an SDIO card which is unsupported!
+ err = SDIO_EBADCARD;
+ return NULL;
+ }
+ do {
+ err = stm32_sdio_command(sd, 55, 0); // broadcast ACMD
+ if (err) {
+ break; // try again
+ }
+ // Testing Card Busy, Voltage match, and capacity
+ err = stm32_sdio_command(sd, 41, 0xc0100000);
+ if (err != -2) { // Expect CCRCFAIL here
+ break; // try again
+ }
+ tmp_reg = SDIO_RESP1; // what did the card send?
+ if ((tmp_reg & 0x80000000) == 0) {
+ continue; // still powering up
+ }
+ res->ocr = tmp_reg; // Ok OCR is valid
+ break;
+ } while (++i < MAX_RETRIES);
+ if (res->ocr) {
+ err = stm32_sdio_command(sd, 2, 0);
+ if (! err) {
+ res->cid[0] = SDIO_RESP1;
+ res->cid[1] = SDIO_RESP2;
+ res->cid[2] = SDIO_RESP3;
+ res->cid[3] = SDIO_RESP4;
+ err = stm32_sdio_command(sd, 3, 0); // get the RCA
+ if (! err) {
+ tmp_reg = SDIO_RESP1;
+ res->rca = (tmp_reg >> 16) & 0xffff;
+ if (! res->rca) {
+ /*
+ * If the card says '0' tell it to pick
+ * we assume this will work because the
+ * previous send RCA worked and the card
+ * should be in the ident state if it is
+ * functioning correctly.
+ */
+ (void) stm32_sdio_command(sd, 3, 0); // try again
+ tmp_reg = SDIO_RESP1;
+ res->rca = (tmp_reg >> 16) & 0xffff;
+ }
+ err = stm32_sdio_command(sd, 9, res->rca << 16);
+ if (! err) {
+ res->csd[0] = SDIO_RESP1;
+ res->csd[1] = SDIO_RESP2;
+ res->csd[2] = SDIO_RESP3;
+ res->csd[3] = SDIO_RESP4;
+ err = sdio_scr(sd, res); // Capture the SCR
+ if (! err) {
+ /* All SD Cards support 4 bit bus and 24Mhz */
+ err = sdio_select(sd, res->rca);
+ if (! err) {
+ err = stm32_sdio_command(sd, 55, res->rca << 16);
+ if (! err) {
+ err = stm32_sdio_command(sd, 6, 2);
+ if (! err) {
+ //XXX stm32_sdio_bus(4, SDIO_24MHZ);
+ //Seems we have speed issues for now...
+ stm32_sdio_bus(sd, 4, SDIO_12MHZ);
+ (void) sdio_select(sd, 0);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ /* Compute the size of the card based on fields in the CSD
+ * block. There are two kinds, V1 or V2.
+ * In the V1 Case :
+ * Size = 1<size = 0;
+ switch (SDIO_CSD_VERSION(res)) {
+ case 0:
+ tmp_reg = ((1 << (SDIO_CSD1_CSIZE_MULT(res) + 2)) *
+ ( 1 << SDIO_CSD1_RBLKLEN(res))) >> 9;
+ res->size = tmp_reg * (SDIO_CSD1_CSIZE(res) + 1);
+ break;
+ case 1:
+ res->size = (SDIO_CSD2_CSIZE(res)+1) << 10;
+ break;
+ default:
+ res->size = 0; // Bug if its not CSD V1 or V2
+ }
+ }
+
+ return (err == 0) ? res : NULL;
+}
+
+static int stm32_sdio_card_detect(void)
+{
+ uint8_t block[BLOCK_SIZE];
+ SDIO_CARD sdcard;
+ if (SD.card != NULL)
+ return 0;
+ sdcard = stm32_sdio_open(&SD);
+ if (sdcard != NULL) {
+ SD.card = sdcard;
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * Set up the GPIO pins and peripheral clocks for the SDIO
+ * system. The code should probably take an option card detect
+ * pin, at the moment it uses the one used by the Embest board.
+ */
+static void sdio_hw_init(void)
+{
+ int i;
+ uint32_t reg;
+ /* Enable clocks for SDIO and DMA2 */
+ APB2_CLOCK_ER |= SDIO_APB2_CLOCK_ER_VAL;
+ /* Enable clocks for GPIOA, GPIOC, GPIOD */
+ AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER |
+ GPIOC_AHB1_CLOCK_ER | GPIOD_AHB1_CLOCK_ER;
+ for (i = 0 ; i < 5; i++) {
+ /* mode = AF */
+ reg = GPIOC_MODE & ~ (0x03 << (sdio_pins[i] * 2));
+ GPIOC_MODE = reg | (2 << (sdio_pins[i] * 2));
+
+#if 0
+ /* Set 100MHz ospeed + pullup */
+ GPIOC_OSPEED |= (0x03 << (sdio_pins[i] * 2));
+ GPIOC_OTYPE &= ~(0x01 << (sdio_pins[i]));
+ reg = GPIOC_PUPD & (~(0x03 << (sdio_pins[i] & 2)));
+ GPIOC_PUPD = reg | (1 << (sdio_pins[i] * 2));
+#endif
+
+ /* Alternate function: use high pins (8..12) */
+ reg = GPIOC_AFH & ~(0xf << ((sdio_pins[i] - 8) * 4));
+ GPIOC_AFH = reg | (sdio_af << ((sdio_pins[i] - 8) * 4));
+ }
+ /* cmd pin */
+ reg = GPIOD_MODE & ~ (0x03 << (sdio_cmd_pin * 2));
+ GPIOD_MODE = reg | (2 << (sdio_cmd_pin * 2));
+#if 0
+ /* Set 100MHz ospeed + pullup */
+ GPIOD_OSPEED |= (0x03 << (sdio_cmd_pin * 2));
+ GPIOD_OTYPE &= ~(0x01 << (sdio_cmd_pin));
+ reg = GPIOD_PUPD & (~(0x03 << (sdio_cmd_pin & 2)));
+ GPIOD_PUPD = reg | (1 << (sdio_cmd_pin * 2));
+#endif
+ /* Alternate function: use low pin */
+ reg = GPIOD_AFL & ~(0xf << ((sdio_cmd_pin) * 4));
+ GPIOD_AFL = reg | (sdio_af << ((sdio_cmd_pin) * 4));
+
+ /* card detect pin configured as input */
+ GPIOA_MODE &= ~ (0x03 << (sdio_detect_pin * 2));
+ reg = GPIOA_PUPD & (~(0x03 << (sdio_detect_pin & 2)));
+ GPIOA_PUPD = reg | (1 << (sdio_detect_pin * 2));
+}
+
+void *block_open(void)
+{
+ int ret;
+ /* Initialize sdio RCC and pins */
+ sdio_hw_init();
+ do {
+ ret = stm32_sdio_card_detect();
+ } while (ret < 0);
+ return &SD;
+}
+
+
diff --git a/src/usecfs_dev_sdio.h b/src/usecfs_dev_sdio.h
new file mode 100644
index 0000000..bf7b8b8
--- /dev/null
+++ b/src/usecfs_dev_sdio.h
@@ -0,0 +1,54 @@
+/* this define lets the init code know that you are using a GPIO as a card
+ * detect pin */
+#define SDIO_HAS_CARD_DETECT
+
+enum SDIO_CLOCK_DIV {
+ SDIO_24MHZ = 0,
+ SDIO_16MHZ,
+ SDIO_12MHZ,
+ SDIO_8MHZ,
+ SDIO_4MHZ,
+ SDIO_1MHZ,
+ SDIO_400KHZ
+};
+
+enum SDIO_POWER_STATE {
+ SDIO_POWER_ON,
+ SDIO_POWER_OFF
+};
+
+#define SDIO_CARD_CCS(c) (((c)->ocr & 0x40000000) != 0)
+#define SDIO_CARD_UHS2(c) (((c)->ocr & 0x40000000) != 0)
+#define SDIO_CARD_LVOK(c) (((c)->ocr & 0x01000000) != 0)
+
+typedef struct SDIO_CARD_DATA {
+ uint32_t props;
+ uint32_t ocr;
+ uint32_t cid[4];
+ uint32_t csd[4];
+ uint32_t scr[2];
+ uint32_t status[16];
+ uint32_t size;
+ uint16_t rca;
+} * SDIO_CARD;
+
+struct dev_sd {
+ struct device *dev;
+ uint32_t base;
+ uint32_t *rcc_rst_reg;
+ uint32_t rcc_rst;
+ SDIO_CARD card;
+};
+
+/* API for sd_bus clock setting */
+enum SD_CLOCK_DIV {
+ CLOCK_24MHZ = 0,
+ CLOCK_16MHZ,
+ CLOCK_12MHZ,
+ CLOCK_8MHZ,
+ CLOCK_4MHZ,
+ CLOCK_1MHZ,
+ CLOCK_400KHZ
+};
+
+//int stm32_sd_bus(int bits, enum SD_CLOCK_DIV freq);