All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.