Skip to contentSkip to conversation

MMC: Add support MMCIF for SuperH

PATCH Applied Yusuke Goda 2 participants 3 messages Apr 27, 2010 – Apr 28, 2010

Subsystems (2)

v1 of 2 Applied Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 MMC: Add support MMCIF for SuperH

MMCIF is MMC Host Interface in SuperH.

---
 drivers/mmc/host/Kconfig     |    8 +
 drivers/mmc/host/Makefile    |    1 +
 drivers/mmc/host/sh_mmcif.c  |  964 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/sh_mmcif.h |   39 ++
 4 files changed, 1012 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mmc/host/sh_mmcif.c
 create mode 100644 include/linux/mmc/sh_mmcif.h
drivers/mmc/host/Kconfig +8 -0
index 2e13b94..aeecbc9 100644
@@ -412,3 +412,11 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
 	depends on SDH_BFIN
 	help
 	  If you say yes here SD-Cards may work on the EZkit.
+
+config MMC_SH_MMCIF
+	tristate "SuperH Internal MMCIF support"
+	depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE)
+	help
+	  This selects the MMC Host Interface controler (MMCIF).
+
+	  This driver supports MMCIF in sh7724/sh7757/sh7372.
drivers/mmc/host/Makefile +1 -0
index f480397..2447b66 100644
@@ -34,6 +34,7 @@ obj-$(CONFIG_MMC_TMIO)		+= tmio_mmc.o
 obj-$(CONFIG_MMC_CB710)	+= cb710-mmc.o
 obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
+obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o
 
 obj-$(CONFIG_MMC_SDHCI_OF)	+= sdhci-of.o
 sdhci-of-y				:= sdhci-of-core.o
drivers/mmc/host/sh_mmcif.c new file +963 -0

963 lines not on this page · raw message

include/linux/mmc/sh_mmcif.h new file +39 -0
new file mode 100644
index 0000000..aafe832
@@ -0,0 +1,39 @@
+/*
+ * include/linux/mmc/sh_mmcif.h
+ *
+ * platform data for eMMC driver
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ */
+
+#ifndef __SH_MMCIF_H__
+#define __SH_MMCIF_H__
+
+/*
+ * MMCIF : CE_CLK_CTRL [19:16]
+ * 1000 : Peripheral clock / 512
+ * 0111 : Peripheral clock / 256
+ * 0110 : Peripheral clock / 128
+ * 0101 : Peripheral clock / 64
+ * 0100 : Peripheral clock / 32
+ * 0011 : Peripheral clock / 16
+ * 0010 : Peripheral clock / 8
+ * 0001 : Peripheral clock / 4
+ * 0000 : Peripheral clock / 2
+ * 1111 : Peripheral clock (sup_pclk set '1')
+ */
+
+struct sh_mmcif_plat_data {
+	void (*set_pwr)(struct platform_device *pdev, int state);
+	void (*down_pwr)(struct platform_device *pdev);
+	u8	sup_pclk;	/* 1 :SH7757, 0: SH7724/SH7372 */
+	unsigned long caps;
+	u32	ocr;
+};
+
+#endif /* __SH_MMCIF_H__ */
Signature · 1 line
1.7.0
#1 lore raw
Quoted 10 lines · On Tue, 27 Apr 2010 19:15:02 +0900 Yusuke Goda <[email protected]>…

MMCIF is MMC Host Interface in SuperH.

...

drivers/mmc/host/sh_mmcif.c new file +5 -0
+static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
+{
+	int i;
+	struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+

drivers/mmc/host/sh_mmcif.c line 248

Quoted 10 lines
drivers/mmc/host/sh_mmcif.c new file +10 -0
+	sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
+	sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR);
+
+	if (!clk)
+		return;
+	if (p->sup_pclk && clk = host->clk) {
+			sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
+	} else {
+		for (i = 1; (unsigned int)host->clk / (1 << i) >= clk; i++)
+			;

I suspect this could be clarified. Perhaps

	i = ilog2(__roundup_pow_of_two(host->clk));

If that's wrong then include/linux/log2.h has various tools which can surely be used. If they're not appropriate then please feel free to propose additions.

Quoted 31 lines
drivers/mmc/host/sh_mmcif.c new file +28 -0
+		sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, (i - 1) << 16);
+	}
+	sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
+}
+
 
...
 
+static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
+{
+	u32 state1, state2;
+	int ret, timeout = 10000000;
+
+	host->sd_error = 0;
+	host->wait_int = 0;
+
+	state1 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS1);
+	state2 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS2);
+	pr_debug("%s: ERR HOST_STS1 = %08x\n", \
+			DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS1));
+	pr_debug("%s: ERR HOST_STS2 = %08x\n", \
+			DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS2));
+
+	if (state1 & STS1_CMDSEQ) {
+		pr_debug("%s: Forced end of command sequence\n", DRIVER_NAME);
+		sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
+		sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
+		while (1) {
+			timeout--;
+			if (timeout < 0) {
+				pr_err(DRIVER_NAME": Forceed end of " \

drivers/mmc/host/sh_mmcif.c line 300

Quoted 10 lines
drivers/mmc/host/sh_mmcif.c new file +10 -0
+					"command sequence timeout err\n");
+				return -EILSEQ;
+			}
+			if (!(sh_mmcif_readl(host, MMCIF_CE_HOST_STS1)
+								& STS1_CMDSEQ))
+				break;
+			mdelay(1);
+		}
+		sh_mmcif_sync_reset(host);
+		return -EILSEQ;

Good heavens, what is EILSEQ?

<googles a bit>

"An illegal multibyte sequence was found in the input. This
usually means that you have the wrong charactor encoding, for instance the MicrosoftCorporation version of latin-1 (aka iso_8859_1(7)) (which has it's own stuff like "smart quotes" in the reserved bytes) instead of the real latin (or perhaps utf8(7))."

Why on earth are driver writers using this in the kernel??? Imagine the confusion which ensues when this error code propagates all the way back to some poor user's console. They'll be scrabbling around with language encodings not even suspecting that their hardware is busted.

People do this *a lot*. They go grubbing through errno.h and grab something which looks vaguely appropriate. But it's wrong.

If your hardware is busted then return -EIO and emit a printk to tell the operator what broke.

Quoted 13 lines
drivers/mmc/host/sh_mmcif.c new file +10 -0
+	}
+
+	if (state2 & STS2_CRC_ERR)
+		ret = -EILSEQ;
+	else if (state2 & STS2_TIMEOUT_ERR)
+		ret = -ETIMEDOUT;
+	else
+		ret = -EILSEQ;
+	return ret;
+}
 
...
#2 lore raw

Hi Andrew

Thanks so much for your help.

Quoted 25 lines · Andrew Morton
Quoted 9 lines · On Tue, 27 Apr 2010 19:15:02 +0900 Yusuke Goda <[email protected]>…

MMCIF is MMC Host Interface in SuperH.

...

drivers/mmc/host/sh_mmcif.c new file +5 -0
+static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
+{
+	int i;
+	struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+

drivers/mmc/host/sh_mmcif.c line 248

Quoted 10 lines
drivers/mmc/host/sh_mmcif.c new file +10 -0
+	sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
+	sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR);
+
+	if (!clk)
+		return;
+	if (p->sup_pclk && clk == host->clk) {
+			sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
+	} else {
+		for (i = 1; (unsigned int)host->clk / (1 << i) >= clk; i++)
+			;

I suspect this could be clarified. Perhaps

Quoted 5 lines
	i = ilog2(__roundup_pow_of_two(host->clk));

If that's wrong then include/linux/log2.h has various tools which can surely be used. If they're not appropriate then please feel free to propose additions.

OK.
I correct it.

Quoted 65 lines
Quoted 32 lines
drivers/mmc/host/sh_mmcif.c new file +28 -0
+		sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, (i - 1) << 16);
+	}
+	sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
+}
+
 
...
 
+static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
+{
+	u32 state1, state2;
+	int ret, timeout = 10000000;
+
+	host->sd_error = 0;
+	host->wait_int = 0;
+
+	state1 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS1);
+	state2 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS2);
+	pr_debug("%s: ERR HOST_STS1 = %08x\n", \
+			DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS1));
+	pr_debug("%s: ERR HOST_STS2 = %08x\n", \
+			DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS2));
+
+	if (state1 & STS1_CMDSEQ) {
+		pr_debug("%s: Forced end of command sequence\n", DRIVER_NAME);
+		sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
+		sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
+		while (1) {
+			timeout--;
+			if (timeout < 0) {
+				pr_err(DRIVER_NAME": Forceed end of " \

drivers/mmc/host/sh_mmcif.c line 300

Quoted 10 lines
drivers/mmc/host/sh_mmcif.c new file +10 -0
+					"command sequence timeout err\n");
+				return -EILSEQ;
+			}
+			if (!(sh_mmcif_readl(host, MMCIF_CE_HOST_STS1)
+								& STS1_CMDSEQ))
+				break;
+			mdelay(1);
+		}
+		sh_mmcif_sync_reset(host);
+		return -EILSEQ;

Good heavens, what is EILSEQ?

<googles a bit>

"An illegal multibyte sequence was found in the input. This
usually means that you have the wrong charactor encoding, for instance the MicrosoftCorporation version of latin-1 (aka iso_8859_1(7)) (which has it's own stuff like "smart quotes" in the reserved bytes) instead of the real latin (or perhaps utf8(7))."

Why on earth are driver writers using this in the kernel??? Imagine the confusion which ensues when this error code propagates all the way back to some poor user's console. They'll be scrabbling around with language encodings not even suspecting that their hardware is busted.

People do this *a lot*. They go grubbing through errno.h and grab something which looks vaguely appropriate. But it's wrong.

If your hardware is busted then return -EIO and emit a printk to tell the operator what broke.

Quoted 10 lines

drivers/mmc/host/sh_mmcif.c line 310

Quoted 10 lines
drivers/mmc/host/sh_mmcif.c new file +10 -0
+	}
+
+	if (state2 & STS2_CRC_ERR)
+		ret = -EILSEQ;
+	else if (state2 & STS2_TIMEOUT_ERR)
+		ret = -ETIMEDOUT;
+	else
+		ret = -EILSEQ;
+	return ret;
+}

Thank you.
I think that EIO is appropriate.

I revise it and send a patch.

Thanks,
Goda