* [U-Boot] [PATCH 0/4] generic mmc_spi driver
@ 2010-12-24 7:16 Thomas Chou
2010-12-24 7:16 ` [U-Boot] [PATCH 1/4] lib: add crc7 from Linux Thomas Chou
` (5 more replies)
0 siblings, 6 replies; 22+ messages in thread
From: Thomas Chou @ 2010-12-24 7:16 UTC (permalink / raw)
To: u-boot
This is the v9 update of the mmc_spi driver. Please enable DEBUG on the top of
mmc_spi.c and help me perform the tests.
A new spi_set_speed() is added to meet the 400KHz clock requirement during mmc card
initialization. An example update to bfin_spi is included. The altera_spi core does
not support speed change, so I am going to post a new opencore ip for this.
The driver now claims and releases the spi bus for each mmc command, as Mike suggested.
Thomas Chou (4):
lib: add crc7 from Linux
spi: add spi_set_speed func
bfin_spi: add spi_set_speed
mmc: add generic mmc spi driver
common/Makefile | 1 +
common/cmd_mmc_spi.c | 88 +++++++++++++++
drivers/mmc/Makefile | 1 +
drivers/mmc/mmc.c | 93 +++++++++++++----
drivers/mmc/mmc_spi.c | 278 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/spi/Makefile | 1 +
drivers/spi/bfin_spi.c | 32 ++++---
drivers/spi/spi.c | 9 ++
include/linux/crc7.h | 14 +++
include/mmc.h | 5 +
include/spi.h | 8 ++
lib/Makefile | 1 +
lib/crc7.c | 62 +++++++++++
13 files changed, 560 insertions(+), 33 deletions(-)
create mode 100644 common/cmd_mmc_spi.c
create mode 100644 drivers/mmc/mmc_spi.c
create mode 100644 drivers/spi/spi.c
create mode 100644 include/linux/crc7.h
create mode 100644 lib/crc7.c
--
1.7.3.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 1/4] lib: add crc7 from Linux
2010-12-24 7:16 [U-Boot] [PATCH 0/4] generic mmc_spi driver Thomas Chou
@ 2010-12-24 7:16 ` Thomas Chou
2011-01-10 20:59 ` Wolfgang Denk
2010-12-24 7:16 ` [U-Boot] [PATCH 2/4] spi: add spi_set_speed func Thomas Chou
` (4 subsequent siblings)
5 siblings, 1 reply; 22+ messages in thread
From: Thomas Chou @ 2010-12-24 7:16 UTC (permalink / raw)
To: u-boot
Crc7 is used to compute mmc spi comamnd packet checksum.
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
include/linux/crc7.h | 14 +++++++++++
lib/Makefile | 1 +
lib/crc7.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 77 insertions(+), 0 deletions(-)
create mode 100644 include/linux/crc7.h
create mode 100644 lib/crc7.c
diff --git a/include/linux/crc7.h b/include/linux/crc7.h
new file mode 100644
index 0000000..1786e77
--- /dev/null
+++ b/include/linux/crc7.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_CRC7_H
+#define _LINUX_CRC7_H
+#include <linux/types.h>
+
+extern const u8 crc7_syndrome_table[256];
+
+static inline u8 crc7_byte(u8 crc, u8 data)
+{
+ return crc7_syndrome_table[(crc << 1) ^ data];
+}
+
+extern u8 crc7(u8 crc, const u8 *buffer, size_t len);
+
+#endif
diff --git a/lib/Makefile b/lib/Makefile
index ffdee7d..fcfe351 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -32,6 +32,7 @@ COBJS-$(CONFIG_BZIP2) += bzlib_decompress.o
COBJS-$(CONFIG_BZIP2) += bzlib_randtable.o
COBJS-$(CONFIG_BZIP2) += bzlib_huffman.o
COBJS-$(CONFIG_USB_TTY) += circbuf.o
+COBJS-y += crc7.o
COBJS-y += crc16.o
COBJS-y += crc32.o
COBJS-y += ctype.o
diff --git a/lib/crc7.c b/lib/crc7.c
new file mode 100644
index 0000000..e635c9c
--- /dev/null
+++ b/lib/crc7.c
@@ -0,0 +1,62 @@
+/*
+ * crc7.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/crc7.h>
+
+
+/* Table for CRC-7 (polynomial x^7 + x^3 + 1) */
+const u8 crc7_syndrome_table[256] = {
+ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
+ 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
+ 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
+ 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
+ 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
+ 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
+ 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
+ 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
+ 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
+ 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
+ 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
+ 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
+ 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
+ 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
+ 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
+ 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
+ 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
+ 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
+ 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
+ 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
+ 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
+ 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
+ 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
+ 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
+ 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
+ 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
+ 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
+ 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
+ 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
+ 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
+ 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
+ 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
+};
+
+/**
+ * crc7 - update the CRC7 for the data buffer
+ * @crc: previous CRC7 value
+ * @buffer: data pointer
+ * @len: number of bytes in the buffer
+ * Context: any
+ *
+ * Returns the updated CRC7 value.
+ */
+u8 crc7(u8 crc, const u8 *buffer, size_t len)
+{
+ while (len--)
+ crc = crc7_byte(crc, *buffer++);
+ return crc;
+}
--
1.7.3.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 2/4] spi: add spi_set_speed func
2010-12-24 7:16 [U-Boot] [PATCH 0/4] generic mmc_spi driver Thomas Chou
2010-12-24 7:16 ` [U-Boot] [PATCH 1/4] lib: add crc7 from Linux Thomas Chou
@ 2010-12-24 7:16 ` Thomas Chou
2010-12-24 17:09 ` Mike Frysinger
2010-12-24 23:13 ` [U-Boot] [PATCH 2/4 v2] " Thomas Chou
2010-12-24 7:16 ` [U-Boot] [PATCH 3/4] bfin_spi: add spi_set_speed Thomas Chou
` (3 subsequent siblings)
5 siblings, 2 replies; 22+ messages in thread
From: Thomas Chou @ 2010-12-24 7:16 UTC (permalink / raw)
To: u-boot
This func helps mmc_spi driver set correct speed for mmc/sd, as
mmc card needs 400KHz clock for spi mode initialization.
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
drivers/spi/Makefile | 1 +
drivers/spi/spi.c | 9 +++++++++
include/spi.h | 8 ++++++++
3 files changed, 18 insertions(+), 0 deletions(-)
create mode 100644 drivers/spi/spi.c
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e34a124..c4eb627 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libspi.o
+COBJS-$(CONFIG_MMC_SPI) += spi.o
COBJS-$(CONFIG_ALTERA_SPI) += altera_spi.o
COBJS-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
new file mode 100644
index 0000000..944466a
--- /dev/null
+++ b/drivers/spi/spi.c
@@ -0,0 +1,9 @@
+#include <common.h>
+#include <spi.h>
+
+/* default func for SPI driver without set speed func */
+static void __spi_set_speed(struct spi_slave *slave, uint hz)
+{
+}
+void spi_set_speed(struct spi_slave *slave, uint hz)
+ __attribute__((weak, alias("__spi_set_speed")));
diff --git a/include/spi.h b/include/spi.h
index 320e50e..7887d0f 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -176,6 +176,14 @@ void spi_cs_activate(struct spi_slave *slave);
void spi_cs_deactivate(struct spi_slave *slave);
/*-----------------------------------------------------------------------
+ * Set transfer speed.
+ * This sets a new speed to be applied for next spi_xfer().
+ * slave: The SPI slave
+ * hz: The transfer speed
+ */
+void spi_set_speed(struct spi_slave *slave, uint hz);
+
+/*-----------------------------------------------------------------------
* Write 8 bits, then read 8 bits.
* slave: The SPI slave we're communicating with
* byte: Byte to be written
--
1.7.3.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 3/4] bfin_spi: add spi_set_speed
2010-12-24 7:16 [U-Boot] [PATCH 0/4] generic mmc_spi driver Thomas Chou
2010-12-24 7:16 ` [U-Boot] [PATCH 1/4] lib: add crc7 from Linux Thomas Chou
2010-12-24 7:16 ` [U-Boot] [PATCH 2/4] spi: add spi_set_speed func Thomas Chou
@ 2010-12-24 7:16 ` Thomas Chou
2010-12-24 17:25 ` Mike Frysinger
2010-12-24 7:16 ` [U-Boot] [PATCH 4/4] mmc: add generic mmc spi driver Thomas Chou
` (2 subsequent siblings)
5 siblings, 1 reply; 22+ messages in thread
From: Thomas Chou @ 2010-12-24 7:16 UTC (permalink / raw)
To: u-boot
The new speed will be applied by spi_claim_bus.
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
drivers/spi/bfin_spi.c | 32 +++++++++++++++++++-------------
1 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/drivers/spi/bfin_spi.c b/drivers/spi/bfin_spi.c
index d7e1474..bfecdaf 100644
--- a/drivers/spi/bfin_spi.c
+++ b/drivers/spi/bfin_spi.c
@@ -138,13 +138,29 @@ static const unsigned short cs_pins[][7] = {
#endif
};
+void spi_set_speed(struct spi_slave *slave, uint hz)
+{
+ struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
+ ulong sclk;
+ u32 baud;
+
+ sclk = get_sclk();
+ baud = sclk / (2 * hz);
+ /* baud should be rounded up */
+ if (sclk % (2 * hz))
+ baud += 1;
+ if (baud < 2)
+ baud = 2;
+ else if (baud > (u16)-1)
+ baud = -1;
+ bss->baud = baud;
+}
+
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
struct bfin_spi_slave *bss;
- ulong sclk;
u32 mmr_base;
- u32 baud;
if (!spi_cs_is_valid(bus, cs))
return NULL;
@@ -166,16 +182,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
default: return NULL;
}
- sclk = get_sclk();
- baud = sclk / (2 * max_hz);
- /* baud should be rounded up */
- if (sclk % (2 * max_hz))
- baud += 1;
- if (baud < 2)
- baud = 2;
- else if (baud > (u16)-1)
- baud = -1;
-
bss = malloc(sizeof(*bss));
if (!bss)
return NULL;
@@ -187,8 +193,8 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (mode & SPI_CPHA) bss->ctl |= CPHA;
if (mode & SPI_CPOL) bss->ctl |= CPOL;
if (mode & SPI_LSB_FIRST) bss->ctl |= LSBF;
- bss->baud = baud;
bss->flg = mode & SPI_CS_HIGH ? 1 : 0;
+ spi_set_speed(&bss->slave, max_hz);
debug("%s: bus:%i cs:%i mmr:%x ctl:%x baud:%i flg:%i\n", __func__,
bus, cs, mmr_base, bss->ctl, baud, bss->flg);
--
1.7.3.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 4/4] mmc: add generic mmc spi driver
2010-12-24 7:16 [U-Boot] [PATCH 0/4] generic mmc_spi driver Thomas Chou
` (2 preceding siblings ...)
2010-12-24 7:16 ` [U-Boot] [PATCH 3/4] bfin_spi: add spi_set_speed Thomas Chou
@ 2010-12-24 7:16 ` Thomas Chou
2010-12-24 23:12 ` [U-Boot] [PATCH 4/4 v10] " Thomas Chou
2010-12-24 17:24 ` [U-Boot] [PATCH 0/4] generic mmc_spi driver Mike Frysinger
2011-04-12 6:58 ` Mike Frysinger
5 siblings, 1 reply; 22+ messages in thread
From: Thomas Chou @ 2010-12-24 7:16 UTC (permalink / raw)
To: u-boot
This patch supports mmc/sd card with spi interface. It is based on
the generic mmc framework. It works with SDHC and supports multi
blocks read/write.
The crc checksum on data packet is enabled with the def,
There is a subcomamnd "mmc_spi" to setup spi bus and cs at run time.
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
common/Makefile | 1 +
common/cmd_mmc_spi.c | 88 ++++++++++++++++
drivers/mmc/Makefile | 1 +
drivers/mmc/mmc.c | 93 +++++++++++++----
drivers/mmc/mmc_spi.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++++
include/mmc.h | 5 +
6 files changed, 446 insertions(+), 20 deletions(-)
create mode 100644 common/cmd_mmc_spi.c
create mode 100644 drivers/mmc/mmc_spi.c
diff --git a/common/Makefile b/common/Makefile
index abea91c..381ac38 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -117,6 +117,7 @@ COBJS-$(CONFIG_CMD_MII) += miiphyutil.o
COBJS-$(CONFIG_CMD_MII) += cmd_mii.o
COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o
COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o
+COBJS-$(CONFIG_CMD_MMC_SPI) += cmd_mmc_spi.o
COBJS-$(CONFIG_MP) += cmd_mp.o
COBJS-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o
COBJS-$(CONFIG_CMD_NAND) += cmd_nand.o
diff --git a/common/cmd_mmc_spi.c b/common/cmd_mmc_spi.c
new file mode 100644
index 0000000..63fe313
--- /dev/null
+++ b/common/cmd_mmc_spi.c
@@ -0,0 +1,88 @@
+/*
+ * Command for mmc_spi setup.
+ *
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <spi.h>
+
+#ifndef CONFIG_MMC_SPI_BUS
+# define CONFIG_MMC_SPI_BUS 0
+#endif
+#ifndef CONFIG_MMC_SPI_CS
+# define CONFIG_MMC_SPI_CS 1
+#endif
+/* in SPI mode, MMC speed limit is 20MHz, while SD speed limit is 25MHz */
+#ifndef CONFIG_MMC_SPI_SPEED
+# define CONFIG_MMC_SPI_SPEED 25000000
+#endif
+/* MMC and SD specs only seem to care that sampling is on the
+ * rising edge ... meaning SPI modes 0 or 3. So either SPI mode
+ * should be legit. We'll use mode 0 since the steady state is 0,
+ * which is appropriate for hotplugging, unless the platform data
+ * specify mode 3 (if hardware is not compatible to mode 0).
+ */
+#ifndef CONFIG_MMC_SPI_MODE
+# define CONFIG_MMC_SPI_MODE SPI_MODE_0
+#endif
+
+static int do_mmc_spi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint bus = CONFIG_MMC_SPI_BUS;
+ uint cs = CONFIG_MMC_SPI_CS;
+ uint speed = CONFIG_MMC_SPI_SPEED;
+ uint mode = CONFIG_MMC_SPI_MODE;
+ char *endp;
+ struct mmc *mmc;
+
+ if (argc < 2)
+ goto usage;
+
+ cs = simple_strtoul(argv[1], &endp, 0);
+ if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
+ goto usage;
+ if (*endp == ':') {
+ if (endp[1] == 0)
+ goto usage;
+ bus = cs;
+ cs = simple_strtoul(endp + 1, &endp, 0);
+ if (*endp != 0)
+ goto usage;
+ }
+ if (argc >= 3) {
+ speed = simple_strtoul(argv[2], &endp, 0);
+ if (*argv[2] == 0 || *endp != 0)
+ goto usage;
+ }
+ if (argc >= 4) {
+ mode = simple_strtoul(argv[3], &endp, 16);
+ if (*argv[3] == 0 || *endp != 0)
+ goto usage;
+ }
+ if (!spi_cs_is_valid(bus, cs)) {
+ printf("Invalid SPI bus %u cs %u\n", bus, cs);
+ return 1;
+ }
+
+ mmc = mmc_spi_init(bus, cs, speed, mode);
+ if (!mmc) {
+ printf("Failed to create MMC Device\n");
+ return 1;
+ }
+ printf("%s: %d at %u:%u hz %u mode %u\n", mmc->name, mmc->block_dev.dev,
+ bus, cs, speed, mode);
+ return 0;
+
+usage:
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+U_BOOT_CMD(
+ mmc_spi, 4, 0, do_mmc_spi,
+ "mmc_spi setup",
+ "[bus:]cs [hz] [mode] - setup mmc_spi device"
+);
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 68afd30..599105f 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -30,6 +30,7 @@ COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
+COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o
COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6805b33..7218a36 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -112,7 +112,10 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
return 0;
}
- if (blkcnt > 1) {
+ /* SPI multiblock writes terminate using a special
+ * token, not a STOP_TRANSMISSION request.
+ */
+ if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
@@ -280,7 +283,8 @@ sd_send_op_cond(struct mmc *mmc)
* how to manage low voltages SD card is not yet
* specified.
*/
- cmd.cmdarg = mmc->voltages & 0xff8000;
+ cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
+ (mmc->voltages & 0xff8000);
if (mmc->version == SD_VERSION_2)
cmd.cmdarg |= OCR_HCS;
@@ -299,6 +303,18 @@ sd_send_op_cond(struct mmc *mmc)
if (mmc->version != SD_VERSION_2)
mmc->version = SD_VERSION_1_0;
+ if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
+ cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
+ cmd.resp_type = MMC_RSP_R3;
+ cmd.cmdarg = 0;
+ cmd.flags = 0;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+ }
+
mmc->ocr = cmd.response[0];
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
@@ -319,7 +335,8 @@ int mmc_send_op_cond(struct mmc *mmc)
do {
cmd.cmdidx = MMC_CMD_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = OCR_HCS | mmc->voltages;
+ cmd.cmdarg = OCR_HCS | (mmc_host_is_spi(mmc) ? 0 :
+ mmc->voltages);
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
@@ -333,6 +350,18 @@ int mmc_send_op_cond(struct mmc *mmc)
if (timeout <= 0)
return UNUSABLE_ERR;
+ if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
+ cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
+ cmd.resp_type = MMC_RSP_R3;
+ cmd.cmdarg = 0;
+ cmd.flags = 0;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+ }
+
mmc->version = MMC_VERSION_UNKNOWN;
mmc->ocr = cmd.response[0];
@@ -388,6 +417,9 @@ int mmc_change_freq(struct mmc *mmc)
mmc->card_caps = 0;
+ if (mmc_host_is_spi(mmc))
+ return 0;
+
/* Only version 4 supports high-speed */
if (mmc->version < MMC_VERSION_4)
return 0;
@@ -461,6 +493,9 @@ int sd_change_freq(struct mmc *mmc)
mmc->card_caps = 0;
+ if (mmc_host_is_spi(mmc))
+ return 0;
+
/* Read the SCR to find out if this card supports higher speeds */
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
@@ -611,8 +646,22 @@ int mmc_startup(struct mmc *mmc)
struct mmc_cmd cmd;
char ext_csd[512];
+#ifdef CONFIG_MMC_SPI_CRC_ON
+ if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
+ cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.cmdarg = 1;
+ cmd.flags = 0;
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+ }
+#endif
+
/* Put the Card in Identify Mode */
- cmd.cmdidx = MMC_CMD_ALL_SEND_CID;
+ cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
+ MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
cmd.resp_type = MMC_RSP_R2;
cmd.cmdarg = 0;
cmd.flags = 0;
@@ -629,18 +678,20 @@ int mmc_startup(struct mmc *mmc)
* For SD cards, get the Relatvie Address.
* This also puts the cards into Standby State
*/
- cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
- cmd.cmdarg = mmc->rca << 16;
- cmd.resp_type = MMC_RSP_R6;
- cmd.flags = 0;
+ if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
+ cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
+ cmd.cmdarg = mmc->rca << 16;
+ cmd.resp_type = MMC_RSP_R6;
+ cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
+ if (err)
+ return err;
- if (IS_SD(mmc))
- mmc->rca = (cmd.response[0] >> 16) & 0xffff;
+ if (IS_SD(mmc))
+ mmc->rca = (cmd.response[0] >> 16) & 0xffff;
+ }
/* Get the Card-Specific Data */
cmd.cmdidx = MMC_CMD_SEND_CSD;
@@ -716,14 +767,16 @@ int mmc_startup(struct mmc *mmc)
mmc->write_bl_len = 512;
/* Select the card, and put it into Transfer Mode */
- cmd.cmdidx = MMC_CMD_SELECT_CARD;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.cmdarg = mmc->rca << 16;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
+ cmd.cmdidx = MMC_CMD_SELECT_CARD;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = mmc->rca << 16;
+ cmd.flags = 0;
+ err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
+ if (err)
+ return err;
+ }
if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
/* check ext_csd version and capacity */
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c
new file mode 100644
index 0000000..6882fbd
--- /dev/null
+++ b/drivers/mmc/mmc_spi.c
@@ -0,0 +1,278 @@
+/*
+ * generic mmc spi driver
+ *
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Licensed under the GPL-2 or later.
+ */
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+#include <spi.h>
+#include <crc.h>
+#include <linux/crc7.h>
+#include <linux/byteorder/swab.h>
+
+/* MMC/SD in SPI mode reports R1 status always */
+#define R1_SPI_IDLE (1 << 0)
+#define R1_SPI_ERASE_RESET (1 << 1)
+#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
+#define R1_SPI_COM_CRC (1 << 3)
+#define R1_SPI_ERASE_SEQ (1 << 4)
+#define R1_SPI_ADDRESS (1 << 5)
+#define R1_SPI_PARAMETER (1 << 6)
+/* R1 bit 7 is always zero, reuse this bit for error */
+#define R1_SPI_ERROR (1 << 7)
+
+/* Response tokens used to ack each block written: */
+#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f)
+#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1)
+#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1)
+#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1)
+
+/* Read and write blocks start with these tokens and end with crc;
+ * on error, read tokens act like a subset of R2_SPI_* values.
+ */
+#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */
+#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */
+#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */
+
+/* MMC SPI commands start with a start bit "0" and a transmit bit "1" */
+#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f))
+
+/* bus capability */
+#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34)
+#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */
+
+/* timeout value */
+#define CTOUT 8
+#define RTOUT 3000000 /* 1 sec */
+#define WTOUT 3000000 /* 1 sec */
+
+static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg)
+{
+ struct spi_slave *spi = mmc->priv;
+ u8 cmdo[7];
+ u8 r1;
+ int i;
+ cmdo[0] = 0xff;
+ cmdo[1] = MMC_SPI_CMD(cmdidx);
+ cmdo[2] = cmdarg >> 24;
+ cmdo[3] = cmdarg >> 16;
+ cmdo[4] = cmdarg >> 8;
+ cmdo[5] = cmdarg;
+ cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
+ spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0);
+ for (i = 0; i < CTOUT; i++) {
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if (i && (r1 & 0x80) == 0) /* r1 response */
+ break;
+ }
+ debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1);
+ return r1;
+}
+
+static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf,
+ u32 bcnt, u32 bsize)
+{
+ struct spi_slave *spi = mmc->priv;
+ u8 *buf = xbuf;
+ u8 r1;
+ u16 crc;
+ int i;
+ while (bcnt--) {
+ for (i = 0; i < RTOUT; i++) {
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if (r1 != 0xff) /* data token */
+ break;
+ }
+ debug("%s:tok%d %x\n", __func__, i, r1);
+ if (r1 == SPI_TOKEN_SINGLE) {
+ spi_xfer(spi, bsize * 8, NULL, buf, 0);
+ spi_xfer(spi, 2 * 8, NULL, &crc, 0);
+#ifdef CONFIG_MMC_SPI_CRC_ON
+ if (swab16(cyg_crc16(buf, bsize)) != crc) {
+ debug("%s: CRC error\n", mmc->name);
+ r1 = R1_SPI_COM_CRC;
+ break;
+ }
+#endif
+ r1 = 0;
+ } else {
+ r1 = R1_SPI_ERROR;
+ break;
+ }
+ buf += bsize;
+ }
+ return r1;
+}
+
+static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf,
+ u32 bcnt, u32 bsize, int multi)
+{
+ struct spi_slave *spi = mmc->priv;
+ const u8 *buf = xbuf;
+ u8 r1;
+ u16 crc;
+ u8 tok[2];
+ int i;
+ tok[0] = 0xff;
+ tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
+ while (bcnt--) {
+#ifdef CONFIG_MMC_SPI_CRC_ON
+ crc = swab16(cyg_crc16((u8 *)buf, bsize));
+#endif
+ spi_xfer(spi, 2 * 8, tok, NULL, 0);
+ spi_xfer(spi, bsize * 8, buf, NULL, 0);
+ spi_xfer(spi, 2 * 8, &crc, NULL, 0);
+ for (i = 0; i < CTOUT; i++) {
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if ((r1 & 0x10) == 0) /* response token */
+ break;
+ }
+ debug("%s:tok%d %x\n", __func__, i, r1);
+ if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
+ for (i = 0; i < WTOUT; i++) { /* wait busy */
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if (i && r1 == 0xff) {
+ r1 = 0;
+ break;
+ }
+ }
+ if (i == WTOUT) {
+ debug("%s:wtout %x\n", __func__, r1);
+ r1 = R1_SPI_ERROR;
+ break;
+ }
+ } else {
+ debug("%s: err %x\n", __func__, r1);
+ r1 = R1_SPI_COM_CRC;
+ break;
+ }
+ buf += bsize;
+ }
+ if (multi && bcnt == -1) { /* stop multi write */
+ tok[1] = SPI_TOKEN_STOP_TRAN;
+ spi_xfer(spi, 2 * 8, tok, NULL, 0);
+ for (i = 0; i < WTOUT; i++) { /* wait busy */
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if (i && r1 == 0xff) {
+ r1 = 0;
+ break;
+ }
+ }
+ if (i == WTOUT) {
+ debug("%s:wstop %x\n", __func__, r1);
+ r1 = R1_SPI_ERROR;
+ }
+ }
+ return r1;
+}
+
+static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ struct spi_slave *spi = mmc->priv;
+ u8 r1;
+ int i;
+ int ret = 0;
+ debug("%s:cmd%d %x %x %x\n", __func__,
+ cmd->cmdidx, cmd->resp_type, cmd->cmdarg, cmd->flags);
+ spi_claim_bus(spi);
+ spi_cs_activate(spi);
+ r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg);
+ if (r1 == 0xff) { /* no response */
+ ret = NO_CARD_ERR;
+ goto done;
+ } else if (r1 & R1_SPI_COM_CRC) {
+ ret = COMM_ERR;
+ goto done;
+ } else if (r1 & ~R1_SPI_IDLE) { /* other errors */
+ ret = TIMEOUT;
+ goto done;
+ } else if (cmd->resp_type == MMC_RSP_R2) {
+ r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16);
+ for (i = 0; i < 4; i++)
+ cmd->response[i] = swab32(cmd->response[i]);
+ debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1],
+ cmd->response[2], cmd->response[3]);
+ } else if (!data) {
+ switch (cmd->cmdidx) {
+ case SD_CMD_APP_SEND_OP_COND:
+ case MMC_CMD_SEND_OP_COND:
+ cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
+ break;
+ case SD_CMD_SEND_IF_COND:
+ case MMC_CMD_SPI_READ_OCR:
+ spi_xfer(spi, 4 * 8, NULL, cmd->response, 0);
+ cmd->response[0] = swab32(cmd->response[0]);
+ debug("r32 %x\n", cmd->response[0]);
+ break;
+ }
+ } else {
+ debug("%s:data %x %x %x\n", __func__,
+ data->flags, data->blocks, data->blocksize);
+ if (data->flags == MMC_DATA_READ)
+ r1 = mmc_spi_readdata(mmc, data->dest,
+ data->blocks, data->blocksize);
+ else if (data->flags == MMC_DATA_WRITE)
+ r1 = mmc_spi_writedata(mmc, data->src,
+ data->blocks, data->blocksize,
+ (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK));
+ if (r1 & R1_SPI_COM_CRC)
+ ret = COMM_ERR;
+ else if (r1) /* other errors */
+ ret = TIMEOUT;
+ }
+done:
+ spi_cs_deactivate(spi);
+ spi_release_bus(spi);
+ return ret;
+}
+
+static void mmc_spi_set_ios(struct mmc *mmc)
+{
+ struct spi_slave *spi = mmc->priv;
+ debug("%s: clock %u\n", __func__, mmc->clock);
+ if (mmc->clock)
+ spi_set_speed(spi, mmc->clock);
+}
+
+static int mmc_spi_init_p(struct mmc *mmc)
+{
+ struct spi_slave *spi = mmc->priv;
+ spi_claim_bus(spi);
+ /* cs deactivated for 100+ clock */
+ spi_xfer(spi, 18 * 8, NULL, NULL, 0);
+ spi_release_bus(spi);
+ return 0;
+}
+
+struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode)
+{
+ struct mmc *mmc;
+
+ mmc = malloc(sizeof(*mmc));
+ if (!mmc)
+ return NULL;
+ memset(mmc, 0, sizeof(*mmc));
+ mmc->priv = spi_setup_slave(bus, cs, speed, mode);
+ if (!mmc->priv) {
+ free(mmc);
+ return NULL;
+ }
+ sprintf(mmc->name, "MMC_SPI");
+ mmc->send_cmd = mmc_spi_request;
+ mmc->set_ios = mmc_spi_set_ios;
+ mmc->init = mmc_spi_init_p;
+ mmc->host_caps = MMC_MODE_SPI;
+
+ mmc->voltages = MMC_SPI_VOLTAGE;
+ mmc->f_max = speed;
+ mmc->f_min = MMC_SPI_MIN_CLOCK;
+ mmc->block_dev.part_type = PART_TYPE_DOS;
+
+ mmc_register(mmc);
+
+ return mmc;
+}
diff --git a/include/mmc.h b/include/mmc.h
index 74c0b1d..0b1e064 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -44,6 +44,7 @@
#define MMC_MODE_HS_52MHz 0x010
#define MMC_MODE_4BIT 0x100
#define MMC_MODE_8BIT 0x200
+#define MMC_MODE_SPI 0x400
#define SD_DATA_4BIT 0x00040000
@@ -75,6 +76,8 @@
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
#define MMC_CMD_APP_CMD 55
+#define MMC_CMD_SPI_READ_OCR 58
+#define MMC_CMD_SPI_CRC_ON_OFF 59
#define SD_CMD_SEND_RELATIVE_ADDR 3
#define SD_CMD_SWITCH_FUNC 6
@@ -288,6 +291,8 @@ int board_mmc_getcd(u8 *cd, struct mmc *mmc);
#ifdef CONFIG_GENERIC_MMC
int atmel_mci_init(void *regs);
+#define mmc_host_is_spi(mmc) ((mmc)->host_caps & MMC_MODE_SPI)
+struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode);
#else
int mmc_legacy_init(int verbose);
#endif
--
1.7.3.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 2/4] spi: add spi_set_speed func
2010-12-24 7:16 ` [U-Boot] [PATCH 2/4] spi: add spi_set_speed func Thomas Chou
@ 2010-12-24 17:09 ` Mike Frysinger
2010-12-24 23:13 ` [U-Boot] [PATCH 2/4 v2] " Thomas Chou
1 sibling, 0 replies; 22+ messages in thread
From: Mike Frysinger @ 2010-12-24 17:09 UTC (permalink / raw)
To: u-boot
On Friday, December 24, 2010 02:16:07 Thomas Chou wrote:
> --- /dev/null
> +++ b/drivers/spi/spi.c
> @@ -0,0 +1,9 @@
> +#include <common.h>
> +#include <spi.h>
> +
> +/* default func for SPI driver without set speed func */
> +static void __spi_set_speed(struct spi_slave *slave, uint hz)
> +{
> +}
> +void spi_set_speed(struct spi_slave *slave, uint hz)
> + __attribute__((weak, alias("__spi_set_speed")));
let's not go this route. just add the prototype to the header and when the
respective spi bus maintainer wants to support this new func, they can
implement it. i'd rather people know about the problem up front rather than
have things randomly not work.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101224/9999498e/attachment.pgp
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 0/4] generic mmc_spi driver
2010-12-24 7:16 [U-Boot] [PATCH 0/4] generic mmc_spi driver Thomas Chou
` (3 preceding siblings ...)
2010-12-24 7:16 ` [U-Boot] [PATCH 4/4] mmc: add generic mmc spi driver Thomas Chou
@ 2010-12-24 17:24 ` Mike Frysinger
2010-12-24 19:06 ` Reinhard Meyer
2011-04-12 6:58 ` Mike Frysinger
5 siblings, 1 reply; 22+ messages in thread
From: Mike Frysinger @ 2010-12-24 17:24 UTC (permalink / raw)
To: u-boot
On Friday, December 24, 2010 02:16:05 Thomas Chou wrote:
> This is the v9 update of the mmc_spi driver. Please enable DEBUG on the top
> of mmc_spi.c and help me perform the tests.
>
> A new spi_set_speed() is added to meet the 400KHz clock requirement during
> mmc card initialization. An example update to bfin_spi is included. The
> altera_spi core does not support speed change, so I am going to post a new
> opencore ip for this.
this seems to work much nicer for me. only odd thing is that 'fatls' does not
work if i dont 'mmcinfo' first. do you see the same ? maybe this is
(currently) expected behavior ?
from cold boot:
bfin> mmc_spi 4
MMC_SPI: 0 at 0:4 hz 25000000 mode 0
bfin> fatls mmc 0:1
MMC: block number 0x1 exceeds max(0x0)
** Can't read from device 0 **
** Unable to use mmc 0:1 for fatls **
bfin> mmcinfo
Device: MMC_SPI
Manufacturer ID: 0
OEM: 2
Name: card
Tran Speed: 25000000
Rd Block Len: 512
SD version 1.0
High Capacity: No
Capacity: 31326208
Bus Width: 1-bit
bfin> fatls mmc 0:1
private/
bootmii/
3041 installer.log
apps/
5213 readme-bootmii.txt
7273 readme-hbc.txt
config/
3 file(s), 4 dir(s)
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101224/511e161d/attachment.pgp
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 3/4] bfin_spi: add spi_set_speed
2010-12-24 7:16 ` [U-Boot] [PATCH 3/4] bfin_spi: add spi_set_speed Thomas Chou
@ 2010-12-24 17:25 ` Mike Frysinger
0 siblings, 0 replies; 22+ messages in thread
From: Mike Frysinger @ 2010-12-24 17:25 UTC (permalink / raw)
To: u-boot
On Friday, December 24, 2010 02:16:08 Thomas Chou wrote:
> The new speed will be applied by spi_claim_bus.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101224/4263ee3e/attachment.pgp
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 0/4] generic mmc_spi driver
2010-12-24 17:24 ` [U-Boot] [PATCH 0/4] generic mmc_spi driver Mike Frysinger
@ 2010-12-24 19:06 ` Reinhard Meyer
2010-12-24 19:45 ` Mike Frysinger
0 siblings, 1 reply; 22+ messages in thread
From: Reinhard Meyer @ 2010-12-24 19:06 UTC (permalink / raw)
To: u-boot
Dear Mike Frysinger,
> this seems to work much nicer for me. only odd thing is that 'fatls' does not
> work if i dont 'mmcinfo' first. do you see the same ? maybe this is
> (currently) expected behavior ?
Currently it is like that with the common MMC framework. Same behavior with
gen_atmel_mci.
I'd think its normal that you have to "init" such a block device first, isn't
it the same with USB?
Otherwise you'd have to implement automated init on first block read, and
detection of removal and insertion of a new device to re-read the info.
Season's Greetings,
Reinhard
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 0/4] generic mmc_spi driver
2010-12-24 19:06 ` Reinhard Meyer
@ 2010-12-24 19:45 ` Mike Frysinger
2010-12-24 23:21 ` Thomas Chou
0 siblings, 1 reply; 22+ messages in thread
From: Mike Frysinger @ 2010-12-24 19:45 UTC (permalink / raw)
To: u-boot
On Friday, December 24, 2010 14:06:34 Reinhard Meyer wrote:
> Dear Mike Frysinger,
> > this seems to work much nicer for me. only odd thing is that 'fatls'
> > does not work if i dont 'mmcinfo' first. do you see the same ? maybe
> > this is (currently) expected behavior ?
>
> Currently it is like that with the common MMC framework. Same behavior with
> gen_atmel_mci.
>
> I'd think its normal that you have to "init" such a block device first,
> isn't it the same with USB?
>
> Otherwise you'd have to implement automated init on first block read, and
> detection of removal and insertion of a new device to re-read the info.
my gripe is that it's called "mmcinfo" and not "mmc init". if it were the
latter, i wouldnt be surprised at all. but it seems odd that i have to "query
the device and print its extended info" rather than "initialize the mmc card".
perhaps i'm just whining semantics though.
if this is currently the standard/expected behavior for the generic mmc
framework, then that's OK from the mmc_spi perspective. i'll merge this into
the Blackfin tree and let our testers validate it with our regression tests.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101224/5b295a89/attachment.pgp
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 4/4 v10] mmc: add generic mmc spi driver
2010-12-24 7:16 ` [U-Boot] [PATCH 4/4] mmc: add generic mmc spi driver Thomas Chou
@ 2010-12-24 23:12 ` Thomas Chou
0 siblings, 0 replies; 22+ messages in thread
From: Thomas Chou @ 2010-12-24 23:12 UTC (permalink / raw)
To: u-boot
This patch supports mmc/sd card with spi interface. It is based on
the generic mmc framework. It works with SDHC and supports multi
blocks read/write.
The crc checksum on data packet is enabled with the def,
There is a subcomamnd "mmc_spi" to setup spi bus and cs at run time.
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
v10 set speed to 400KHz for deactived 144 clock, 18 bytes, initialization.
common/Makefile | 1 +
common/cmd_mmc_spi.c | 88 +++++++++++++++
drivers/mmc/Makefile | 1 +
drivers/mmc/mmc.c | 93 +++++++++++++----
drivers/mmc/mmc_spi.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++++
include/mmc.h | 5 +
6 files changed, 448 insertions(+), 20 deletions(-)
create mode 100644 common/cmd_mmc_spi.c
create mode 100644 drivers/mmc/mmc_spi.c
diff --git a/common/Makefile b/common/Makefile
index abea91c..381ac38 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -117,6 +117,7 @@ COBJS-$(CONFIG_CMD_MII) += miiphyutil.o
COBJS-$(CONFIG_CMD_MII) += cmd_mii.o
COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o
COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o
+COBJS-$(CONFIG_CMD_MMC_SPI) += cmd_mmc_spi.o
COBJS-$(CONFIG_MP) += cmd_mp.o
COBJS-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o
COBJS-$(CONFIG_CMD_NAND) += cmd_nand.o
diff --git a/common/cmd_mmc_spi.c b/common/cmd_mmc_spi.c
new file mode 100644
index 0000000..63fe313
--- /dev/null
+++ b/common/cmd_mmc_spi.c
@@ -0,0 +1,88 @@
+/*
+ * Command for mmc_spi setup.
+ *
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <spi.h>
+
+#ifndef CONFIG_MMC_SPI_BUS
+# define CONFIG_MMC_SPI_BUS 0
+#endif
+#ifndef CONFIG_MMC_SPI_CS
+# define CONFIG_MMC_SPI_CS 1
+#endif
+/* in SPI mode, MMC speed limit is 20MHz, while SD speed limit is 25MHz */
+#ifndef CONFIG_MMC_SPI_SPEED
+# define CONFIG_MMC_SPI_SPEED 25000000
+#endif
+/* MMC and SD specs only seem to care that sampling is on the
+ * rising edge ... meaning SPI modes 0 or 3. So either SPI mode
+ * should be legit. We'll use mode 0 since the steady state is 0,
+ * which is appropriate for hotplugging, unless the platform data
+ * specify mode 3 (if hardware is not compatible to mode 0).
+ */
+#ifndef CONFIG_MMC_SPI_MODE
+# define CONFIG_MMC_SPI_MODE SPI_MODE_0
+#endif
+
+static int do_mmc_spi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint bus = CONFIG_MMC_SPI_BUS;
+ uint cs = CONFIG_MMC_SPI_CS;
+ uint speed = CONFIG_MMC_SPI_SPEED;
+ uint mode = CONFIG_MMC_SPI_MODE;
+ char *endp;
+ struct mmc *mmc;
+
+ if (argc < 2)
+ goto usage;
+
+ cs = simple_strtoul(argv[1], &endp, 0);
+ if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
+ goto usage;
+ if (*endp == ':') {
+ if (endp[1] == 0)
+ goto usage;
+ bus = cs;
+ cs = simple_strtoul(endp + 1, &endp, 0);
+ if (*endp != 0)
+ goto usage;
+ }
+ if (argc >= 3) {
+ speed = simple_strtoul(argv[2], &endp, 0);
+ if (*argv[2] == 0 || *endp != 0)
+ goto usage;
+ }
+ if (argc >= 4) {
+ mode = simple_strtoul(argv[3], &endp, 16);
+ if (*argv[3] == 0 || *endp != 0)
+ goto usage;
+ }
+ if (!spi_cs_is_valid(bus, cs)) {
+ printf("Invalid SPI bus %u cs %u\n", bus, cs);
+ return 1;
+ }
+
+ mmc = mmc_spi_init(bus, cs, speed, mode);
+ if (!mmc) {
+ printf("Failed to create MMC Device\n");
+ return 1;
+ }
+ printf("%s: %d at %u:%u hz %u mode %u\n", mmc->name, mmc->block_dev.dev,
+ bus, cs, speed, mode);
+ return 0;
+
+usage:
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+U_BOOT_CMD(
+ mmc_spi, 4, 0, do_mmc_spi,
+ "mmc_spi setup",
+ "[bus:]cs [hz] [mode] - setup mmc_spi device"
+);
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 68afd30..599105f 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -30,6 +30,7 @@ COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
+COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o
COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6805b33..7218a36 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -112,7 +112,10 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
return 0;
}
- if (blkcnt > 1) {
+ /* SPI multiblock writes terminate using a special
+ * token, not a STOP_TRANSMISSION request.
+ */
+ if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
@@ -280,7 +283,8 @@ sd_send_op_cond(struct mmc *mmc)
* how to manage low voltages SD card is not yet
* specified.
*/
- cmd.cmdarg = mmc->voltages & 0xff8000;
+ cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
+ (mmc->voltages & 0xff8000);
if (mmc->version == SD_VERSION_2)
cmd.cmdarg |= OCR_HCS;
@@ -299,6 +303,18 @@ sd_send_op_cond(struct mmc *mmc)
if (mmc->version != SD_VERSION_2)
mmc->version = SD_VERSION_1_0;
+ if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
+ cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
+ cmd.resp_type = MMC_RSP_R3;
+ cmd.cmdarg = 0;
+ cmd.flags = 0;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+ }
+
mmc->ocr = cmd.response[0];
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
@@ -319,7 +335,8 @@ int mmc_send_op_cond(struct mmc *mmc)
do {
cmd.cmdidx = MMC_CMD_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = OCR_HCS | mmc->voltages;
+ cmd.cmdarg = OCR_HCS | (mmc_host_is_spi(mmc) ? 0 :
+ mmc->voltages);
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
@@ -333,6 +350,18 @@ int mmc_send_op_cond(struct mmc *mmc)
if (timeout <= 0)
return UNUSABLE_ERR;
+ if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
+ cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
+ cmd.resp_type = MMC_RSP_R3;
+ cmd.cmdarg = 0;
+ cmd.flags = 0;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+ }
+
mmc->version = MMC_VERSION_UNKNOWN;
mmc->ocr = cmd.response[0];
@@ -388,6 +417,9 @@ int mmc_change_freq(struct mmc *mmc)
mmc->card_caps = 0;
+ if (mmc_host_is_spi(mmc))
+ return 0;
+
/* Only version 4 supports high-speed */
if (mmc->version < MMC_VERSION_4)
return 0;
@@ -461,6 +493,9 @@ int sd_change_freq(struct mmc *mmc)
mmc->card_caps = 0;
+ if (mmc_host_is_spi(mmc))
+ return 0;
+
/* Read the SCR to find out if this card supports higher speeds */
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
@@ -611,8 +646,22 @@ int mmc_startup(struct mmc *mmc)
struct mmc_cmd cmd;
char ext_csd[512];
+#ifdef CONFIG_MMC_SPI_CRC_ON
+ if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
+ cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.cmdarg = 1;
+ cmd.flags = 0;
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+ }
+#endif
+
/* Put the Card in Identify Mode */
- cmd.cmdidx = MMC_CMD_ALL_SEND_CID;
+ cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
+ MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
cmd.resp_type = MMC_RSP_R2;
cmd.cmdarg = 0;
cmd.flags = 0;
@@ -629,18 +678,20 @@ int mmc_startup(struct mmc *mmc)
* For SD cards, get the Relatvie Address.
* This also puts the cards into Standby State
*/
- cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
- cmd.cmdarg = mmc->rca << 16;
- cmd.resp_type = MMC_RSP_R6;
- cmd.flags = 0;
+ if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
+ cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
+ cmd.cmdarg = mmc->rca << 16;
+ cmd.resp_type = MMC_RSP_R6;
+ cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
+ if (err)
+ return err;
- if (IS_SD(mmc))
- mmc->rca = (cmd.response[0] >> 16) & 0xffff;
+ if (IS_SD(mmc))
+ mmc->rca = (cmd.response[0] >> 16) & 0xffff;
+ }
/* Get the Card-Specific Data */
cmd.cmdidx = MMC_CMD_SEND_CSD;
@@ -716,14 +767,16 @@ int mmc_startup(struct mmc *mmc)
mmc->write_bl_len = 512;
/* Select the card, and put it into Transfer Mode */
- cmd.cmdidx = MMC_CMD_SELECT_CARD;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.cmdarg = mmc->rca << 16;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
+ cmd.cmdidx = MMC_CMD_SELECT_CARD;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = mmc->rca << 16;
+ cmd.flags = 0;
+ err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
+ if (err)
+ return err;
+ }
if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
/* check ext_csd version and capacity */
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c
new file mode 100644
index 0000000..dc7574c
--- /dev/null
+++ b/drivers/mmc/mmc_spi.c
@@ -0,0 +1,280 @@
+/*
+ * generic mmc spi driver
+ *
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Licensed under the GPL-2 or later.
+ */
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+#include <spi.h>
+#include <crc.h>
+#include <linux/crc7.h>
+#include <linux/byteorder/swab.h>
+
+/* MMC/SD in SPI mode reports R1 status always */
+#define R1_SPI_IDLE (1 << 0)
+#define R1_SPI_ERASE_RESET (1 << 1)
+#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
+#define R1_SPI_COM_CRC (1 << 3)
+#define R1_SPI_ERASE_SEQ (1 << 4)
+#define R1_SPI_ADDRESS (1 << 5)
+#define R1_SPI_PARAMETER (1 << 6)
+/* R1 bit 7 is always zero, reuse this bit for error */
+#define R1_SPI_ERROR (1 << 7)
+
+/* Response tokens used to ack each block written: */
+#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f)
+#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1)
+#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1)
+#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1)
+
+/* Read and write blocks start with these tokens and end with crc;
+ * on error, read tokens act like a subset of R2_SPI_* values.
+ */
+#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */
+#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */
+#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */
+
+/* MMC SPI commands start with a start bit "0" and a transmit bit "1" */
+#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f))
+
+/* bus capability */
+#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34)
+#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */
+
+/* timeout value */
+#define CTOUT 8
+#define RTOUT 3000000 /* 1 sec */
+#define WTOUT 3000000 /* 1 sec */
+
+static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg)
+{
+ struct spi_slave *spi = mmc->priv;
+ u8 cmdo[7];
+ u8 r1;
+ int i;
+ cmdo[0] = 0xff;
+ cmdo[1] = MMC_SPI_CMD(cmdidx);
+ cmdo[2] = cmdarg >> 24;
+ cmdo[3] = cmdarg >> 16;
+ cmdo[4] = cmdarg >> 8;
+ cmdo[5] = cmdarg;
+ cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
+ spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0);
+ for (i = 0; i < CTOUT; i++) {
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if (i && (r1 & 0x80) == 0) /* r1 response */
+ break;
+ }
+ debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1);
+ return r1;
+}
+
+static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf,
+ u32 bcnt, u32 bsize)
+{
+ struct spi_slave *spi = mmc->priv;
+ u8 *buf = xbuf;
+ u8 r1;
+ u16 crc;
+ int i;
+ while (bcnt--) {
+ for (i = 0; i < RTOUT; i++) {
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if (r1 != 0xff) /* data token */
+ break;
+ }
+ debug("%s:tok%d %x\n", __func__, i, r1);
+ if (r1 == SPI_TOKEN_SINGLE) {
+ spi_xfer(spi, bsize * 8, NULL, buf, 0);
+ spi_xfer(spi, 2 * 8, NULL, &crc, 0);
+#ifdef CONFIG_MMC_SPI_CRC_ON
+ if (swab16(cyg_crc16(buf, bsize)) != crc) {
+ debug("%s: CRC error\n", mmc->name);
+ r1 = R1_SPI_COM_CRC;
+ break;
+ }
+#endif
+ r1 = 0;
+ } else {
+ r1 = R1_SPI_ERROR;
+ break;
+ }
+ buf += bsize;
+ }
+ return r1;
+}
+
+static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf,
+ u32 bcnt, u32 bsize, int multi)
+{
+ struct spi_slave *spi = mmc->priv;
+ const u8 *buf = xbuf;
+ u8 r1;
+ u16 crc;
+ u8 tok[2];
+ int i;
+ tok[0] = 0xff;
+ tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
+ while (bcnt--) {
+#ifdef CONFIG_MMC_SPI_CRC_ON
+ crc = swab16(cyg_crc16((u8 *)buf, bsize));
+#endif
+ spi_xfer(spi, 2 * 8, tok, NULL, 0);
+ spi_xfer(spi, bsize * 8, buf, NULL, 0);
+ spi_xfer(spi, 2 * 8, &crc, NULL, 0);
+ for (i = 0; i < CTOUT; i++) {
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if ((r1 & 0x10) == 0) /* response token */
+ break;
+ }
+ debug("%s:tok%d %x\n", __func__, i, r1);
+ if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
+ for (i = 0; i < WTOUT; i++) { /* wait busy */
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if (i && r1 == 0xff) {
+ r1 = 0;
+ break;
+ }
+ }
+ if (i == WTOUT) {
+ debug("%s:wtout %x\n", __func__, r1);
+ r1 = R1_SPI_ERROR;
+ break;
+ }
+ } else {
+ debug("%s: err %x\n", __func__, r1);
+ r1 = R1_SPI_COM_CRC;
+ break;
+ }
+ buf += bsize;
+ }
+ if (multi && bcnt == -1) { /* stop multi write */
+ tok[1] = SPI_TOKEN_STOP_TRAN;
+ spi_xfer(spi, 2 * 8, tok, NULL, 0);
+ for (i = 0; i < WTOUT; i++) { /* wait busy */
+ spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+ if (i && r1 == 0xff) {
+ r1 = 0;
+ break;
+ }
+ }
+ if (i == WTOUT) {
+ debug("%s:wstop %x\n", __func__, r1);
+ r1 = R1_SPI_ERROR;
+ }
+ }
+ return r1;
+}
+
+static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ struct spi_slave *spi = mmc->priv;
+ u8 r1;
+ int i;
+ int ret = 0;
+ debug("%s:cmd%d %x %x %x\n", __func__,
+ cmd->cmdidx, cmd->resp_type, cmd->cmdarg, cmd->flags);
+ spi_claim_bus(spi);
+ spi_cs_activate(spi);
+ r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg);
+ if (r1 == 0xff) { /* no response */
+ ret = NO_CARD_ERR;
+ goto done;
+ } else if (r1 & R1_SPI_COM_CRC) {
+ ret = COMM_ERR;
+ goto done;
+ } else if (r1 & ~R1_SPI_IDLE) { /* other errors */
+ ret = TIMEOUT;
+ goto done;
+ } else if (cmd->resp_type == MMC_RSP_R2) {
+ r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16);
+ for (i = 0; i < 4; i++)
+ cmd->response[i] = swab32(cmd->response[i]);
+ debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1],
+ cmd->response[2], cmd->response[3]);
+ } else if (!data) {
+ switch (cmd->cmdidx) {
+ case SD_CMD_APP_SEND_OP_COND:
+ case MMC_CMD_SEND_OP_COND:
+ cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
+ break;
+ case SD_CMD_SEND_IF_COND:
+ case MMC_CMD_SPI_READ_OCR:
+ spi_xfer(spi, 4 * 8, NULL, cmd->response, 0);
+ cmd->response[0] = swab32(cmd->response[0]);
+ debug("r32 %x\n", cmd->response[0]);
+ break;
+ }
+ } else {
+ debug("%s:data %x %x %x\n", __func__,
+ data->flags, data->blocks, data->blocksize);
+ if (data->flags == MMC_DATA_READ)
+ r1 = mmc_spi_readdata(mmc, data->dest,
+ data->blocks, data->blocksize);
+ else if (data->flags == MMC_DATA_WRITE)
+ r1 = mmc_spi_writedata(mmc, data->src,
+ data->blocks, data->blocksize,
+ (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK));
+ if (r1 & R1_SPI_COM_CRC)
+ ret = COMM_ERR;
+ else if (r1) /* other errors */
+ ret = TIMEOUT;
+ }
+done:
+ spi_cs_deactivate(spi);
+ spi_release_bus(spi);
+ return ret;
+}
+
+static void mmc_spi_set_ios(struct mmc *mmc)
+{
+ struct spi_slave *spi = mmc->priv;
+ debug("%s: clock %u\n", __func__, mmc->clock);
+ if (mmc->clock)
+ spi_set_speed(spi, mmc->clock);
+}
+
+static int mmc_spi_init_p(struct mmc *mmc)
+{
+ struct spi_slave *spi = mmc->priv;
+ mmc->clock = 0;
+ spi_set_speed(spi, MMC_SPI_MIN_CLOCK);
+ spi_claim_bus(spi);
+ /* cs deactivated for 100+ clock */
+ spi_xfer(spi, 18 * 8, NULL, NULL, 0);
+ spi_release_bus(spi);
+ return 0;
+}
+
+struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode)
+{
+ struct mmc *mmc;
+
+ mmc = malloc(sizeof(*mmc));
+ if (!mmc)
+ return NULL;
+ memset(mmc, 0, sizeof(*mmc));
+ mmc->priv = spi_setup_slave(bus, cs, speed, mode);
+ if (!mmc->priv) {
+ free(mmc);
+ return NULL;
+ }
+ sprintf(mmc->name, "MMC_SPI");
+ mmc->send_cmd = mmc_spi_request;
+ mmc->set_ios = mmc_spi_set_ios;
+ mmc->init = mmc_spi_init_p;
+ mmc->host_caps = MMC_MODE_SPI;
+
+ mmc->voltages = MMC_SPI_VOLTAGE;
+ mmc->f_max = speed;
+ mmc->f_min = MMC_SPI_MIN_CLOCK;
+ mmc->block_dev.part_type = PART_TYPE_DOS;
+
+ mmc_register(mmc);
+
+ return mmc;
+}
diff --git a/include/mmc.h b/include/mmc.h
index 74c0b1d..0b1e064 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -44,6 +44,7 @@
#define MMC_MODE_HS_52MHz 0x010
#define MMC_MODE_4BIT 0x100
#define MMC_MODE_8BIT 0x200
+#define MMC_MODE_SPI 0x400
#define SD_DATA_4BIT 0x00040000
@@ -75,6 +76,8 @@
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
#define MMC_CMD_APP_CMD 55
+#define MMC_CMD_SPI_READ_OCR 58
+#define MMC_CMD_SPI_CRC_ON_OFF 59
#define SD_CMD_SEND_RELATIVE_ADDR 3
#define SD_CMD_SWITCH_FUNC 6
@@ -288,6 +291,8 @@ int board_mmc_getcd(u8 *cd, struct mmc *mmc);
#ifdef CONFIG_GENERIC_MMC
int atmel_mci_init(void *regs);
+#define mmc_host_is_spi(mmc) ((mmc)->host_caps & MMC_MODE_SPI)
+struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode);
#else
int mmc_legacy_init(int verbose);
#endif
--
1.7.3.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 2/4 v2] spi: add spi_set_speed func
2010-12-24 7:16 ` [U-Boot] [PATCH 2/4] spi: add spi_set_speed func Thomas Chou
2010-12-24 17:09 ` Mike Frysinger
@ 2010-12-24 23:13 ` Thomas Chou
2011-01-18 22:37 ` Wolfgang Denk
1 sibling, 1 reply; 22+ messages in thread
From: Thomas Chou @ 2010-12-24 23:13 UTC (permalink / raw)
To: u-boot
This func helps mmc_spi driver set correct speed for mmc/sd, as
mmc card needs 400KHz clock for spi mode initialization.
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
v2 remove weak func as Mike suggested.
include/spi.h | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/include/spi.h b/include/spi.h
index 320e50e..7887d0f 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -176,6 +176,14 @@ void spi_cs_activate(struct spi_slave *slave);
void spi_cs_deactivate(struct spi_slave *slave);
/*-----------------------------------------------------------------------
+ * Set transfer speed.
+ * This sets a new speed to be applied for next spi_xfer().
+ * slave: The SPI slave
+ * hz: The transfer speed
+ */
+void spi_set_speed(struct spi_slave *slave, uint hz);
+
+/*-----------------------------------------------------------------------
* Write 8 bits, then read 8 bits.
* slave: The SPI slave we're communicating with
* byte: Byte to be written
--
1.7.3.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 0/4] generic mmc_spi driver
2010-12-24 19:45 ` Mike Frysinger
@ 2010-12-24 23:21 ` Thomas Chou
0 siblings, 0 replies; 22+ messages in thread
From: Thomas Chou @ 2010-12-24 23:21 UTC (permalink / raw)
To: u-boot
On 12/25/2010 03:45 AM, Mike Frysinger wrote:
> if this is currently the standard/expected behavior for the generic mmc
> framework, then that's OK from the mmc_spi perspective. i'll merge this into
> the Blackfin tree and let our testers validate it with our regression tests.
> -mike
Yes. It is the current behaviour. I just added an update to run the
initialization clock at 400KHz which should improve compatibility.
Please try out. Thank you very much.
Merry Xmas!
- Thomas
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 1/4] lib: add crc7 from Linux
2010-12-24 7:16 ` [U-Boot] [PATCH 1/4] lib: add crc7 from Linux Thomas Chou
@ 2011-01-10 20:59 ` Wolfgang Denk
2011-01-11 1:38 ` [U-Boot] [PATCH v2] " Thomas Chou
0 siblings, 1 reply; 22+ messages in thread
From: Wolfgang Denk @ 2011-01-10 20:59 UTC (permalink / raw)
To: u-boot
Dear Thomas Chou,
In message <1293174969-18653-2-git-send-email-thomas@wytron.com.tw> you wrote:
> Crc7 is used to compute mmc spi comamnd packet checksum.
s/comamnd/sommand/
> Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
Please fix the typos, and provide proper attribution where this code
is coming from - see
http://www.denx.de/wiki/view/U-Boot/Patches#Attributing_Code_Copyrights_Sign
for details.
Thanks.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Commitment, n.: Commitment can be illustrated by a breakfast
of ham and eggs. The chicken was involved, the pig was committed.
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH v2] lib: add crc7 from Linux
2011-01-10 20:59 ` Wolfgang Denk
@ 2011-01-11 1:38 ` Thomas Chou
2011-01-18 22:38 ` Wolfgang Denk
0 siblings, 1 reply; 22+ messages in thread
From: Thomas Chou @ 2011-01-11 1:38 UTC (permalink / raw)
To: u-boot
Crc7 is used to compute mmc spi command packet checksum.
Copy from linux-2.6 lib/crc7.c include/linux/crc7.h
commit ad241528c4919505afccb022acbab3eeb0db4d80
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
v2 update attribution as Wolfgang suggested.
include/linux/crc7.h | 14 +++++++++++
lib/Makefile | 1 +
lib/crc7.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 77 insertions(+), 0 deletions(-)
create mode 100644 include/linux/crc7.h
create mode 100644 lib/crc7.c
diff --git a/include/linux/crc7.h b/include/linux/crc7.h
new file mode 100644
index 0000000..1786e77
--- /dev/null
+++ b/include/linux/crc7.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_CRC7_H
+#define _LINUX_CRC7_H
+#include <linux/types.h>
+
+extern const u8 crc7_syndrome_table[256];
+
+static inline u8 crc7_byte(u8 crc, u8 data)
+{
+ return crc7_syndrome_table[(crc << 1) ^ data];
+}
+
+extern u8 crc7(u8 crc, const u8 *buffer, size_t len);
+
+#endif
diff --git a/lib/Makefile b/lib/Makefile
index ffdee7d..fcfe351 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -32,6 +32,7 @@ COBJS-$(CONFIG_BZIP2) += bzlib_decompress.o
COBJS-$(CONFIG_BZIP2) += bzlib_randtable.o
COBJS-$(CONFIG_BZIP2) += bzlib_huffman.o
COBJS-$(CONFIG_USB_TTY) += circbuf.o
+COBJS-y += crc7.o
COBJS-y += crc16.o
COBJS-y += crc32.o
COBJS-y += ctype.o
diff --git a/lib/crc7.c b/lib/crc7.c
new file mode 100644
index 0000000..e635c9c
--- /dev/null
+++ b/lib/crc7.c
@@ -0,0 +1,62 @@
+/*
+ * crc7.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/crc7.h>
+
+
+/* Table for CRC-7 (polynomial x^7 + x^3 + 1) */
+const u8 crc7_syndrome_table[256] = {
+ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
+ 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
+ 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
+ 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
+ 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
+ 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
+ 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
+ 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
+ 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
+ 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
+ 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
+ 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
+ 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
+ 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
+ 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
+ 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
+ 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
+ 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
+ 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
+ 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
+ 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
+ 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
+ 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
+ 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
+ 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
+ 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
+ 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
+ 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
+ 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
+ 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
+ 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
+ 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
+};
+
+/**
+ * crc7 - update the CRC7 for the data buffer
+ * @crc: previous CRC7 value
+ * @buffer: data pointer
+ * @len: number of bytes in the buffer
+ * Context: any
+ *
+ * Returns the updated CRC7 value.
+ */
+u8 crc7(u8 crc, const u8 *buffer, size_t len)
+{
+ while (len--)
+ crc = crc7_byte(crc, *buffer++);
+ return crc;
+}
--
1.7.3.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 2/4 v2] spi: add spi_set_speed func
2010-12-24 23:13 ` [U-Boot] [PATCH 2/4 v2] " Thomas Chou
@ 2011-01-18 22:37 ` Wolfgang Denk
2011-01-19 1:34 ` [U-Boot] [PATCH 2/4 v3] " Thomas Chou
0 siblings, 1 reply; 22+ messages in thread
From: Wolfgang Denk @ 2011-01-18 22:37 UTC (permalink / raw)
To: u-boot
Dear Thomas Chou,
In message <1293232433-2985-1-git-send-email-thomas@wytron.com.tw> you wrote:
> This func helps mmc_spi driver set correct speed for mmc/sd, as
> mmc card needs 400KHz clock for spi mode initialization.
>
> Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
> ---
> v2 remove weak func as Mike suggested.
>
> include/spi.h | 8 ++++++++
> 1 files changed, 8 insertions(+), 0 deletions(-)
>
> diff --git a/include/spi.h b/include/spi.h
> index 320e50e..7887d0f 100644
> --- a/include/spi.h
> +++ b/include/spi.h
> @@ -176,6 +176,14 @@ void spi_cs_activate(struct spi_slave *slave);
> void spi_cs_deactivate(struct spi_slave *slave);
>
> /*-----------------------------------------------------------------------
> + * Set transfer speed.
> + * This sets a new speed to be applied for next spi_xfer().
> + * slave: The SPI slave
> + * hz: The transfer speed
> + */
Incorrect multiline comment style.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Wenn Du ein' weise Antwort verlangst, Mu?t Du vern?nftig fragen.
-- Goethe, Invektiven
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH v2] lib: add crc7 from Linux
2011-01-11 1:38 ` [U-Boot] [PATCH v2] " Thomas Chou
@ 2011-01-18 22:38 ` Wolfgang Denk
0 siblings, 0 replies; 22+ messages in thread
From: Wolfgang Denk @ 2011-01-18 22:38 UTC (permalink / raw)
To: u-boot
Dear Thomas Chou,
In message <1294709900-2764-1-git-send-email-thomas@wytron.com.tw> you wrote:
> Crc7 is used to compute mmc spi command packet checksum.
>
> Copy from linux-2.6 lib/crc7.c include/linux/crc7.h
> commit ad241528c4919505afccb022acbab3eeb0db4d80
>
> Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
> ---
> v2 update attribution as Wolfgang suggested.
>
> include/linux/crc7.h | 14 +++++++++++
> lib/Makefile | 1 +
> lib/crc7.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 77 insertions(+), 0 deletions(-)
> create mode 100644 include/linux/crc7.h
> create mode 100644 lib/crc7.c
Applied, thanks.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
A witty saying proves nothing, but saying something pointless gets
people's attention.
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 2/4 v3] spi: add spi_set_speed func
2011-01-18 22:37 ` Wolfgang Denk
@ 2011-01-19 1:34 ` Thomas Chou
0 siblings, 0 replies; 22+ messages in thread
From: Thomas Chou @ 2011-01-19 1:34 UTC (permalink / raw)
To: u-boot
This func helps mmc_spi driver set correct speed for mmc/sd, as
mmc card needs 400KHz clock for spi mode initialization.
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
v2 remove weak func as Mike suggested.
v3 comment style fix as Wolfgang suggested.
include/spi.h | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/include/spi.h b/include/spi.h
index 320e50e..e364d2d 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -175,6 +175,14 @@ void spi_cs_activate(struct spi_slave *slave);
*/
void spi_cs_deactivate(struct spi_slave *slave);
+/*
+ * Set transfer speed.
+ * This sets a new speed to be applied for next spi_xfer().
+ * slave: The SPI slave
+ * hz: The transfer speed
+ */
+void spi_set_speed(struct spi_slave *slave, uint hz);
+
/*-----------------------------------------------------------------------
* Write 8 bits, then read 8 bits.
* slave: The SPI slave we're communicating with
--
1.7.3.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 0/4] generic mmc_spi driver
2010-12-24 7:16 [U-Boot] [PATCH 0/4] generic mmc_spi driver Thomas Chou
` (4 preceding siblings ...)
2010-12-24 17:24 ` [U-Boot] [PATCH 0/4] generic mmc_spi driver Mike Frysinger
@ 2011-04-12 6:58 ` Mike Frysinger
2011-04-13 10:17 ` Andy Fleming
5 siblings, 1 reply; 22+ messages in thread
From: Mike Frysinger @ 2011-04-12 6:58 UTC (permalink / raw)
To: u-boot
On Friday, December 24, 2010 02:16:05 Thomas Chou wrote:
> This is the v9 update of the mmc_spi driver. Please enable DEBUG on the top
> of mmc_spi.c and help me perform the tests.
>
> A new spi_set_speed() is added to meet the 400KHz clock requirement during
> mmc card initialization. An example update to bfin_spi is included. The
> altera_spi core does not support speed change, so I am going to post a new
> opencore ip for this.
>
> The driver now claims and releases the spi bus for each mmc command, as
> Mike suggested.
>
> Thomas Chou (4):
> lib: add crc7 from Linux
> spi: add spi_set_speed func
> bfin_spi: add spi_set_speed
> mmc: add generic mmc spi driver
Andy: i think we've hit a fairly stable point. could you merge this now ?
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20110412/dd22131e/attachment.pgp
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 0/4] generic mmc_spi driver
2011-04-12 6:58 ` Mike Frysinger
@ 2011-04-13 10:17 ` Andy Fleming
2011-04-13 19:46 ` Mike Frysinger
2011-04-18 7:00 ` [U-Boot] [PATCH] mmc_spi: add mmc_init call Thomas Chou
0 siblings, 2 replies; 22+ messages in thread
From: Andy Fleming @ 2011-04-13 10:17 UTC (permalink / raw)
To: u-boot
On Tue, Apr 12, 2011 at 1:58 AM, Mike Frysinger <vapier@gentoo.org> wrote:
> On Friday, December 24, 2010 02:16:05 Thomas Chou wrote:
>> This is the v9 update of the mmc_spi driver. Please enable DEBUG on the top
>> of mmc_spi.c and help me perform the tests.
>>
>> A new spi_set_speed() is added to meet the 400KHz clock requirement during
>> mmc card initialization. An example update to bfin_spi is included. The
>> altera_spi core does not support speed change, so I am going to post a new
>> opencore ip for this.
>>
>> The driver now claims and releases the spi bus for each mmc command, as
>> Mike suggested.
>>
>> Thomas Chou (4):
>> ? lib: add crc7 from Linux
>> ? spi: add spi_set_speed func
>> ? bfin_spi: add spi_set_speed
>> ? mmc: add generic mmc spi driver
>
> Andy: i think we've hit a fairly stable point. ?could you merge this now ?
I'm going to merge this, but I'll note that the reason you had to run
mmcinfo before this will work is because this code never invoks
mmc_init(). If you look at the mmc command in common/cmd_mmc.c, and
see how the various sub-commands operate (under GENERIC_MMC), all of
them call mmc_init() before running the command. It's suboptimal in
terms of performance, but has the advantage of being robust and
actually detecting if you put a card in, or took one out. If someone
could find the appropriate places to call mmc_init(mmc), I'll be happy
to also merge in the follow-up patch.
Also, I'm assuming, at the moment, that this supersedes the legacy
mmc_spi patch you submitted earlier? If not, I'll put that in, now,
too.
Andy
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH 0/4] generic mmc_spi driver
2011-04-13 10:17 ` Andy Fleming
@ 2011-04-13 19:46 ` Mike Frysinger
2011-04-18 7:00 ` [U-Boot] [PATCH] mmc_spi: add mmc_init call Thomas Chou
1 sibling, 0 replies; 22+ messages in thread
From: Mike Frysinger @ 2011-04-13 19:46 UTC (permalink / raw)
To: u-boot
On Wednesday, April 13, 2011 06:17:43 Andy Fleming wrote:
> On Tue, Apr 12, 2011 at 1:58 AM, Mike Frysinger <vapier@gentoo.org> wrote:
> > On Friday, December 24, 2010 02:16:05 Thomas Chou wrote:
> >> This is the v9 update of the mmc_spi driver. Please enable DEBUG on the
> >> top of mmc_spi.c and help me perform the tests.
> >>
> >> A new spi_set_speed() is added to meet the 400KHz clock requirement
> >> during mmc card initialization. An example update to bfin_spi is
> >> included. The altera_spi core does not support speed change, so I am
> >> going to post a new opencore ip for this.
> >>
> >> The driver now claims and releases the spi bus for each mmc command, as
> >> Mike suggested.
> >>
> >> Thomas Chou (4):
> >> lib: add crc7 from Linux
> >> spi: add spi_set_speed func
> >> bfin_spi: add spi_set_speed
> >> mmc: add generic mmc spi driver
> >
> > Andy: i think we've hit a fairly stable point. could you merge this now
> > ?
>
> I'm going to merge this, but I'll note that the reason you had to run
> mmcinfo before this will work is because this code never invoks
> mmc_init(). If you look at the mmc command in common/cmd_mmc.c, and
> see how the various sub-commands operate (under GENERIC_MMC), all of
> them call mmc_init() before running the command. It's suboptimal in
> terms of performance, but has the advantage of being robust and
> actually detecting if you put a card in, or took one out. If someone
> could find the appropriate places to call mmc_init(mmc), I'll be happy
> to also merge in the follow-up patch.
i hope Thomas can do that :)
> Also, I'm assuming, at the moment, that this supersedes the legacy
> mmc_spi patch you submitted earlier? If not, I'll put that in, now,
> too.
correct, the legacy mmc_spi code is hopefully no longer needed
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20110413/ea65099d/attachment.pgp
^ permalink raw reply [flat|nested] 22+ messages in thread
* [U-Boot] [PATCH] mmc_spi: add mmc_init call
2011-04-13 10:17 ` Andy Fleming
2011-04-13 19:46 ` Mike Frysinger
@ 2011-04-18 7:00 ` Thomas Chou
1 sibling, 0 replies; 22+ messages in thread
From: Thomas Chou @ 2011-04-18 7:00 UTC (permalink / raw)
To: u-boot
As Andy Fleming suggested, we can call mmc_init() in mmc_spi command.
So that we don't need to run mmcinfo command next.
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
for u-boot.
common/cmd_mmc_spi.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/common/cmd_mmc_spi.c b/common/cmd_mmc_spi.c
index 63fe313..cfd0fb1 100644
--- a/common/cmd_mmc_spi.c
+++ b/common/cmd_mmc_spi.c
@@ -74,6 +74,7 @@ static int do_mmc_spi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}
printf("%s: %d at %u:%u hz %u mode %u\n", mmc->name, mmc->block_dev.dev,
bus, cs, speed, mode);
+ mmc_init(mmc);
return 0;
usage:
--
1.7.1.86.g0e460
^ permalink raw reply related [flat|nested] 22+ messages in thread
end of thread, other threads:[~2011-04-18 7:00 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-12-24 7:16 [U-Boot] [PATCH 0/4] generic mmc_spi driver Thomas Chou
2010-12-24 7:16 ` [U-Boot] [PATCH 1/4] lib: add crc7 from Linux Thomas Chou
2011-01-10 20:59 ` Wolfgang Denk
2011-01-11 1:38 ` [U-Boot] [PATCH v2] " Thomas Chou
2011-01-18 22:38 ` Wolfgang Denk
2010-12-24 7:16 ` [U-Boot] [PATCH 2/4] spi: add spi_set_speed func Thomas Chou
2010-12-24 17:09 ` Mike Frysinger
2010-12-24 23:13 ` [U-Boot] [PATCH 2/4 v2] " Thomas Chou
2011-01-18 22:37 ` Wolfgang Denk
2011-01-19 1:34 ` [U-Boot] [PATCH 2/4 v3] " Thomas Chou
2010-12-24 7:16 ` [U-Boot] [PATCH 3/4] bfin_spi: add spi_set_speed Thomas Chou
2010-12-24 17:25 ` Mike Frysinger
2010-12-24 7:16 ` [U-Boot] [PATCH 4/4] mmc: add generic mmc spi driver Thomas Chou
2010-12-24 23:12 ` [U-Boot] [PATCH 4/4 v10] " Thomas Chou
2010-12-24 17:24 ` [U-Boot] [PATCH 0/4] generic mmc_spi driver Mike Frysinger
2010-12-24 19:06 ` Reinhard Meyer
2010-12-24 19:45 ` Mike Frysinger
2010-12-24 23:21 ` Thomas Chou
2011-04-12 6:58 ` Mike Frysinger
2011-04-13 10:17 ` Andy Fleming
2011-04-13 19:46 ` Mike Frysinger
2011-04-18 7:00 ` [U-Boot] [PATCH] mmc_spi: add mmc_init call Thomas Chou
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.