All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/2] Add support for Amlogic Meson MMC controller
@ 2016-05-12 12:41 ` Carlo Caione
  0 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-12 12:41 UTC (permalink / raw)
  To: u-boot

From: Carlo Caione <carlo@endlessm.com>

This patchset is a port / rewrite of the Amlogic driver shipped in the SDK for
the Meson GXBB (S905) platform. It has been tested on the Hardkernel Odroid-C2
board.

The driver is enabled using U_BOOT_DEVICE in the board file because there is no
MMC driver yet in the linux kernel.

This patchset depends on the basic support for Amlogic S905 SoCs written by
Beniamino[1]

[1] https://www.mail-archive.com/u-boot at lists.denx.de/msg212188.html

Carlo Caione (2):
  mmc: Add Amlogic Meson driver
  arm: amlogic: Enable MMC driver on Odroid-C2

 arch/arm/include/asm/arch-meson/sd_emmc.h | 109 +++++++++++
 board/hardkernel/odroid-c2/odroid-c2.c    |  42 ++++
 configs/odroid-c2_defconfig               |   5 +
 drivers/mmc/Makefile                      |   1 +
 drivers/mmc/meson_mmc.c                   | 305 ++++++++++++++++++++++++++++++
 include/configs/odroid-c2.h               |   7 +
 6 files changed, 469 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h
 create mode 100644 drivers/mmc/meson_mmc.c

-- 
2.7.4

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 0/2] Add support for Amlogic Meson MMC controller
@ 2016-05-12 12:41 ` Carlo Caione
  0 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-12 12:41 UTC (permalink / raw)
  To: linus-amlogic

From: Carlo Caione <carlo@endlessm.com>

This patchset is a port / rewrite of the Amlogic driver shipped in the SDK for
the Meson GXBB (S905) platform. It has been tested on the Hardkernel Odroid-C2
board.

The driver is enabled using U_BOOT_DEVICE in the board file because there is no
MMC driver yet in the linux kernel.

This patchset depends on the basic support for Amlogic S905 SoCs written by
Beniamino[1]

[1] https://www.mail-archive.com/u-boot at lists.denx.de/msg212188.html

Carlo Caione (2):
  mmc: Add Amlogic Meson driver
  arm: amlogic: Enable MMC driver on Odroid-C2

 arch/arm/include/asm/arch-meson/sd_emmc.h | 109 +++++++++++
 board/hardkernel/odroid-c2/odroid-c2.c    |  42 ++++
 configs/odroid-c2_defconfig               |   5 +
 drivers/mmc/Makefile                      |   1 +
 drivers/mmc/meson_mmc.c                   | 305 ++++++++++++++++++++++++++++++
 include/configs/odroid-c2.h               |   7 +
 6 files changed, 469 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h
 create mode 100644 drivers/mmc/meson_mmc.c

-- 
2.7.4

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 1/2] mmc: Add Amlogic Meson driver
  2016-05-12 12:41 ` Carlo Caione
@ 2016-05-12 12:41   ` Carlo Caione
  -1 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-12 12:41 UTC (permalink / raw)
  To: u-boot

From: Carlo Caione <carlo@endlessm.com>

This is a port / rewrite of the Amlogic driver shipped whithin the
Amlogic SDK for the Meson GXBaby (S905) SoC.

Signed-off-by: Carlo Caione <carlo@endlessm.com>
---
 arch/arm/include/asm/arch-meson/sd_emmc.h | 109 +++++++++++
 drivers/mmc/Makefile                      |   1 +
 drivers/mmc/meson_mmc.c                   | 305 ++++++++++++++++++++++++++++++
 3 files changed, 415 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h
 create mode 100644 drivers/mmc/meson_mmc.c

diff --git a/arch/arm/include/asm/arch-meson/sd_emmc.h b/arch/arm/include/asm/arch-meson/sd_emmc.h
new file mode 100644
index 0000000..6781dca
--- /dev/null
+++ b/arch/arm/include/asm/arch-meson/sd_emmc.h
@@ -0,0 +1,109 @@
+/*
+ * (C) Copyright 2016 Carlo Caione <carlo@caione.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __SD_EMMC_H__
+#define __SD_EMMC_H__
+
+#include <mmc.h>
+
+#define SDIO_PORT_A			0
+#define SDIO_PORT_B			1
+#define SDIO_PORT_C			2
+
+#define SD_EMMC_BASE_A			0xd0070000
+#define SD_EMMC_BASE_B			0xd0072000
+#define SD_EMMC_BASE_C			0xd0074000
+
+#define SD_IRQ_ALL			0x3fff
+
+#define SD_EMMC_CLKSRC_24M		24000000
+#define SD_EMMC_CLKSRC_DIV2		1000000000
+
+#define CLK_DIV				0
+#define CLK_SRC				6
+#define CLK_CO_PHASE			8
+#define CLK_ALWAYS_ON			24
+
+#define ADDR_USE_PING_BUF		BIT(1)
+
+#define SD_EMMC_RXD_ERROR		BIT(0)
+#define SD_EMMC_TXD_ERROR		BIT(1)
+#define SD_EMMC_DESC_ERROR		BIT(2)
+#define SD_EMMC_RESP_CRC_ERROR		BIT(3)
+#define SD_EMMC_RESP_TIMEOUT_ERROR	BIT(4)
+#define SD_EMMC_DESC_TIMEOUT_ERROR	BIT(5)
+
+#define CFG_BUS_WIDTH			0
+#define CFG_BUS_WIDTH_MASK		(0x3 << 0)
+#define CFG_BL_LEN			4
+#define CFG_BL_LEN_MASK			(0xf << 4)
+#define CFG_RESP_TIMEOUT		8
+#define CFG_RESP_TIMEOUT_MASK		(0xf << 8)
+#define CFG_RC_CC			12
+#define CFG_RC_CC_MASK			(0xf << 12)
+
+#define STATUS_RXD_ERR_MASK		0xff
+#define STATUS_TXD_ERR			BIT(8)
+#define STATUS_DESC_ERR			BIT(9)
+#define STATUS_RESP_ERR			BIT(10)
+#define STATUS_RESP_TIMEOUT		BIT(11)
+#define STATUS_DESC_TIMEOUT		BIT(12)
+#define STATUS_END_OF_CHAIN		BIT(13)
+
+#define CMD_CFG_LENGTH_MASK		0x1ff
+#define CMD_CFG_CMD_INDEX		24
+#define CMD_CFG_BLOCK_MODE		BIT(9)
+#define CMD_CFG_R1B			BIT(10)
+#define CMD_CFG_END_OF_CHAIN		BIT(11)
+#define CMD_CFG_NO_RESP			BIT(16)
+#define CMD_CFG_DATA_IO			BIT(18)
+#define CMD_CFG_DATA_WR			BIT(19)
+#define CMD_CFG_RESP_NOCRC		BIT(20)
+#define CMD_CFG_RESP_128		BIT(21)
+#define CMD_CFG_OWNER			BIT(31)
+
+struct meson_mmc_regs {
+	uint32_t gclock;
+	uint32_t gdelay;
+	uint32_t gadjust;
+	uint32_t reserved_0c;
+	uint32_t gcalout;
+	uint32_t reserved_14[11];
+	uint32_t gstart;
+	uint32_t gcfg;
+	uint32_t gstatus;
+	uint32_t girq_en;
+	uint32_t gcmd_cfg;
+	uint32_t gcmd_arg;
+	uint32_t gcmd_dat;
+	uint32_t gcmd_rsp0;
+	uint32_t gcmd_rsp1;
+	uint32_t gcmd_rsp2;
+	uint32_t gcmd_rsp3;
+	uint32_t reserved_6c;
+	uint32_t gcurr_cfg;
+	uint32_t gcurr_arg;
+	uint32_t gcurr_dat;
+	uint32_t gcurr_rsp;
+	uint32_t gnext_cfg;
+	uint32_t gnext_arg;
+	uint32_t gnext_dat;
+	uint32_t gnext_rsp;
+	uint32_t grxd;
+	uint32_t gtxd;
+	uint32_t reserved_98[90];
+	uint32_t gdesc[128];
+	uint32_t gping[128];
+	uint32_t gpong[128];
+};
+
+struct meson_mmc_platdata {
+	struct mmc_config cfg;
+	struct meson_mmc_regs *sd_emmc_reg;
+	char *w_buf;
+};
+
+#endif
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 585aaf3..08ac9ba 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_FTSDC021) += ftsdc021_sdhci.o
 obj-$(CONFIG_GENERIC_MMC) += mmc.o
 obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
 obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o
+obj-$(CONFIG_MMC_MESON) += meson_mmc.o
 obj-$(CONFIG_MMC_SPI) += mmc_spi.o
 obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o
 obj-$(CONFIG_MV_SDHCI) += mv_sdhci.o
diff --git a/drivers/mmc/meson_mmc.c b/drivers/mmc/meson_mmc.c
new file mode 100644
index 0000000..af224ec
--- /dev/null
+++ b/drivers/mmc/meson_mmc.c
@@ -0,0 +1,305 @@
+/*
+ * (C) Copyright 2016 Carlo Caione <carlo@caione.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/io.h>
+#include <asm/arch/sd_emmc.h>
+#include <dm/device.h>
+
+static void meson_mmc_config_clock(struct mmc *mmc,
+				   struct meson_mmc_regs *meson_mmc_reg)
+{
+	uint32_t meson_mmc_clk = 0;
+	unsigned int clk, clk_src, clk_div;
+
+	if (mmc->clock > 12000000) {
+		clk = SD_EMMC_CLKSRC_DIV2;
+		clk_src = 1;
+	} else {
+		clk = SD_EMMC_CLKSRC_24M;
+		clk_src = 0;
+	}
+	clk_div = clk / mmc->clock;
+
+	if (mmc->clock < mmc->cfg->f_min)
+		mmc->clock = mmc->cfg->f_min;
+	if (mmc->clock > mmc->cfg->f_max)
+		mmc->clock = mmc->cfg->f_max;
+
+	/* Keep the clock always on */
+	meson_mmc_clk |= (1 << CLK_ALWAYS_ON);
+
+	/* 180 phase */
+	meson_mmc_clk |= (2 << CLK_CO_PHASE);
+
+	/* clock settings */
+	meson_mmc_clk |= (clk_src << CLK_SRC);
+	meson_mmc_clk |= (clk_div << CLK_DIV);
+
+	writel(meson_mmc_clk, &meson_mmc_reg->gclock);
+}
+
+static void meson_mmc_set_ios(struct mmc *mmc)
+{
+	struct meson_mmc_platdata *pdata;
+	struct meson_mmc_regs *meson_mmc_reg;
+	unsigned int bus_width;
+	uint32_t meson_mmc_cfg = 0;
+
+	pdata = mmc->priv;
+	meson_mmc_reg = pdata->sd_emmc_reg;
+
+	meson_mmc_config_clock(mmc, meson_mmc_reg);
+
+	meson_mmc_cfg = readl(&meson_mmc_reg->gcfg);
+
+	if (mmc->bus_width == 1)
+		bus_width = 0;
+	else
+		bus_width = mmc->bus_width / 4;
+
+	/* 1-bit mode */
+	meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK;
+	meson_mmc_cfg |= (bus_width << CFG_BUS_WIDTH);
+
+	/* 512 bytes block lenght */
+	meson_mmc_cfg &= ~CFG_BL_LEN_MASK;
+	meson_mmc_cfg |= (9 << CFG_BL_LEN);
+
+	/* Response timeout 256 clk */
+	meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK;
+	meson_mmc_cfg |= (7 << CFG_RESP_TIMEOUT);
+
+	/* Command-command gap 1024 clk */
+	meson_mmc_cfg &= ~CFG_RC_CC_MASK;
+	meson_mmc_cfg |= (4 << CFG_RC_CC);
+
+	writel(meson_mmc_cfg, &meson_mmc_reg->gcfg);
+
+	return;
+}
+
+static int meson_mmc_init(struct mmc *mmc)
+{
+	mmc_set_clock(mmc, 400000);
+
+	return 0;
+}
+
+static void meson_mmc_setup_cmd(struct mmc *mmc, struct mmc_data *data,
+				struct mmc_cmd *cmd,
+				struct meson_mmc_regs *meson_mmc_reg)
+{
+	uint32_t meson_mmc_cmd = 0;
+
+	meson_mmc_cmd = ((0x80 | cmd->cmdidx) << CMD_CFG_CMD_INDEX);
+
+	if (cmd->resp_type & MMC_RSP_PRESENT) {
+		if (cmd->resp_type & MMC_RSP_136)
+			meson_mmc_cmd |= CMD_CFG_RESP_128;
+
+		if (cmd->resp_type & MMC_RSP_BUSY)
+			meson_mmc_cmd |= CMD_CFG_R1B;
+
+		if (!(cmd->resp_type & MMC_RSP_CRC))
+			meson_mmc_cmd |= CMD_CFG_RESP_NOCRC;
+	} else {
+		meson_mmc_cmd |= CMD_CFG_NO_RESP;
+	}
+
+	if (data) {
+		meson_mmc_cmd |= CMD_CFG_DATA_IO;
+
+		if (data->flags == MMC_DATA_WRITE)
+			meson_mmc_cmd |= CMD_CFG_DATA_WR;
+
+		if (data->blocks > 1) {
+			meson_mmc_cmd |= CMD_CFG_BLOCK_MODE;
+			meson_mmc_cmd |= data->blocks;
+		} else {
+			meson_mmc_cmd |= (data->blocksize & CMD_CFG_LENGTH_MASK);
+		}
+	}
+
+	meson_mmc_cmd |= CMD_CFG_OWNER;
+	meson_mmc_cmd |= CMD_CFG_END_OF_CHAIN;
+
+	writel(meson_mmc_cmd, &meson_mmc_reg->gcmd_cfg);
+
+	return;
+}
+
+static void meson_mmc_setup_addr(struct mmc *mmc, struct mmc_data *data,
+				 struct meson_mmc_regs *meson_mmc_reg)
+{
+	struct meson_mmc_platdata *pdata;
+	unsigned int data_size = 0;
+	uint32_t meson_mmc_data_addr = 0;
+
+	pdata = mmc->priv;
+
+	if (data) {
+		data_size = data->blocks * data->blocksize;
+
+		if (data->flags == MMC_DATA_READ) {
+			if (data_size < 0x200) {
+				meson_mmc_data_addr = (ulong) meson_mmc_reg->gping;
+				meson_mmc_data_addr |= ADDR_USE_PING_BUF;
+			} else {
+				invalidate_dcache_range((ulong) data->dest,
+							(ulong) (data->dest + data_size));
+				meson_mmc_data_addr = (ulong) data->dest;
+			}
+		}
+
+		if (data->flags == MMC_DATA_WRITE) {
+			pdata->w_buf = calloc(data_size, sizeof(char));
+			memcpy(pdata->w_buf, data->src, data_size);
+			flush_dcache_range((ulong) pdata->w_buf,
+					   (ulong) (pdata->w_buf + data_size));
+			meson_mmc_data_addr = (ulong) pdata->w_buf;
+		}
+	}
+
+	writel(meson_mmc_data_addr, &meson_mmc_reg->gcmd_dat);
+
+	return;
+}
+
+static void meson_mmc_read_response(struct mmc *mmc, struct mmc_data *data,
+				    struct mmc_cmd *cmd,
+				    struct meson_mmc_regs *meson_mmc_reg)
+{
+	unsigned int data_size = 0;
+
+	if (data) {
+		data_size = data->blocks * data->blocksize;
+		if ((data_size < 0x200) && (data->flags == MMC_DATA_READ))
+			memcpy(data->dest, (const void *)meson_mmc_reg->gping, data_size);
+	}
+
+	if (cmd->resp_type & MMC_RSP_136) {
+		cmd->response[0] = readl(&meson_mmc_reg->gcmd_rsp3);
+		cmd->response[1] = readl(&meson_mmc_reg->gcmd_rsp2);
+		cmd->response[2] = readl(&meson_mmc_reg->gcmd_rsp1);
+		cmd->response[3] = readl(&meson_mmc_reg->gcmd_rsp0);
+	} else {
+		cmd->response[0] = readl(&meson_mmc_reg->gcmd_rsp0);
+	}
+}
+
+static int meson_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+			      struct mmc_data *data)
+{
+	struct meson_mmc_platdata *pdata;
+	struct meson_mmc_regs *meson_mmc_reg;
+	uint32_t meson_mmc_irq = 0;
+	int ret = 0;
+
+	pdata = mmc->priv;
+	meson_mmc_reg = pdata->sd_emmc_reg;
+
+	meson_mmc_setup_cmd(mmc, data, cmd, meson_mmc_reg);
+	meson_mmc_setup_addr(mmc, data, meson_mmc_reg);
+
+	writel(SD_IRQ_ALL, &meson_mmc_reg->gstatus);
+	writel(cmd->cmdarg, &meson_mmc_reg->gcmd_arg);
+
+	while (1) {
+		meson_mmc_irq = readl(&meson_mmc_reg->gstatus);
+		if (meson_mmc_irq & STATUS_END_OF_CHAIN)
+			break;
+	}
+
+	if (meson_mmc_irq & STATUS_RXD_ERR_MASK)
+		ret |= SD_EMMC_RXD_ERROR;
+	if (meson_mmc_irq & STATUS_TXD_ERR)
+		ret |= SD_EMMC_TXD_ERROR;
+	if (meson_mmc_irq & STATUS_DESC_ERR)
+		ret |= SD_EMMC_DESC_ERROR;
+	if (meson_mmc_irq & STATUS_RESP_ERR)
+		ret |= SD_EMMC_RESP_CRC_ERROR;
+	if (meson_mmc_irq & STATUS_RESP_TIMEOUT)
+		ret |= SD_EMMC_RESP_TIMEOUT_ERROR;
+	if (meson_mmc_irq & STATUS_DESC_TIMEOUT)
+		ret |= SD_EMMC_DESC_TIMEOUT_ERROR;
+
+	meson_mmc_read_response(mmc, data, cmd, meson_mmc_reg);
+
+	if (data && data->flags == MMC_DATA_WRITE)
+		free(pdata->w_buf);
+
+	if (ret) {
+		if (meson_mmc_irq & STATUS_RESP_TIMEOUT)
+			return TIMEOUT;
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct mmc_ops meson_mmc_ops = {
+	.send_cmd	= meson_mmc_send_cmd,
+	.set_ios	= meson_mmc_set_ios,
+	.init		= meson_mmc_init,
+};
+
+static int meson_mmc_ofdata_to_platdata(struct udevice *dev)
+{
+	struct meson_mmc_platdata *pdata = dev->platdata;
+	fdt_addr_t addr;
+
+	addr = dev_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	pdata->sd_emmc_reg = (struct meson_mmc_regs *)addr;
+
+	return 0;
+}
+
+static int meson_mmc_probe(struct udevice *dev)
+{
+	struct meson_mmc_platdata *pdata = dev->platdata;
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct mmc *mmc;
+	struct mmc_config *cfg;
+
+	cfg = &pdata->cfg;
+	cfg->ops = &meson_mmc_ops;
+
+	cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 |
+			MMC_VDD_31_32 | MMC_VDD_165_195;
+	cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT |
+			 MMC_MODE_HS_52MHz | MMC_MODE_HS;
+	cfg->f_min = 400000;
+	cfg->f_max = 50000000;
+	cfg->b_max = 256;
+
+	mmc = mmc_create(cfg, pdata);
+	if (!mmc)
+		return -ENOMEM;
+
+	upriv->mmc = mmc;
+	return 0;
+}
+
+static const struct udevice_id meson_mmc_match[] = {
+	{ .compatible = "amlogic,meson-mmc" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(meson_mmc) = {
+	.name = "meson_mmc",
+	.id = UCLASS_MMC,
+	.of_match = meson_mmc_match,
+	.probe = meson_mmc_probe,
+	.ofdata_to_platdata = meson_mmc_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct meson_mmc_platdata),
+};
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 1/2] mmc: Add Amlogic Meson driver
@ 2016-05-12 12:41   ` Carlo Caione
  0 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-12 12:41 UTC (permalink / raw)
  To: linus-amlogic

From: Carlo Caione <carlo@endlessm.com>

This is a port / rewrite of the Amlogic driver shipped whithin the
Amlogic SDK for the Meson GXBaby (S905) SoC.

Signed-off-by: Carlo Caione <carlo@endlessm.com>
---
 arch/arm/include/asm/arch-meson/sd_emmc.h | 109 +++++++++++
 drivers/mmc/Makefile                      |   1 +
 drivers/mmc/meson_mmc.c                   | 305 ++++++++++++++++++++++++++++++
 3 files changed, 415 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h
 create mode 100644 drivers/mmc/meson_mmc.c

diff --git a/arch/arm/include/asm/arch-meson/sd_emmc.h b/arch/arm/include/asm/arch-meson/sd_emmc.h
new file mode 100644
index 0000000..6781dca
--- /dev/null
+++ b/arch/arm/include/asm/arch-meson/sd_emmc.h
@@ -0,0 +1,109 @@
+/*
+ * (C) Copyright 2016 Carlo Caione <carlo@caione.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __SD_EMMC_H__
+#define __SD_EMMC_H__
+
+#include <mmc.h>
+
+#define SDIO_PORT_A			0
+#define SDIO_PORT_B			1
+#define SDIO_PORT_C			2
+
+#define SD_EMMC_BASE_A			0xd0070000
+#define SD_EMMC_BASE_B			0xd0072000
+#define SD_EMMC_BASE_C			0xd0074000
+
+#define SD_IRQ_ALL			0x3fff
+
+#define SD_EMMC_CLKSRC_24M		24000000
+#define SD_EMMC_CLKSRC_DIV2		1000000000
+
+#define CLK_DIV				0
+#define CLK_SRC				6
+#define CLK_CO_PHASE			8
+#define CLK_ALWAYS_ON			24
+
+#define ADDR_USE_PING_BUF		BIT(1)
+
+#define SD_EMMC_RXD_ERROR		BIT(0)
+#define SD_EMMC_TXD_ERROR		BIT(1)
+#define SD_EMMC_DESC_ERROR		BIT(2)
+#define SD_EMMC_RESP_CRC_ERROR		BIT(3)
+#define SD_EMMC_RESP_TIMEOUT_ERROR	BIT(4)
+#define SD_EMMC_DESC_TIMEOUT_ERROR	BIT(5)
+
+#define CFG_BUS_WIDTH			0
+#define CFG_BUS_WIDTH_MASK		(0x3 << 0)
+#define CFG_BL_LEN			4
+#define CFG_BL_LEN_MASK			(0xf << 4)
+#define CFG_RESP_TIMEOUT		8
+#define CFG_RESP_TIMEOUT_MASK		(0xf << 8)
+#define CFG_RC_CC			12
+#define CFG_RC_CC_MASK			(0xf << 12)
+
+#define STATUS_RXD_ERR_MASK		0xff
+#define STATUS_TXD_ERR			BIT(8)
+#define STATUS_DESC_ERR			BIT(9)
+#define STATUS_RESP_ERR			BIT(10)
+#define STATUS_RESP_TIMEOUT		BIT(11)
+#define STATUS_DESC_TIMEOUT		BIT(12)
+#define STATUS_END_OF_CHAIN		BIT(13)
+
+#define CMD_CFG_LENGTH_MASK		0x1ff
+#define CMD_CFG_CMD_INDEX		24
+#define CMD_CFG_BLOCK_MODE		BIT(9)
+#define CMD_CFG_R1B			BIT(10)
+#define CMD_CFG_END_OF_CHAIN		BIT(11)
+#define CMD_CFG_NO_RESP			BIT(16)
+#define CMD_CFG_DATA_IO			BIT(18)
+#define CMD_CFG_DATA_WR			BIT(19)
+#define CMD_CFG_RESP_NOCRC		BIT(20)
+#define CMD_CFG_RESP_128		BIT(21)
+#define CMD_CFG_OWNER			BIT(31)
+
+struct meson_mmc_regs {
+	uint32_t gclock;
+	uint32_t gdelay;
+	uint32_t gadjust;
+	uint32_t reserved_0c;
+	uint32_t gcalout;
+	uint32_t reserved_14[11];
+	uint32_t gstart;
+	uint32_t gcfg;
+	uint32_t gstatus;
+	uint32_t girq_en;
+	uint32_t gcmd_cfg;
+	uint32_t gcmd_arg;
+	uint32_t gcmd_dat;
+	uint32_t gcmd_rsp0;
+	uint32_t gcmd_rsp1;
+	uint32_t gcmd_rsp2;
+	uint32_t gcmd_rsp3;
+	uint32_t reserved_6c;
+	uint32_t gcurr_cfg;
+	uint32_t gcurr_arg;
+	uint32_t gcurr_dat;
+	uint32_t gcurr_rsp;
+	uint32_t gnext_cfg;
+	uint32_t gnext_arg;
+	uint32_t gnext_dat;
+	uint32_t gnext_rsp;
+	uint32_t grxd;
+	uint32_t gtxd;
+	uint32_t reserved_98[90];
+	uint32_t gdesc[128];
+	uint32_t gping[128];
+	uint32_t gpong[128];
+};
+
+struct meson_mmc_platdata {
+	struct mmc_config cfg;
+	struct meson_mmc_regs *sd_emmc_reg;
+	char *w_buf;
+};
+
+#endif
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 585aaf3..08ac9ba 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_FTSDC021) += ftsdc021_sdhci.o
 obj-$(CONFIG_GENERIC_MMC) += mmc.o
 obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
 obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o
+obj-$(CONFIG_MMC_MESON) += meson_mmc.o
 obj-$(CONFIG_MMC_SPI) += mmc_spi.o
 obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o
 obj-$(CONFIG_MV_SDHCI) += mv_sdhci.o
diff --git a/drivers/mmc/meson_mmc.c b/drivers/mmc/meson_mmc.c
new file mode 100644
index 0000000..af224ec
--- /dev/null
+++ b/drivers/mmc/meson_mmc.c
@@ -0,0 +1,305 @@
+/*
+ * (C) Copyright 2016 Carlo Caione <carlo@caione.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/io.h>
+#include <asm/arch/sd_emmc.h>
+#include <dm/device.h>
+
+static void meson_mmc_config_clock(struct mmc *mmc,
+				   struct meson_mmc_regs *meson_mmc_reg)
+{
+	uint32_t meson_mmc_clk = 0;
+	unsigned int clk, clk_src, clk_div;
+
+	if (mmc->clock > 12000000) {
+		clk = SD_EMMC_CLKSRC_DIV2;
+		clk_src = 1;
+	} else {
+		clk = SD_EMMC_CLKSRC_24M;
+		clk_src = 0;
+	}
+	clk_div = clk / mmc->clock;
+
+	if (mmc->clock < mmc->cfg->f_min)
+		mmc->clock = mmc->cfg->f_min;
+	if (mmc->clock > mmc->cfg->f_max)
+		mmc->clock = mmc->cfg->f_max;
+
+	/* Keep the clock always on */
+	meson_mmc_clk |= (1 << CLK_ALWAYS_ON);
+
+	/* 180 phase */
+	meson_mmc_clk |= (2 << CLK_CO_PHASE);
+
+	/* clock settings */
+	meson_mmc_clk |= (clk_src << CLK_SRC);
+	meson_mmc_clk |= (clk_div << CLK_DIV);
+
+	writel(meson_mmc_clk, &meson_mmc_reg->gclock);
+}
+
+static void meson_mmc_set_ios(struct mmc *mmc)
+{
+	struct meson_mmc_platdata *pdata;
+	struct meson_mmc_regs *meson_mmc_reg;
+	unsigned int bus_width;
+	uint32_t meson_mmc_cfg = 0;
+
+	pdata = mmc->priv;
+	meson_mmc_reg = pdata->sd_emmc_reg;
+
+	meson_mmc_config_clock(mmc, meson_mmc_reg);
+
+	meson_mmc_cfg = readl(&meson_mmc_reg->gcfg);
+
+	if (mmc->bus_width == 1)
+		bus_width = 0;
+	else
+		bus_width = mmc->bus_width / 4;
+
+	/* 1-bit mode */
+	meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK;
+	meson_mmc_cfg |= (bus_width << CFG_BUS_WIDTH);
+
+	/* 512 bytes block lenght */
+	meson_mmc_cfg &= ~CFG_BL_LEN_MASK;
+	meson_mmc_cfg |= (9 << CFG_BL_LEN);
+
+	/* Response timeout 256 clk */
+	meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK;
+	meson_mmc_cfg |= (7 << CFG_RESP_TIMEOUT);
+
+	/* Command-command gap 1024 clk */
+	meson_mmc_cfg &= ~CFG_RC_CC_MASK;
+	meson_mmc_cfg |= (4 << CFG_RC_CC);
+
+	writel(meson_mmc_cfg, &meson_mmc_reg->gcfg);
+
+	return;
+}
+
+static int meson_mmc_init(struct mmc *mmc)
+{
+	mmc_set_clock(mmc, 400000);
+
+	return 0;
+}
+
+static void meson_mmc_setup_cmd(struct mmc *mmc, struct mmc_data *data,
+				struct mmc_cmd *cmd,
+				struct meson_mmc_regs *meson_mmc_reg)
+{
+	uint32_t meson_mmc_cmd = 0;
+
+	meson_mmc_cmd = ((0x80 | cmd->cmdidx) << CMD_CFG_CMD_INDEX);
+
+	if (cmd->resp_type & MMC_RSP_PRESENT) {
+		if (cmd->resp_type & MMC_RSP_136)
+			meson_mmc_cmd |= CMD_CFG_RESP_128;
+
+		if (cmd->resp_type & MMC_RSP_BUSY)
+			meson_mmc_cmd |= CMD_CFG_R1B;
+
+		if (!(cmd->resp_type & MMC_RSP_CRC))
+			meson_mmc_cmd |= CMD_CFG_RESP_NOCRC;
+	} else {
+		meson_mmc_cmd |= CMD_CFG_NO_RESP;
+	}
+
+	if (data) {
+		meson_mmc_cmd |= CMD_CFG_DATA_IO;
+
+		if (data->flags == MMC_DATA_WRITE)
+			meson_mmc_cmd |= CMD_CFG_DATA_WR;
+
+		if (data->blocks > 1) {
+			meson_mmc_cmd |= CMD_CFG_BLOCK_MODE;
+			meson_mmc_cmd |= data->blocks;
+		} else {
+			meson_mmc_cmd |= (data->blocksize & CMD_CFG_LENGTH_MASK);
+		}
+	}
+
+	meson_mmc_cmd |= CMD_CFG_OWNER;
+	meson_mmc_cmd |= CMD_CFG_END_OF_CHAIN;
+
+	writel(meson_mmc_cmd, &meson_mmc_reg->gcmd_cfg);
+
+	return;
+}
+
+static void meson_mmc_setup_addr(struct mmc *mmc, struct mmc_data *data,
+				 struct meson_mmc_regs *meson_mmc_reg)
+{
+	struct meson_mmc_platdata *pdata;
+	unsigned int data_size = 0;
+	uint32_t meson_mmc_data_addr = 0;
+
+	pdata = mmc->priv;
+
+	if (data) {
+		data_size = data->blocks * data->blocksize;
+
+		if (data->flags == MMC_DATA_READ) {
+			if (data_size < 0x200) {
+				meson_mmc_data_addr = (ulong) meson_mmc_reg->gping;
+				meson_mmc_data_addr |= ADDR_USE_PING_BUF;
+			} else {
+				invalidate_dcache_range((ulong) data->dest,
+							(ulong) (data->dest + data_size));
+				meson_mmc_data_addr = (ulong) data->dest;
+			}
+		}
+
+		if (data->flags == MMC_DATA_WRITE) {
+			pdata->w_buf = calloc(data_size, sizeof(char));
+			memcpy(pdata->w_buf, data->src, data_size);
+			flush_dcache_range((ulong) pdata->w_buf,
+					   (ulong) (pdata->w_buf + data_size));
+			meson_mmc_data_addr = (ulong) pdata->w_buf;
+		}
+	}
+
+	writel(meson_mmc_data_addr, &meson_mmc_reg->gcmd_dat);
+
+	return;
+}
+
+static void meson_mmc_read_response(struct mmc *mmc, struct mmc_data *data,
+				    struct mmc_cmd *cmd,
+				    struct meson_mmc_regs *meson_mmc_reg)
+{
+	unsigned int data_size = 0;
+
+	if (data) {
+		data_size = data->blocks * data->blocksize;
+		if ((data_size < 0x200) && (data->flags == MMC_DATA_READ))
+			memcpy(data->dest, (const void *)meson_mmc_reg->gping, data_size);
+	}
+
+	if (cmd->resp_type & MMC_RSP_136) {
+		cmd->response[0] = readl(&meson_mmc_reg->gcmd_rsp3);
+		cmd->response[1] = readl(&meson_mmc_reg->gcmd_rsp2);
+		cmd->response[2] = readl(&meson_mmc_reg->gcmd_rsp1);
+		cmd->response[3] = readl(&meson_mmc_reg->gcmd_rsp0);
+	} else {
+		cmd->response[0] = readl(&meson_mmc_reg->gcmd_rsp0);
+	}
+}
+
+static int meson_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+			      struct mmc_data *data)
+{
+	struct meson_mmc_platdata *pdata;
+	struct meson_mmc_regs *meson_mmc_reg;
+	uint32_t meson_mmc_irq = 0;
+	int ret = 0;
+
+	pdata = mmc->priv;
+	meson_mmc_reg = pdata->sd_emmc_reg;
+
+	meson_mmc_setup_cmd(mmc, data, cmd, meson_mmc_reg);
+	meson_mmc_setup_addr(mmc, data, meson_mmc_reg);
+
+	writel(SD_IRQ_ALL, &meson_mmc_reg->gstatus);
+	writel(cmd->cmdarg, &meson_mmc_reg->gcmd_arg);
+
+	while (1) {
+		meson_mmc_irq = readl(&meson_mmc_reg->gstatus);
+		if (meson_mmc_irq & STATUS_END_OF_CHAIN)
+			break;
+	}
+
+	if (meson_mmc_irq & STATUS_RXD_ERR_MASK)
+		ret |= SD_EMMC_RXD_ERROR;
+	if (meson_mmc_irq & STATUS_TXD_ERR)
+		ret |= SD_EMMC_TXD_ERROR;
+	if (meson_mmc_irq & STATUS_DESC_ERR)
+		ret |= SD_EMMC_DESC_ERROR;
+	if (meson_mmc_irq & STATUS_RESP_ERR)
+		ret |= SD_EMMC_RESP_CRC_ERROR;
+	if (meson_mmc_irq & STATUS_RESP_TIMEOUT)
+		ret |= SD_EMMC_RESP_TIMEOUT_ERROR;
+	if (meson_mmc_irq & STATUS_DESC_TIMEOUT)
+		ret |= SD_EMMC_DESC_TIMEOUT_ERROR;
+
+	meson_mmc_read_response(mmc, data, cmd, meson_mmc_reg);
+
+	if (data && data->flags == MMC_DATA_WRITE)
+		free(pdata->w_buf);
+
+	if (ret) {
+		if (meson_mmc_irq & STATUS_RESP_TIMEOUT)
+			return TIMEOUT;
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct mmc_ops meson_mmc_ops = {
+	.send_cmd	= meson_mmc_send_cmd,
+	.set_ios	= meson_mmc_set_ios,
+	.init		= meson_mmc_init,
+};
+
+static int meson_mmc_ofdata_to_platdata(struct udevice *dev)
+{
+	struct meson_mmc_platdata *pdata = dev->platdata;
+	fdt_addr_t addr;
+
+	addr = dev_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	pdata->sd_emmc_reg = (struct meson_mmc_regs *)addr;
+
+	return 0;
+}
+
+static int meson_mmc_probe(struct udevice *dev)
+{
+	struct meson_mmc_platdata *pdata = dev->platdata;
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct mmc *mmc;
+	struct mmc_config *cfg;
+
+	cfg = &pdata->cfg;
+	cfg->ops = &meson_mmc_ops;
+
+	cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 |
+			MMC_VDD_31_32 | MMC_VDD_165_195;
+	cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT |
+			 MMC_MODE_HS_52MHz | MMC_MODE_HS;
+	cfg->f_min = 400000;
+	cfg->f_max = 50000000;
+	cfg->b_max = 256;
+
+	mmc = mmc_create(cfg, pdata);
+	if (!mmc)
+		return -ENOMEM;
+
+	upriv->mmc = mmc;
+	return 0;
+}
+
+static const struct udevice_id meson_mmc_match[] = {
+	{ .compatible = "amlogic,meson-mmc" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(meson_mmc) = {
+	.name = "meson_mmc",
+	.id = UCLASS_MMC,
+	.of_match = meson_mmc_match,
+	.probe = meson_mmc_probe,
+	.ofdata_to_platdata = meson_mmc_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct meson_mmc_platdata),
+};
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 2/2] arm: amlogic: Enable MMC driver on Odroid-C2
  2016-05-12 12:41 ` Carlo Caione
@ 2016-05-12 12:41   ` Carlo Caione
  -1 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-12 12:41 UTC (permalink / raw)
  To: u-boot

From: Carlo Caione <carlo@endlessm.com>

Add support for the MMC on the Hardkernel Odroid-C2 board.

Signed-off-by: Carlo Caione <carlo@endlessm.com>
---
 board/hardkernel/odroid-c2/odroid-c2.c | 42 ++++++++++++++++++++++++++++++++++
 configs/odroid-c2_defconfig            |  5 ++++
 include/configs/odroid-c2.h            |  7 ++++++
 3 files changed, 54 insertions(+)

diff --git a/board/hardkernel/odroid-c2/odroid-c2.c b/board/hardkernel/odroid-c2/odroid-c2.c
index bd72100..34b9a95 100644
--- a/board/hardkernel/odroid-c2/odroid-c2.c
+++ b/board/hardkernel/odroid-c2/odroid-c2.c
@@ -8,6 +8,7 @@
 #include <asm/io.h>
 #include <asm/arch/gxbb.h>
 #include <asm/arch/sm.h>
+#include <asm/arch/sd_emmc.h>
 #include <dm/platdata.h>
 #include <phy.h>
 
@@ -65,3 +66,44 @@ int misc_init_r(void)
 
 	return 0;
 }
+
+#ifdef CONFIG_GENERIC_MMC
+
+static const struct meson_mmc_platdata gxbb_sd_platdata[] = {
+	{ .sd_emmc_reg = (struct meson_mmc_regs *)SD_EMMC_BASE_A },
+	{ .sd_emmc_reg = (struct meson_mmc_regs *)SD_EMMC_BASE_B },
+	{ .sd_emmc_reg = (struct meson_mmc_regs *)SD_EMMC_BASE_C },
+};
+
+U_BOOT_DEVICE(meson_mmc) = {
+	.name = "meson_mmc",
+	.platdata = &gxbb_sd_platdata[CONFIG_MMC_MESON_SD_PORT],
+};
+
+static void meson_mmc_pinmux_setup(unsigned int port)
+{
+	switch (port) {
+	case SDIO_PORT_A:
+		setbits_le32(GXBB_PINMUX(8), 0x3f);
+		break;
+	case SDIO_PORT_B:
+		setbits_le32(GXBB_PINMUX(2), 0x3f << 10);
+		break;
+	case SDIO_PORT_C:
+		clrbits_le32(GXBB_PINMUX(2), 0x1f << 22);
+		setbits_le32(GXBB_PINMUX(4), (0x3 << 18) | (3 << 30));
+		break;
+	default:
+		printf("meson: invalid MMC port %d for pinmux setup\n", port);
+		break;
+	}
+}
+
+int board_mmc_init(bd_t *bis)
+{
+	meson_mmc_pinmux_setup(CONFIG_MMC_MESON_SD_PORT);
+
+	return 0;
+}
+
+#endif
diff --git a/configs/odroid-c2_defconfig b/configs/odroid-c2_defconfig
index a771b20..a1ffe73 100644
--- a/configs/odroid-c2_defconfig
+++ b/configs/odroid-c2_defconfig
@@ -7,11 +7,16 @@ CONFIG_DEFAULT_DEVICE_TREE="meson-gxbb-odroidc2"
 # CONFIG_CMD_IMI is not set
 # CONFIG_CMD_IMLS is not set
 # CONFIG_CMD_LOADS is not set
+CONFIG_CMD_MMC=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_SOURCE is not set
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
 CONFIG_OF_CONTROL=y
 CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_DM_MMC=y
 CONFIG_DM_ETH=y
 CONFIG_ETH_DESIGNWARE=y
 CONFIG_DEBUG_UART=y
diff --git a/include/configs/odroid-c2.h b/include/configs/odroid-c2.h
index 37a5671..4af7cc6 100644
--- a/include/configs/odroid-c2.h
+++ b/include/configs/odroid-c2.h
@@ -46,6 +46,13 @@
 #define CONFIG_SYS_LONGHELP
 #define CONFIG_CMDLINE_EDITING
 
+#ifdef CONFIG_DM_MMC
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_MMC_MESON
+#define CONFIG_MMC_MESON_SD_PORT	1
+#endif
+
 #include <config_distro_defaults.h>
 
 #endif /* __CONFIG_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 2/2] arm: amlogic: Enable MMC driver on Odroid-C2
@ 2016-05-12 12:41   ` Carlo Caione
  0 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-12 12:41 UTC (permalink / raw)
  To: linus-amlogic

From: Carlo Caione <carlo@endlessm.com>

Add support for the MMC on the Hardkernel Odroid-C2 board.

Signed-off-by: Carlo Caione <carlo@endlessm.com>
---
 board/hardkernel/odroid-c2/odroid-c2.c | 42 ++++++++++++++++++++++++++++++++++
 configs/odroid-c2_defconfig            |  5 ++++
 include/configs/odroid-c2.h            |  7 ++++++
 3 files changed, 54 insertions(+)

diff --git a/board/hardkernel/odroid-c2/odroid-c2.c b/board/hardkernel/odroid-c2/odroid-c2.c
index bd72100..34b9a95 100644
--- a/board/hardkernel/odroid-c2/odroid-c2.c
+++ b/board/hardkernel/odroid-c2/odroid-c2.c
@@ -8,6 +8,7 @@
 #include <asm/io.h>
 #include <asm/arch/gxbb.h>
 #include <asm/arch/sm.h>
+#include <asm/arch/sd_emmc.h>
 #include <dm/platdata.h>
 #include <phy.h>
 
@@ -65,3 +66,44 @@ int misc_init_r(void)
 
 	return 0;
 }
+
+#ifdef CONFIG_GENERIC_MMC
+
+static const struct meson_mmc_platdata gxbb_sd_platdata[] = {
+	{ .sd_emmc_reg = (struct meson_mmc_regs *)SD_EMMC_BASE_A },
+	{ .sd_emmc_reg = (struct meson_mmc_regs *)SD_EMMC_BASE_B },
+	{ .sd_emmc_reg = (struct meson_mmc_regs *)SD_EMMC_BASE_C },
+};
+
+U_BOOT_DEVICE(meson_mmc) = {
+	.name = "meson_mmc",
+	.platdata = &gxbb_sd_platdata[CONFIG_MMC_MESON_SD_PORT],
+};
+
+static void meson_mmc_pinmux_setup(unsigned int port)
+{
+	switch (port) {
+	case SDIO_PORT_A:
+		setbits_le32(GXBB_PINMUX(8), 0x3f);
+		break;
+	case SDIO_PORT_B:
+		setbits_le32(GXBB_PINMUX(2), 0x3f << 10);
+		break;
+	case SDIO_PORT_C:
+		clrbits_le32(GXBB_PINMUX(2), 0x1f << 22);
+		setbits_le32(GXBB_PINMUX(4), (0x3 << 18) | (3 << 30));
+		break;
+	default:
+		printf("meson: invalid MMC port %d for pinmux setup\n", port);
+		break;
+	}
+}
+
+int board_mmc_init(bd_t *bis)
+{
+	meson_mmc_pinmux_setup(CONFIG_MMC_MESON_SD_PORT);
+
+	return 0;
+}
+
+#endif
diff --git a/configs/odroid-c2_defconfig b/configs/odroid-c2_defconfig
index a771b20..a1ffe73 100644
--- a/configs/odroid-c2_defconfig
+++ b/configs/odroid-c2_defconfig
@@ -7,11 +7,16 @@ CONFIG_DEFAULT_DEVICE_TREE="meson-gxbb-odroidc2"
 # CONFIG_CMD_IMI is not set
 # CONFIG_CMD_IMLS is not set
 # CONFIG_CMD_LOADS is not set
+CONFIG_CMD_MMC=y
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_SOURCE is not set
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
 CONFIG_OF_CONTROL=y
 CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_DM_MMC=y
 CONFIG_DM_ETH=y
 CONFIG_ETH_DESIGNWARE=y
 CONFIG_DEBUG_UART=y
diff --git a/include/configs/odroid-c2.h b/include/configs/odroid-c2.h
index 37a5671..4af7cc6 100644
--- a/include/configs/odroid-c2.h
+++ b/include/configs/odroid-c2.h
@@ -46,6 +46,13 @@
 #define CONFIG_SYS_LONGHELP
 #define CONFIG_CMDLINE_EDITING
 
+#ifdef CONFIG_DM_MMC
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_MMC_MESON
+#define CONFIG_MMC_MESON_SD_PORT	1
+#endif
+
 #include <config_distro_defaults.h>
 
 #endif /* __CONFIG_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 1/2] mmc: Add Amlogic Meson driver
  2016-05-12 12:41   ` Carlo Caione
@ 2016-05-13 13:46     ` Kevin Hilman
  -1 siblings, 0 replies; 28+ messages in thread
From: Kevin Hilman @ 2016-05-13 13:46 UTC (permalink / raw)
  To: u-boot

Carlo Caione <carlo@caione.org> writes:

> From: Carlo Caione <carlo@endlessm.com>
>
> This is a port / rewrite of the Amlogic driver shipped whithin the
> Amlogic SDK for the Meson GXBaby (S905) SoC.
>
> Signed-off-by: Carlo Caione <carlo@endlessm.com>

[...]

> +static const struct udevice_id meson_mmc_match[] = {
> +	{ .compatible = "amlogic,meson-mmc" },
> +	{ /* sentinel */ }

IIUC, this controller is different between meson8* and gxbb.  If that's
the case, this compatible should probably be more specific.

Kevin

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 1/2] mmc: Add Amlogic Meson driver
@ 2016-05-13 13:46     ` Kevin Hilman
  0 siblings, 0 replies; 28+ messages in thread
From: Kevin Hilman @ 2016-05-13 13:46 UTC (permalink / raw)
  To: linus-amlogic

Carlo Caione <carlo@caione.org> writes:

> From: Carlo Caione <carlo@endlessm.com>
>
> This is a port / rewrite of the Amlogic driver shipped whithin the
> Amlogic SDK for the Meson GXBaby (S905) SoC.
>
> Signed-off-by: Carlo Caione <carlo@endlessm.com>

[...]

> +static const struct udevice_id meson_mmc_match[] = {
> +	{ .compatible = "amlogic,meson-mmc" },
> +	{ /* sentinel */ }

IIUC, this controller is different between meson8* and gxbb.  If that's
the case, this compatible should probably be more specific.

Kevin

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 1/2] mmc: Add Amlogic Meson driver
  2016-05-13 13:46     ` Kevin Hilman
@ 2016-05-13 13:53       ` Carlo Caione
  -1 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-13 13:53 UTC (permalink / raw)
  To: u-boot

On Fri, May 13, 2016 at 3:46 PM, Kevin Hilman <khilman@baylibre.com> wrote:
> Carlo Caione <carlo@caione.org> writes:
>
>> From: Carlo Caione <carlo@endlessm.com>
>>
>> This is a port / rewrite of the Amlogic driver shipped whithin the
>> Amlogic SDK for the Meson GXBaby (S905) SoC.
>>
>> Signed-off-by: Carlo Caione <carlo@endlessm.com>
>
> [...]
>
>> +static const struct udevice_id meson_mmc_match[] = {
>> +     { .compatible = "amlogic,meson-mmc" },
>> +     { /* sentinel */ }
>
> IIUC, this controller is different between meson8* and gxbb.  If that's
> the case, this compatible should probably be more specific.

Yes, this is a point I raised also on lkml when I submitted the MMC
driver for the Meson8b.
Since the registers mapping is different I assume that this is the
case. Just to be sure, given that you are the only one with a
datasheet for the GXBB, can you confirm that?

Actually for the same reason I was in doubt if CONFIG_MMC_MESON was a
right naming choice here, but since it is really unlikely that we will
ever see a U-Boot port for the Meson8b I stuck with that.

Cheers,

-- 
Carlo Caione

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 1/2] mmc: Add Amlogic Meson driver
@ 2016-05-13 13:53       ` Carlo Caione
  0 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-13 13:53 UTC (permalink / raw)
  To: linus-amlogic

On Fri, May 13, 2016 at 3:46 PM, Kevin Hilman <khilman@baylibre.com> wrote:
> Carlo Caione <carlo@caione.org> writes:
>
>> From: Carlo Caione <carlo@endlessm.com>
>>
>> This is a port / rewrite of the Amlogic driver shipped whithin the
>> Amlogic SDK for the Meson GXBaby (S905) SoC.
>>
>> Signed-off-by: Carlo Caione <carlo@endlessm.com>
>
> [...]
>
>> +static const struct udevice_id meson_mmc_match[] = {
>> +     { .compatible = "amlogic,meson-mmc" },
>> +     { /* sentinel */ }
>
> IIUC, this controller is different between meson8* and gxbb.  If that's
> the case, this compatible should probably be more specific.

Yes, this is a point I raised also on lkml when I submitted the MMC
driver for the Meson8b.
Since the registers mapping is different I assume that this is the
case. Just to be sure, given that you are the only one with a
datasheet for the GXBB, can you confirm that?

Actually for the same reason I was in doubt if CONFIG_MMC_MESON was a
right naming choice here, but since it is really unlikely that we will
ever see a U-Boot port for the Meson8b I stuck with that.

Cheers,

-- 
Carlo Caione

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 1/2] mmc: Add Amlogic Meson driver
  2016-05-13 13:53       ` Carlo Caione
@ 2016-05-13 16:07         ` Kevin Hilman
  -1 siblings, 0 replies; 28+ messages in thread
From: Kevin Hilman @ 2016-05-13 16:07 UTC (permalink / raw)
  To: u-boot

Carlo Caione <carlo@caione.org> writes:

> On Fri, May 13, 2016 at 3:46 PM, Kevin Hilman <khilman@baylibre.com> wrote:
>> Carlo Caione <carlo@caione.org> writes:
>>
>>> From: Carlo Caione <carlo@endlessm.com>
>>>
>>> This is a port / rewrite of the Amlogic driver shipped whithin the
>>> Amlogic SDK for the Meson GXBaby (S905) SoC.
>>>
>>> Signed-off-by: Carlo Caione <carlo@endlessm.com>
>>
>> [...]
>>
>>> +static const struct udevice_id meson_mmc_match[] = {
>>> +     { .compatible = "amlogic,meson-mmc" },
>>> +     { /* sentinel */ }
>>
>> IIUC, this controller is different between meson8* and gxbb.  If that's
>> the case, this compatible should probably be more specific.
>
> Yes, this is a point I raised also on lkml when I submitted the MMC
> driver for the Meson8b.
> Since the registers mapping is different I assume that this is the
> case. Just to be sure, given that you are the only one with a
> datasheet for the GXBB, can you confirm that?

I took a quick look and just compared the register layouts between s805
and s905 and indeed they are quite different.

Kevin

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 1/2] mmc: Add Amlogic Meson driver
@ 2016-05-13 16:07         ` Kevin Hilman
  0 siblings, 0 replies; 28+ messages in thread
From: Kevin Hilman @ 2016-05-13 16:07 UTC (permalink / raw)
  To: linus-amlogic

Carlo Caione <carlo@caione.org> writes:

> On Fri, May 13, 2016 at 3:46 PM, Kevin Hilman <khilman@baylibre.com> wrote:
>> Carlo Caione <carlo@caione.org> writes:
>>
>>> From: Carlo Caione <carlo@endlessm.com>
>>>
>>> This is a port / rewrite of the Amlogic driver shipped whithin the
>>> Amlogic SDK for the Meson GXBaby (S905) SoC.
>>>
>>> Signed-off-by: Carlo Caione <carlo@endlessm.com>
>>
>> [...]
>>
>>> +static const struct udevice_id meson_mmc_match[] = {
>>> +     { .compatible = "amlogic,meson-mmc" },
>>> +     { /* sentinel */ }
>>
>> IIUC, this controller is different between meson8* and gxbb.  If that's
>> the case, this compatible should probably be more specific.
>
> Yes, this is a point I raised also on lkml when I submitted the MMC
> driver for the Meson8b.
> Since the registers mapping is different I assume that this is the
> case. Just to be sure, given that you are the only one with a
> datasheet for the GXBB, can you confirm that?

I took a quick look and just compared the register layouts between s805
and s905 and indeed they are quite different.

Kevin

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 0/2] Add support for Amlogic Meson MMC controller
  2016-05-12 12:41 ` Carlo Caione
@ 2016-05-20  4:51   ` Robert Gadsdon
  -1 siblings, 0 replies; 28+ messages in thread
From: Robert Gadsdon @ 2016-05-20  4:51 UTC (permalink / raw)
  To: u-boot

Applied this on my Odroid C2, and it worked OK when installed on the
SDcard, but failed when installed on the eMMC module:

=> version
U-Boot 2016.05-rc3 (May 14 2016 - 21:06:28 -0700) odroid-c2
aarch64-linux-gnu-gcc (GCC) 5.3.1 20160212 (Red Hat Cross 5.3.1-2)
GNU ld version 2.26.20160125

=> mmc info
Card did not respond to voltage select!

Robert Gadsdon.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 0/2] Add support for Amlogic Meson MMC controller
@ 2016-05-20  4:51   ` Robert Gadsdon
  0 siblings, 0 replies; 28+ messages in thread
From: Robert Gadsdon @ 2016-05-20  4:51 UTC (permalink / raw)
  To: linus-amlogic

Applied this on my Odroid C2, and it worked OK when installed on the
SDcard, but failed when installed on the eMMC module:

=> version
U-Boot 2016.05-rc3 (May 14 2016 - 21:06:28 -0700) odroid-c2
aarch64-linux-gnu-gcc (GCC) 5.3.1 20160212 (Red Hat Cross 5.3.1-2)
GNU ld version 2.26.20160125

=> mmc info
Card did not respond to voltage select!

Robert Gadsdon.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 0/2] Add support for Amlogic Meson MMC controller
  2016-05-20  4:51   ` Robert Gadsdon
@ 2016-05-20  6:27     ` Carlo Caione
  -1 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-20  6:27 UTC (permalink / raw)
  To: u-boot

On 19/05/16 21:51, Robert Gadsdon wrote:
> Applied this on my Odroid C2, and it worked OK when installed on the
> SDcard, but failed when installed on the eMMC module:
> 
> => version
> U-Boot 2016.05-rc3 (May 14 2016 - 21:06:28 -0700) odroid-c2
> aarch64-linux-gnu-gcc (GCC) 5.3.1 20160212 (Red Hat Cross 5.3.1-2)
> GNU ld version 2.26.20160125
> 
> => mmc info
> Card did not respond to voltage select!

Yes, this is expected since the muxing in the board file is only
enabling the SDcard. Could you try to set the correct muxing also for
the eMMC and check again?

Unfortunately I don't have an eMMC for the Odroid-C2 to check this out.
I'll try to prepare a board file also for the P20x so I can test this
better.

Thank you for testing this BTW.

Cheers,

-- 
Carlo Caione

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 0/2] Add support for Amlogic Meson MMC controller
@ 2016-05-20  6:27     ` Carlo Caione
  0 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-20  6:27 UTC (permalink / raw)
  To: linus-amlogic

On 19/05/16 21:51, Robert Gadsdon wrote:
> Applied this on my Odroid C2, and it worked OK when installed on the
> SDcard, but failed when installed on the eMMC module:
> 
> => version
> U-Boot 2016.05-rc3 (May 14 2016 - 21:06:28 -0700) odroid-c2
> aarch64-linux-gnu-gcc (GCC) 5.3.1 20160212 (Red Hat Cross 5.3.1-2)
> GNU ld version 2.26.20160125
> 
> => mmc info
> Card did not respond to voltage select!

Yes, this is expected since the muxing in the board file is only
enabling the SDcard. Could you try to set the correct muxing also for
the eMMC and check again?

Unfortunately I don't have an eMMC for the Odroid-C2 to check this out.
I'll try to prepare a board file also for the P20x so I can test this
better.

Thank you for testing this BTW.

Cheers,

-- 
Carlo Caione

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 0/2] Add support for Amlogic Meson MMC controller
  2016-05-20  6:27     ` Carlo Caione
@ 2016-05-20  8:07       ` Carlo Caione
  -1 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-20  8:07 UTC (permalink / raw)
  To: u-boot

On 20/05/16 08:27, Carlo Caione wrote:
> On 19/05/16 21:51, Robert Gadsdon wrote:
> > Applied this on my Odroid C2, and it worked OK when installed on the
> > SDcard, but failed when installed on the eMMC module:

Oh, reading this again you meant that you put u-boot directly on the
eMMC? Ok then, something is wrong when using the driver with the eMMC.

I'll try to boot it on the P20x and check what's wrong with it.

Thanks,

-- 
Carlo Caione

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 0/2] Add support for Amlogic Meson MMC controller
@ 2016-05-20  8:07       ` Carlo Caione
  0 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-20  8:07 UTC (permalink / raw)
  To: linus-amlogic

On 20/05/16 08:27, Carlo Caione wrote:
> On 19/05/16 21:51, Robert Gadsdon wrote:
> > Applied this on my Odroid C2, and it worked OK when installed on the
> > SDcard, but failed when installed on the eMMC module:

Oh, reading this again you meant that you put u-boot directly on the
eMMC? Ok then, something is wrong when using the driver with the eMMC.

I'll try to boot it on the P20x and check what's wrong with it.

Thanks,

-- 
Carlo Caione

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 0/2] Add support for Amlogic Meson MMC controller
  2016-05-20  8:07       ` Carlo Caione
@ 2016-05-20 18:58         ` Robert Gadsdon
  -1 siblings, 0 replies; 28+ messages in thread
From: Robert Gadsdon @ 2016-05-20 18:58 UTC (permalink / raw)
  To: u-boot

On 05/20/2016 01:07 AM, Carlo Caione wrote:
> On 20/05/16 08:27, Carlo Caione wrote:
>> On 19/05/16 21:51, Robert Gadsdon wrote:
>>> Applied this on my Odroid C2, and it worked OK when installed on the
>>> SDcard, but failed when installed on the eMMC module:
> 
> Oh, reading this again you meant that you put u-boot directly on the
> eMMC? Ok then, something is wrong when using the driver with the eMMC.
> 

Yes, I installed it directly on the eMMC, using the micro-sd adapter,
and following the same instructions as for the SDcard..

Robert Gadsdon.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 0/2] Add support for Amlogic Meson MMC controller
@ 2016-05-20 18:58         ` Robert Gadsdon
  0 siblings, 0 replies; 28+ messages in thread
From: Robert Gadsdon @ 2016-05-20 18:58 UTC (permalink / raw)
  To: linus-amlogic

On 05/20/2016 01:07 AM, Carlo Caione wrote:
> On 20/05/16 08:27, Carlo Caione wrote:
>> On 19/05/16 21:51, Robert Gadsdon wrote:
>>> Applied this on my Odroid C2, and it worked OK when installed on the
>>> SDcard, but failed when installed on the eMMC module:
> 
> Oh, reading this again you meant that you put u-boot directly on the
> eMMC? Ok then, something is wrong when using the driver with the eMMC.
> 

Yes, I installed it directly on the eMMC, using the micro-sd adapter,
and following the same instructions as for the SDcard..

Robert Gadsdon.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 0/2] Add support for Amlogic Meson MMC controller
  2016-05-20 18:58         ` Robert Gadsdon
@ 2016-05-20 19:34           ` Carlo Caione
  -1 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-20 19:34 UTC (permalink / raw)
  To: u-boot

On 20/05/16 11:58, Robert Gadsdon wrote:
> On 05/20/2016 01:07 AM, Carlo Caione wrote:
> > On 20/05/16 08:27, Carlo Caione wrote:
> >> On 19/05/16 21:51, Robert Gadsdon wrote:
> >>> Applied this on my Odroid C2, and it worked OK when installed on the
> >>> SDcard, but failed when installed on the eMMC module:
> > 
> > Oh, reading this again you meant that you put u-boot directly on the
> > eMMC? Ok then, something is wrong when using the driver with the eMMC.
> > 
> 
> Yes, I installed it directly on the eMMC, using the micro-sd adapter,
> and following the same instructions as for the SDcard..

Could you try with this patch?

diff --git a/board/hardkernel/odroid-c2/odroid-c2.c
b/board/hardkernel/odroid-c2/odroid-c2.c
index 34b9a95..ab78328 100644
--- a/board/hardkernel/odroid-c2/odroid-c2.c
+++ b/board/hardkernel/odroid-c2/odroid-c2.c
@@ -80,6 +80,11 @@ U_BOOT_DEVICE(meson_mmc) = {
        .platdata = &gxbb_sd_platdata[CONFIG_MMC_MESON_SD_PORT],
	 };
	  
	  +U_BOOT_DEVICE(meson_emmc) = {
	  +       .name = "meson_mmc",
	  +       .platdata = &gxbb_sd_platdata[2],
	  +};
	  +
	   static void meson_mmc_pinmux_setup(unsigned int port)
	    {
	            switch (port) {

Thanks,

-- 
Carlo Caione

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 0/2] Add support for Amlogic Meson MMC controller
@ 2016-05-20 19:34           ` Carlo Caione
  0 siblings, 0 replies; 28+ messages in thread
From: Carlo Caione @ 2016-05-20 19:34 UTC (permalink / raw)
  To: linus-amlogic

On 20/05/16 11:58, Robert Gadsdon wrote:
> On 05/20/2016 01:07 AM, Carlo Caione wrote:
> > On 20/05/16 08:27, Carlo Caione wrote:
> >> On 19/05/16 21:51, Robert Gadsdon wrote:
> >>> Applied this on my Odroid C2, and it worked OK when installed on the
> >>> SDcard, but failed when installed on the eMMC module:
> > 
> > Oh, reading this again you meant that you put u-boot directly on the
> > eMMC? Ok then, something is wrong when using the driver with the eMMC.
> > 
> 
> Yes, I installed it directly on the eMMC, using the micro-sd adapter,
> and following the same instructions as for the SDcard..

Could you try with this patch?

diff --git a/board/hardkernel/odroid-c2/odroid-c2.c
b/board/hardkernel/odroid-c2/odroid-c2.c
index 34b9a95..ab78328 100644
--- a/board/hardkernel/odroid-c2/odroid-c2.c
+++ b/board/hardkernel/odroid-c2/odroid-c2.c
@@ -80,6 +80,11 @@ U_BOOT_DEVICE(meson_mmc) = {
        .platdata = &gxbb_sd_platdata[CONFIG_MMC_MESON_SD_PORT],
	 };
	  
	  +U_BOOT_DEVICE(meson_emmc) = {
	  +       .name = "meson_mmc",
	  +       .platdata = &gxbb_sd_platdata[2],
	  +};
	  +
	   static void meson_mmc_pinmux_setup(unsigned int port)
	    {
	            switch (port) {

Thanks,

-- 
Carlo Caione

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 0/2] Add support for Amlogic Meson MMC controller
  2016-05-20 19:34           ` Carlo Caione
@ 2016-05-21  2:28             ` Robert Gadsdon
  -1 siblings, 0 replies; 28+ messages in thread
From: Robert Gadsdon @ 2016-05-21  2:28 UTC (permalink / raw)
  To: u-boot

On 05/20/2016 12:34 PM, Carlo Caione wrote:
> On 20/05/16 11:58, Robert Gadsdon wrote:
>> On 05/20/2016 01:07 AM, Carlo Caione wrote:
>>> On 20/05/16 08:27, Carlo Caione wrote:
>>>> On 19/05/16 21:51, Robert Gadsdon wrote:
>>>>> Applied this on my Odroid C2, and it worked OK when installed on the
>>>>> SDcard, but failed when installed on the eMMC module:
>>> Oh, reading this again you meant that you put u-boot directly on the
>>> eMMC? Ok then, something is wrong when using the driver with the eMMC.
>>>
>>> Yes, I installed it directly on the eMMC, using the micro-sd adapter,
>>> and following the same instructions as for the SDcard..
> Could you try with this patch?
>
> diff --git a/board/hardkernel/odroid-c2/odroid-c2.c
> b/board/hardkernel/odroid-c2/odroid-c2.c
> index 34b9a95..ab78328 100644
> --- a/board/hardkernel/odroid-c2/odroid-c2.c
> +++ b/board/hardkernel/odroid-c2/odroid-c2.c
> @@ -80,6 +80,11 @@ U_BOOT_DEVICE(meson_mmc) = {
>         .platdata = &gxbb_sd_platdata[CONFIG_MMC_MESON_SD_PORT],
> 	 };
> 	  
> 	  +U_BOOT_DEVICE(meson_emmc) = {
> 	  +       .name = "meson_mmc",
> 	  +       .platdata = &gxbb_sd_platdata[2],
> 	  +};
> 	  +
> 	   static void meson_mmc_pinmux_setup(unsigned int port)
> 	    {
> 	            switch (port) {
>
> Thanks,

Patch applied, and now the eMMC is detected OK:

=> mmc info
Device: <NULL>
Manufacturer ID: 15
OEM: 100
Name: BGND3
Tran Speed: 52000000
Rd Block Len: 512
MMC version 5.0
High Capacity: Yes
Capacity: 29.1 GiB
Bus Width: 8-bit
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 29.1 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH

...  And I can load/boot the Kernel (as far as the /dev/mmc... prompt..)

Thanks!

Robert Gadsdon.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 0/2] Add support for Amlogic Meson MMC controller
@ 2016-05-21  2:28             ` Robert Gadsdon
  0 siblings, 0 replies; 28+ messages in thread
From: Robert Gadsdon @ 2016-05-21  2:28 UTC (permalink / raw)
  To: linus-amlogic

On 05/20/2016 12:34 PM, Carlo Caione wrote:
> On 20/05/16 11:58, Robert Gadsdon wrote:
>> On 05/20/2016 01:07 AM, Carlo Caione wrote:
>>> On 20/05/16 08:27, Carlo Caione wrote:
>>>> On 19/05/16 21:51, Robert Gadsdon wrote:
>>>>> Applied this on my Odroid C2, and it worked OK when installed on the
>>>>> SDcard, but failed when installed on the eMMC module:
>>> Oh, reading this again you meant that you put u-boot directly on the
>>> eMMC? Ok then, something is wrong when using the driver with the eMMC.
>>>
>>> Yes, I installed it directly on the eMMC, using the micro-sd adapter,
>>> and following the same instructions as for the SDcard..
> Could you try with this patch?
>
> diff --git a/board/hardkernel/odroid-c2/odroid-c2.c
> b/board/hardkernel/odroid-c2/odroid-c2.c
> index 34b9a95..ab78328 100644
> --- a/board/hardkernel/odroid-c2/odroid-c2.c
> +++ b/board/hardkernel/odroid-c2/odroid-c2.c
> @@ -80,6 +80,11 @@ U_BOOT_DEVICE(meson_mmc) = {
>         .platdata = &gxbb_sd_platdata[CONFIG_MMC_MESON_SD_PORT],
> 	 };
> 	  
> 	  +U_BOOT_DEVICE(meson_emmc) = {
> 	  +       .name = "meson_mmc",
> 	  +       .platdata = &gxbb_sd_platdata[2],
> 	  +};
> 	  +
> 	   static void meson_mmc_pinmux_setup(unsigned int port)
> 	    {
> 	            switch (port) {
>
> Thanks,

Patch applied, and now the eMMC is detected OK:

=> mmc info
Device: <NULL>
Manufacturer ID: 15
OEM: 100
Name: BGND3
Tran Speed: 52000000
Rd Block Len: 512
MMC version 5.0
High Capacity: Yes
Capacity: 29.1 GiB
Bus Width: 8-bit
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 29.1 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH

...  And I can load/boot the Kernel (as far as the /dev/mmc... prompt..)

Thanks!

Robert Gadsdon.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [U-Boot,1/2] mmc: Add Amlogic Meson driver
  2016-05-12 12:41   ` Carlo Caione
@ 2016-08-04  6:48     ` Jaehoon Chung
  -1 siblings, 0 replies; 28+ messages in thread
From: Jaehoon Chung @ 2016-08-04  6:48 UTC (permalink / raw)
  To: u-boot

Hi Carlo

On 05/12/2016 09:41 PM, Carlo Caione wrote:
> From: Carlo Caione <carlo@endlessm.com>
> 
> This is a port / rewrite of the Amlogic driver shipped whithin the
> Amlogic SDK for the Meson GXBaby (S905) SoC.

s/whithin/within

And If you want to apply this patch, could you resend the patch on lates u-boot?

> 
> Signed-off-by: Carlo Caione <carlo@endlessm.com>
> ---
>  arch/arm/include/asm/arch-meson/sd_emmc.h | 109 +++++++++++
>  drivers/mmc/Makefile                      |   1 +
>  drivers/mmc/meson_mmc.c                   | 305 ++++++++++++++++++++++++++++++
>  3 files changed, 415 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h
>  create mode 100644 drivers/mmc/meson_mmc.c
> 
> diff --git a/arch/arm/include/asm/arch-meson/sd_emmc.h b/arch/arm/include/asm/arch-meson/sd_emmc.h
> new file mode 100644
> index 0000000..6781dca
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-meson/sd_emmc.h
> @@ -0,0 +1,109 @@
> +/*
> + * (C) Copyright 2016 Carlo Caione <carlo@caione.org>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#ifndef __SD_EMMC_H__
> +#define __SD_EMMC_H__
> +
> +#include <mmc.h>
> +
> +#define SDIO_PORT_A			0
> +#define SDIO_PORT_B			1
> +#define SDIO_PORT_C			2
> +
> +#define SD_EMMC_BASE_A			0xd0070000
> +#define SD_EMMC_BASE_B			0xd0072000
> +#define SD_EMMC_BASE_C			0xd0074000
> +
> +#define SD_IRQ_ALL			0x3fff
> +
> +#define SD_EMMC_CLKSRC_24M		24000000
> +#define SD_EMMC_CLKSRC_DIV2		1000000000

Is it right? 1GHz?

> +
> +#define CLK_DIV				0
> +#define CLK_SRC				6
> +#define CLK_CO_PHASE			8
> +#define CLK_ALWAYS_ON			24

Are these for shifting?

> +
> +#define ADDR_USE_PING_BUF		BIT(1)
> +
> +#define SD_EMMC_RXD_ERROR		BIT(0)
> +#define SD_EMMC_TXD_ERROR		BIT(1)
> +#define SD_EMMC_DESC_ERROR		BIT(2)
> +#define SD_EMMC_RESP_CRC_ERROR		BIT(3)
> +#define SD_EMMC_RESP_TIMEOUT_ERROR	BIT(4)
> +#define SD_EMMC_DESC_TIMEOUT_ERROR	BIT(5)
> +
> +#define CFG_BUS_WIDTH			0
> +#define CFG_BUS_WIDTH_MASK		(0x3 << 0)
> +#define CFG_BL_LEN			4
> +#define CFG_BL_LEN_MASK			(0xf << 4)
> +#define CFG_RESP_TIMEOUT		8
> +#define CFG_RESP_TIMEOUT_MASK		(0xf << 8)
> +#define CFG_RC_CC			12
> +#define CFG_RC_CC_MASK			(0xf << 12)
> +
> +#define STATUS_RXD_ERR_MASK		0xff
> +#define STATUS_TXD_ERR			BIT(8)
> +#define STATUS_DESC_ERR			BIT(9)
> +#define STATUS_RESP_ERR			BIT(10)
> +#define STATUS_RESP_TIMEOUT		BIT(11)
> +#define STATUS_DESC_TIMEOUT		BIT(12)
> +#define STATUS_END_OF_CHAIN		BIT(13)
> +
> +#define CMD_CFG_LENGTH_MASK		0x1ff
> +#define CMD_CFG_CMD_INDEX		24
> +#define CMD_CFG_BLOCK_MODE		BIT(9)
> +#define CMD_CFG_R1B			BIT(10)
> +#define CMD_CFG_END_OF_CHAIN		BIT(11)
> +#define CMD_CFG_NO_RESP			BIT(16)
> +#define CMD_CFG_DATA_IO			BIT(18)
> +#define CMD_CFG_DATA_WR			BIT(19)
> +#define CMD_CFG_RESP_NOCRC		BIT(20)
> +#define CMD_CFG_RESP_128		BIT(21)
> +#define CMD_CFG_OWNER			BIT(31)

Add the description for which register.
e,g
/* GCLOCK register */
#define ...

> +
> +struct meson_mmc_regs {
> +	uint32_t gclock;
> +	uint32_t gdelay;
> +	uint32_t gadjust;
> +	uint32_t reserved_0c;
> +	uint32_t gcalout;
> +	uint32_t reserved_14[11];
> +	uint32_t gstart;
> +	uint32_t gcfg;
> +	uint32_t gstatus;
> +	uint32_t girq_en;
> +	uint32_t gcmd_cfg;
> +	uint32_t gcmd_arg;
> +	uint32_t gcmd_dat;
> +	uint32_t gcmd_rsp0;
> +	uint32_t gcmd_rsp1;
> +	uint32_t gcmd_rsp2;
> +	uint32_t gcmd_rsp3;
> +	uint32_t reserved_6c;
> +	uint32_t gcurr_cfg;
> +	uint32_t gcurr_arg;
> +	uint32_t gcurr_dat;
> +	uint32_t gcurr_rsp;
> +	uint32_t gnext_cfg;
> +	uint32_t gnext_arg;
> +	uint32_t gnext_dat;
> +	uint32_t gnext_rsp;
> +	uint32_t grxd;
> +	uint32_t gtxd;
> +	uint32_t reserved_98[90];
> +	uint32_t gdesc[128];
> +	uint32_t gping[128];
> +	uint32_t gpong[128];
> +};

Don't use this style..Use the define.
It's difficult to debug..devloper don't know which offset is used before calculating.
And add the descriptions..

> +
> +struct meson_mmc_platdata {
> +	struct mmc_config cfg;
> +	struct meson_mmc_regs *sd_emmc_reg;
> +	char *w_buf;
> +};
> +
> +#endif
> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
> index 585aaf3..08ac9ba 100644
> --- a/drivers/mmc/Makefile
> +++ b/drivers/mmc/Makefile
> @@ -21,6 +21,7 @@ obj-$(CONFIG_FTSDC021) += ftsdc021_sdhci.o
>  obj-$(CONFIG_GENERIC_MMC) += mmc.o
>  obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
>  obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o
> +obj-$(CONFIG_MMC_MESON) += meson_mmc.o
>  obj-$(CONFIG_MMC_SPI) += mmc_spi.o
>  obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o
>  obj-$(CONFIG_MV_SDHCI) += mv_sdhci.o
> diff --git a/drivers/mmc/meson_mmc.c b/drivers/mmc/meson_mmc.c
> new file mode 100644
> index 0000000..af224ec
> --- /dev/null
> +++ b/drivers/mmc/meson_mmc.c
> @@ -0,0 +1,305 @@
> +/*
> + * (C) Copyright 2016 Carlo Caione <carlo@caione.org>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <fdtdec.h>
> +#include <malloc.h>
> +#include <mmc.h>
> +#include <asm/io.h>
> +#include <asm/arch/sd_emmc.h>
> +#include <dm/device.h>
> +
> +static void meson_mmc_config_clock(struct mmc *mmc,
> +				   struct meson_mmc_regs *meson_mmc_reg)
> +{
> +	uint32_t meson_mmc_clk = 0;
> +	unsigned int clk, clk_src, clk_div;
> +
> +	if (mmc->clock > 12000000) {
> +		clk = SD_EMMC_CLKSRC_DIV2;
> +		clk_src = 1;
> +	} else {
> +		clk = SD_EMMC_CLKSRC_24M;
> +		clk_src = 0;
> +	}
> +	clk_div = clk / mmc->clock;
> +
> +	if (mmc->clock < mmc->cfg->f_min)
> +		mmc->clock = mmc->cfg->f_min;
> +	if (mmc->clock > mmc->cfg->f_max)
> +		mmc->clock = mmc->cfg->f_max;

In mmc_set_clock(), mmc->clock is already assigned..
Doesn't need this.

> +
> +	/* Keep the clock always on */
> +	meson_mmc_clk |= (1 << CLK_ALWAYS_ON);
> +
> +	/* 180 phase */
> +	meson_mmc_clk |= (2 << CLK_CO_PHASE);

Don't use the magic number, what do 1 and 2 mean?

> +
> +	/* clock settings */
> +	meson_mmc_clk |= (clk_src << CLK_SRC);
> +	meson_mmc_clk |= (clk_div << CLK_DIV);

How many bits do use for clk_div? bit[0:11]?

> +
> +	writel(meson_mmc_clk, &meson_mmc_reg->gclock);
> +}
> +
> +static void meson_mmc_set_ios(struct mmc *mmc)
> +{
> +	struct meson_mmc_platdata *pdata;
> +	struct meson_mmc_regs *meson_mmc_reg;
> +	unsigned int bus_width;
> +	uint32_t meson_mmc_cfg = 0;
> +
> +	pdata = mmc->priv;
> +	meson_mmc_reg = pdata->sd_emmc_reg;
> +
> +	meson_mmc_config_clock(mmc, meson_mmc_reg);
> +
> +	meson_mmc_cfg = readl(&meson_mmc_reg->gcfg);
> +
> +	if (mmc->bus_width == 1)
> +		bus_width = 0;
> +	else
> +		bus_width = mmc->bus_width / 4;
> +
> +	/* 1-bit mode */
> +	meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK;
> +	meson_mmc_cfg |= (bus_width << CFG_BUS_WIDTH);
> +
> +	/* 512 bytes block lenght */
> +	meson_mmc_cfg &= ~CFG_BL_LEN_MASK;
> +	meson_mmc_cfg |= (9 << CFG_BL_LEN);
> +
> +	/* Response timeout 256 clk */
> +	meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK;
> +	meson_mmc_cfg |= (7 << CFG_RESP_TIMEOUT);
> +
> +	/* Command-command gap 1024 clk */
> +	meson_mmc_cfg &= ~CFG_RC_CC_MASK;
> +	meson_mmc_cfg |= (4 << CFG_RC_CC);

Ditto...what are 9, 7, 4?
Don't use the magic number in entire your codes.

> +
> +	writel(meson_mmc_cfg, &meson_mmc_reg->gcfg);
> +
> +	return;

not needs "return"

> +}
> +
> +static int meson_mmc_init(struct mmc *mmc)
> +{
> +	mmc_set_clock(mmc, 400000);
> +
> +	return 0;
> +}
> +
> +static void meson_mmc_setup_cmd(struct mmc *mmc, struct mmc_data *data,
> +				struct mmc_cmd *cmd,
> +				struct meson_mmc_regs *meson_mmc_reg)
> +{
> +	uint32_t meson_mmc_cmd = 0;
> +
> +	meson_mmc_cmd = ((0x80 | cmd->cmdidx) << CMD_CFG_CMD_INDEX);
> +
> +	if (cmd->resp_type & MMC_RSP_PRESENT) {
> +		if (cmd->resp_type & MMC_RSP_136)
> +			meson_mmc_cmd |= CMD_CFG_RESP_128;
> +
> +		if (cmd->resp_type & MMC_RSP_BUSY)
> +			meson_mmc_cmd |= CMD_CFG_R1B;

There is no case with MMC_RSP_136 and MMC_RSP_BUSY together.

> +
> +		if (!(cmd->resp_type & MMC_RSP_CRC))
> +			meson_mmc_cmd |= CMD_CFG_RESP_NOCRC;
> +	} else {
> +		meson_mmc_cmd |= CMD_CFG_NO_RESP;
> +	}
> +
> +	if (data) {
> +		meson_mmc_cmd |= CMD_CFG_DATA_IO;
> +
> +		if (data->flags == MMC_DATA_WRITE)
> +			meson_mmc_cmd |= CMD_CFG_DATA_WR;
> +
> +		if (data->blocks > 1) {
> +			meson_mmc_cmd |= CMD_CFG_BLOCK_MODE;
> +			meson_mmc_cmd |= data->blocks;
> +		} else {
> +			meson_mmc_cmd |= (data->blocksize & CMD_CFG_LENGTH_MASK);
> +		}
> +	}
> +
> +	meson_mmc_cmd |= CMD_CFG_OWNER;
> +	meson_mmc_cmd |= CMD_CFG_END_OF_CHAIN;
> +
> +	writel(meson_mmc_cmd, &meson_mmc_reg->gcmd_cfg);
> +
> +	return;
> +}
> +
> +static void meson_mmc_setup_addr(struct mmc *mmc, struct mmc_data *data,
> +				 struct meson_mmc_regs *meson_mmc_reg)
> +{
> +	struct meson_mmc_platdata *pdata;
> +	unsigned int data_size = 0;
> +	uint32_t meson_mmc_data_addr = 0;
> +
> +	pdata = mmc->priv;
> +
> +	if (data) {
> +		data_size = data->blocks * data->blocksize;
> +
> +		if (data->flags == MMC_DATA_READ) {
> +			if (data_size < 0x200) {
> +				meson_mmc_data_addr = (ulong) meson_mmc_reg->gping;
> +				meson_mmc_data_addr |= ADDR_USE_PING_BUF;
> +			} else {
> +				invalidate_dcache_range((ulong) data->dest,
> +							(ulong) (data->dest + data_size));
> +				meson_mmc_data_addr = (ulong) data->dest;
> +			}
> +		}
> +
> +		if (data->flags == MMC_DATA_WRITE) {

data->flags is only two..MMC_DATA_WRITE ..otherwise MMC_DATA_READ.

> +			pdata->w_buf = calloc(data_size, sizeof(char));
> +			memcpy(pdata->w_buf, data->src, data_size);
> +			flush_dcache_range((ulong) pdata->w_buf,
> +					   (ulong) (pdata->w_buf + data_size));
> +			meson_mmc_data_addr = (ulong) pdata->w_buf;
> +		}
> +	}
> +
> +	writel(meson_mmc_data_addr, &meson_mmc_reg->gcmd_dat);
> +
> +	return;
> +}
> +
> +static void meson_mmc_read_response(struct mmc *mmc, struct mmc_data *data,
> +				    struct mmc_cmd *cmd,
> +				    struct meson_mmc_regs *meson_mmc_reg)
> +{
> +	unsigned int data_size = 0;
> +
> +	if (data) {
> +		data_size = data->blocks * data->blocksize;
> +		if ((data_size < 0x200) && (data->flags == MMC_DATA_READ))
> +			memcpy(data->dest, (const void *)meson_mmc_reg->gping, data_size);
> +	}
> +
> +	if (cmd->resp_type & MMC_RSP_136) {
> +		cmd->response[0] = readl(&meson_mmc_reg->gcmd_rsp3);
> +		cmd->response[1] = readl(&meson_mmc_reg->gcmd_rsp2);
> +		cmd->response[2] = readl(&meson_mmc_reg->gcmd_rsp1);
> +		cmd->response[3] = readl(&meson_mmc_reg->gcmd_rsp0);
> +	} else {
> +		cmd->response[0] = readl(&meson_mmc_reg->gcmd_rsp0);
> +	}
> +}
> +
> +static int meson_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
> +			      struct mmc_data *data)
> +{
> +	struct meson_mmc_platdata *pdata;
> +	struct meson_mmc_regs *meson_mmc_reg;
> +	uint32_t meson_mmc_irq = 0;
> +	int ret = 0;
> +
> +	pdata = mmc->priv;
> +	meson_mmc_reg = pdata->sd_emmc_reg;
> +
> +	meson_mmc_setup_cmd(mmc, data, cmd, meson_mmc_reg);
> +	meson_mmc_setup_addr(mmc, data, meson_mmc_reg);
> +
> +	writel(SD_IRQ_ALL, &meson_mmc_reg->gstatus);
> +	writel(cmd->cmdarg, &meson_mmc_reg->gcmd_arg);
> +
> +	while (1) {
> +		meson_mmc_irq = readl(&meson_mmc_reg->gstatus);
> +		if (meson_mmc_irq & STATUS_END_OF_CHAIN)
> +			break;
> +	}

I don't like this style...potential infinte loop.

> +
> +	if (meson_mmc_irq & STATUS_RXD_ERR_MASK)
> +		ret |= SD_EMMC_RXD_ERROR;
> +	if (meson_mmc_irq & STATUS_TXD_ERR)
> +		ret |= SD_EMMC_TXD_ERROR;
> +	if (meson_mmc_irq & STATUS_DESC_ERR)
> +		ret |= SD_EMMC_DESC_ERROR;
> +	if (meson_mmc_irq & STATUS_RESP_ERR)
> +		ret |= SD_EMMC_RESP_CRC_ERROR;
> +	if (meson_mmc_irq & STATUS_RESP_TIMEOUT)
> +		ret |= SD_EMMC_RESP_TIMEOUT_ERROR;
> +	if (meson_mmc_irq & STATUS_DESC_TIMEOUT)
> +		ret |= SD_EMMC_DESC_TIMEOUT_ERROR;

What are these ret values? Do you use the your specific error values?

> +
> +	meson_mmc_read_response(mmc, data, cmd, meson_mmc_reg);
> +
> +	if (data && data->flags == MMC_DATA_WRITE)
> +		free(pdata->w_buf);
> +
> +	if (ret) {
> +		if (meson_mmc_irq & STATUS_RESP_TIMEOUT)
> +			return TIMEOUT;

Strange this..why return at here...not above?

Best Regards,
Jaehoon Chung

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct mmc_ops meson_mmc_ops = {
> +	.send_cmd	= meson_mmc_send_cmd,
> +	.set_ios	= meson_mmc_set_ios,
> +	.init		= meson_mmc_init,
> +};
> +
> +static int meson_mmc_ofdata_to_platdata(struct udevice *dev)
> +{
> +	struct meson_mmc_platdata *pdata = dev->platdata;
> +	fdt_addr_t addr;
> +
> +	addr = dev_get_addr(dev);
> +	if (addr == FDT_ADDR_T_NONE)
> +		return -EINVAL;
> +
> +	pdata->sd_emmc_reg = (struct meson_mmc_regs *)addr;
> +
> +	return 0;
> +}
> +
> +static int meson_mmc_probe(struct udevice *dev)
> +{
> +	struct meson_mmc_platdata *pdata = dev->platdata;
> +	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
> +	struct mmc *mmc;
> +	struct mmc_config *cfg;
> +
> +	cfg = &pdata->cfg;
> +	cfg->ops = &meson_mmc_ops;
> +
> +	cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 |
> +			MMC_VDD_31_32 | MMC_VDD_165_195;
> +	cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT |
> +			 MMC_MODE_HS_52MHz | MMC_MODE_HS;
> +	cfg->f_min = 400000;
> +	cfg->f_max = 50000000;
> +	cfg->b_max = 256;
> +
> +	mmc = mmc_create(cfg, pdata);
> +	if (!mmc)
> +		return -ENOMEM;
> +
> +	upriv->mmc = mmc;
> +	return 0;
> +}
> +
> +static const struct udevice_id meson_mmc_match[] = {
> +	{ .compatible = "amlogic,meson-mmc" },
> +	{ /* sentinel */ }
> +};
> +
> +U_BOOT_DRIVER(meson_mmc) = {
> +	.name = "meson_mmc",
> +	.id = UCLASS_MMC,
> +	.of_match = meson_mmc_match,
> +	.probe = meson_mmc_probe,
> +	.ofdata_to_platdata = meson_mmc_ofdata_to_platdata,
> +	.platdata_auto_alloc_size = sizeof(struct meson_mmc_platdata),
> +};
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot,1/2] mmc: Add Amlogic Meson driver
@ 2016-08-04  6:48     ` Jaehoon Chung
  0 siblings, 0 replies; 28+ messages in thread
From: Jaehoon Chung @ 2016-08-04  6:48 UTC (permalink / raw)
  To: linus-amlogic

Hi Carlo

On 05/12/2016 09:41 PM, Carlo Caione wrote:
> From: Carlo Caione <carlo@endlessm.com>
> 
> This is a port / rewrite of the Amlogic driver shipped whithin the
> Amlogic SDK for the Meson GXBaby (S905) SoC.

s/whithin/within

And If you want to apply this patch, could you resend the patch on lates u-boot?

> 
> Signed-off-by: Carlo Caione <carlo@endlessm.com>
> ---
>  arch/arm/include/asm/arch-meson/sd_emmc.h | 109 +++++++++++
>  drivers/mmc/Makefile                      |   1 +
>  drivers/mmc/meson_mmc.c                   | 305 ++++++++++++++++++++++++++++++
>  3 files changed, 415 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h
>  create mode 100644 drivers/mmc/meson_mmc.c
> 
> diff --git a/arch/arm/include/asm/arch-meson/sd_emmc.h b/arch/arm/include/asm/arch-meson/sd_emmc.h
> new file mode 100644
> index 0000000..6781dca
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-meson/sd_emmc.h
> @@ -0,0 +1,109 @@
> +/*
> + * (C) Copyright 2016 Carlo Caione <carlo@caione.org>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#ifndef __SD_EMMC_H__
> +#define __SD_EMMC_H__
> +
> +#include <mmc.h>
> +
> +#define SDIO_PORT_A			0
> +#define SDIO_PORT_B			1
> +#define SDIO_PORT_C			2
> +
> +#define SD_EMMC_BASE_A			0xd0070000
> +#define SD_EMMC_BASE_B			0xd0072000
> +#define SD_EMMC_BASE_C			0xd0074000
> +
> +#define SD_IRQ_ALL			0x3fff
> +
> +#define SD_EMMC_CLKSRC_24M		24000000
> +#define SD_EMMC_CLKSRC_DIV2		1000000000

Is it right? 1GHz?

> +
> +#define CLK_DIV				0
> +#define CLK_SRC				6
> +#define CLK_CO_PHASE			8
> +#define CLK_ALWAYS_ON			24

Are these for shifting?

> +
> +#define ADDR_USE_PING_BUF		BIT(1)
> +
> +#define SD_EMMC_RXD_ERROR		BIT(0)
> +#define SD_EMMC_TXD_ERROR		BIT(1)
> +#define SD_EMMC_DESC_ERROR		BIT(2)
> +#define SD_EMMC_RESP_CRC_ERROR		BIT(3)
> +#define SD_EMMC_RESP_TIMEOUT_ERROR	BIT(4)
> +#define SD_EMMC_DESC_TIMEOUT_ERROR	BIT(5)
> +
> +#define CFG_BUS_WIDTH			0
> +#define CFG_BUS_WIDTH_MASK		(0x3 << 0)
> +#define CFG_BL_LEN			4
> +#define CFG_BL_LEN_MASK			(0xf << 4)
> +#define CFG_RESP_TIMEOUT		8
> +#define CFG_RESP_TIMEOUT_MASK		(0xf << 8)
> +#define CFG_RC_CC			12
> +#define CFG_RC_CC_MASK			(0xf << 12)
> +
> +#define STATUS_RXD_ERR_MASK		0xff
> +#define STATUS_TXD_ERR			BIT(8)
> +#define STATUS_DESC_ERR			BIT(9)
> +#define STATUS_RESP_ERR			BIT(10)
> +#define STATUS_RESP_TIMEOUT		BIT(11)
> +#define STATUS_DESC_TIMEOUT		BIT(12)
> +#define STATUS_END_OF_CHAIN		BIT(13)
> +
> +#define CMD_CFG_LENGTH_MASK		0x1ff
> +#define CMD_CFG_CMD_INDEX		24
> +#define CMD_CFG_BLOCK_MODE		BIT(9)
> +#define CMD_CFG_R1B			BIT(10)
> +#define CMD_CFG_END_OF_CHAIN		BIT(11)
> +#define CMD_CFG_NO_RESP			BIT(16)
> +#define CMD_CFG_DATA_IO			BIT(18)
> +#define CMD_CFG_DATA_WR			BIT(19)
> +#define CMD_CFG_RESP_NOCRC		BIT(20)
> +#define CMD_CFG_RESP_128		BIT(21)
> +#define CMD_CFG_OWNER			BIT(31)

Add the description for which register.
e,g
/* GCLOCK register */
#define ...

> +
> +struct meson_mmc_regs {
> +	uint32_t gclock;
> +	uint32_t gdelay;
> +	uint32_t gadjust;
> +	uint32_t reserved_0c;
> +	uint32_t gcalout;
> +	uint32_t reserved_14[11];
> +	uint32_t gstart;
> +	uint32_t gcfg;
> +	uint32_t gstatus;
> +	uint32_t girq_en;
> +	uint32_t gcmd_cfg;
> +	uint32_t gcmd_arg;
> +	uint32_t gcmd_dat;
> +	uint32_t gcmd_rsp0;
> +	uint32_t gcmd_rsp1;
> +	uint32_t gcmd_rsp2;
> +	uint32_t gcmd_rsp3;
> +	uint32_t reserved_6c;
> +	uint32_t gcurr_cfg;
> +	uint32_t gcurr_arg;
> +	uint32_t gcurr_dat;
> +	uint32_t gcurr_rsp;
> +	uint32_t gnext_cfg;
> +	uint32_t gnext_arg;
> +	uint32_t gnext_dat;
> +	uint32_t gnext_rsp;
> +	uint32_t grxd;
> +	uint32_t gtxd;
> +	uint32_t reserved_98[90];
> +	uint32_t gdesc[128];
> +	uint32_t gping[128];
> +	uint32_t gpong[128];
> +};

Don't use this style..Use the define.
It's difficult to debug..devloper don't know which offset is used before calculating.
And add the descriptions..

> +
> +struct meson_mmc_platdata {
> +	struct mmc_config cfg;
> +	struct meson_mmc_regs *sd_emmc_reg;
> +	char *w_buf;
> +};
> +
> +#endif
> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
> index 585aaf3..08ac9ba 100644
> --- a/drivers/mmc/Makefile
> +++ b/drivers/mmc/Makefile
> @@ -21,6 +21,7 @@ obj-$(CONFIG_FTSDC021) += ftsdc021_sdhci.o
>  obj-$(CONFIG_GENERIC_MMC) += mmc.o
>  obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
>  obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o
> +obj-$(CONFIG_MMC_MESON) += meson_mmc.o
>  obj-$(CONFIG_MMC_SPI) += mmc_spi.o
>  obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o
>  obj-$(CONFIG_MV_SDHCI) += mv_sdhci.o
> diff --git a/drivers/mmc/meson_mmc.c b/drivers/mmc/meson_mmc.c
> new file mode 100644
> index 0000000..af224ec
> --- /dev/null
> +++ b/drivers/mmc/meson_mmc.c
> @@ -0,0 +1,305 @@
> +/*
> + * (C) Copyright 2016 Carlo Caione <carlo@caione.org>
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <fdtdec.h>
> +#include <malloc.h>
> +#include <mmc.h>
> +#include <asm/io.h>
> +#include <asm/arch/sd_emmc.h>
> +#include <dm/device.h>
> +
> +static void meson_mmc_config_clock(struct mmc *mmc,
> +				   struct meson_mmc_regs *meson_mmc_reg)
> +{
> +	uint32_t meson_mmc_clk = 0;
> +	unsigned int clk, clk_src, clk_div;
> +
> +	if (mmc->clock > 12000000) {
> +		clk = SD_EMMC_CLKSRC_DIV2;
> +		clk_src = 1;
> +	} else {
> +		clk = SD_EMMC_CLKSRC_24M;
> +		clk_src = 0;
> +	}
> +	clk_div = clk / mmc->clock;
> +
> +	if (mmc->clock < mmc->cfg->f_min)
> +		mmc->clock = mmc->cfg->f_min;
> +	if (mmc->clock > mmc->cfg->f_max)
> +		mmc->clock = mmc->cfg->f_max;

In mmc_set_clock(), mmc->clock is already assigned..
Doesn't need this.

> +
> +	/* Keep the clock always on */
> +	meson_mmc_clk |= (1 << CLK_ALWAYS_ON);
> +
> +	/* 180 phase */
> +	meson_mmc_clk |= (2 << CLK_CO_PHASE);

Don't use the magic number, what do 1 and 2 mean?

> +
> +	/* clock settings */
> +	meson_mmc_clk |= (clk_src << CLK_SRC);
> +	meson_mmc_clk |= (clk_div << CLK_DIV);

How many bits do use for clk_div? bit[0:11]?

> +
> +	writel(meson_mmc_clk, &meson_mmc_reg->gclock);
> +}
> +
> +static void meson_mmc_set_ios(struct mmc *mmc)
> +{
> +	struct meson_mmc_platdata *pdata;
> +	struct meson_mmc_regs *meson_mmc_reg;
> +	unsigned int bus_width;
> +	uint32_t meson_mmc_cfg = 0;
> +
> +	pdata = mmc->priv;
> +	meson_mmc_reg = pdata->sd_emmc_reg;
> +
> +	meson_mmc_config_clock(mmc, meson_mmc_reg);
> +
> +	meson_mmc_cfg = readl(&meson_mmc_reg->gcfg);
> +
> +	if (mmc->bus_width == 1)
> +		bus_width = 0;
> +	else
> +		bus_width = mmc->bus_width / 4;
> +
> +	/* 1-bit mode */
> +	meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK;
> +	meson_mmc_cfg |= (bus_width << CFG_BUS_WIDTH);
> +
> +	/* 512 bytes block lenght */
> +	meson_mmc_cfg &= ~CFG_BL_LEN_MASK;
> +	meson_mmc_cfg |= (9 << CFG_BL_LEN);
> +
> +	/* Response timeout 256 clk */
> +	meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK;
> +	meson_mmc_cfg |= (7 << CFG_RESP_TIMEOUT);
> +
> +	/* Command-command gap 1024 clk */
> +	meson_mmc_cfg &= ~CFG_RC_CC_MASK;
> +	meson_mmc_cfg |= (4 << CFG_RC_CC);

Ditto...what are 9, 7, 4?
Don't use the magic number in entire your codes.

> +
> +	writel(meson_mmc_cfg, &meson_mmc_reg->gcfg);
> +
> +	return;

not needs "return"

> +}
> +
> +static int meson_mmc_init(struct mmc *mmc)
> +{
> +	mmc_set_clock(mmc, 400000);
> +
> +	return 0;
> +}
> +
> +static void meson_mmc_setup_cmd(struct mmc *mmc, struct mmc_data *data,
> +				struct mmc_cmd *cmd,
> +				struct meson_mmc_regs *meson_mmc_reg)
> +{
> +	uint32_t meson_mmc_cmd = 0;
> +
> +	meson_mmc_cmd = ((0x80 | cmd->cmdidx) << CMD_CFG_CMD_INDEX);
> +
> +	if (cmd->resp_type & MMC_RSP_PRESENT) {
> +		if (cmd->resp_type & MMC_RSP_136)
> +			meson_mmc_cmd |= CMD_CFG_RESP_128;
> +
> +		if (cmd->resp_type & MMC_RSP_BUSY)
> +			meson_mmc_cmd |= CMD_CFG_R1B;

There is no case with MMC_RSP_136 and MMC_RSP_BUSY together.

> +
> +		if (!(cmd->resp_type & MMC_RSP_CRC))
> +			meson_mmc_cmd |= CMD_CFG_RESP_NOCRC;
> +	} else {
> +		meson_mmc_cmd |= CMD_CFG_NO_RESP;
> +	}
> +
> +	if (data) {
> +		meson_mmc_cmd |= CMD_CFG_DATA_IO;
> +
> +		if (data->flags == MMC_DATA_WRITE)
> +			meson_mmc_cmd |= CMD_CFG_DATA_WR;
> +
> +		if (data->blocks > 1) {
> +			meson_mmc_cmd |= CMD_CFG_BLOCK_MODE;
> +			meson_mmc_cmd |= data->blocks;
> +		} else {
> +			meson_mmc_cmd |= (data->blocksize & CMD_CFG_LENGTH_MASK);
> +		}
> +	}
> +
> +	meson_mmc_cmd |= CMD_CFG_OWNER;
> +	meson_mmc_cmd |= CMD_CFG_END_OF_CHAIN;
> +
> +	writel(meson_mmc_cmd, &meson_mmc_reg->gcmd_cfg);
> +
> +	return;
> +}
> +
> +static void meson_mmc_setup_addr(struct mmc *mmc, struct mmc_data *data,
> +				 struct meson_mmc_regs *meson_mmc_reg)
> +{
> +	struct meson_mmc_platdata *pdata;
> +	unsigned int data_size = 0;
> +	uint32_t meson_mmc_data_addr = 0;
> +
> +	pdata = mmc->priv;
> +
> +	if (data) {
> +		data_size = data->blocks * data->blocksize;
> +
> +		if (data->flags == MMC_DATA_READ) {
> +			if (data_size < 0x200) {
> +				meson_mmc_data_addr = (ulong) meson_mmc_reg->gping;
> +				meson_mmc_data_addr |= ADDR_USE_PING_BUF;
> +			} else {
> +				invalidate_dcache_range((ulong) data->dest,
> +							(ulong) (data->dest + data_size));
> +				meson_mmc_data_addr = (ulong) data->dest;
> +			}
> +		}
> +
> +		if (data->flags == MMC_DATA_WRITE) {

data->flags is only two..MMC_DATA_WRITE ..otherwise MMC_DATA_READ.

> +			pdata->w_buf = calloc(data_size, sizeof(char));
> +			memcpy(pdata->w_buf, data->src, data_size);
> +			flush_dcache_range((ulong) pdata->w_buf,
> +					   (ulong) (pdata->w_buf + data_size));
> +			meson_mmc_data_addr = (ulong) pdata->w_buf;
> +		}
> +	}
> +
> +	writel(meson_mmc_data_addr, &meson_mmc_reg->gcmd_dat);
> +
> +	return;
> +}
> +
> +static void meson_mmc_read_response(struct mmc *mmc, struct mmc_data *data,
> +				    struct mmc_cmd *cmd,
> +				    struct meson_mmc_regs *meson_mmc_reg)
> +{
> +	unsigned int data_size = 0;
> +
> +	if (data) {
> +		data_size = data->blocks * data->blocksize;
> +		if ((data_size < 0x200) && (data->flags == MMC_DATA_READ))
> +			memcpy(data->dest, (const void *)meson_mmc_reg->gping, data_size);
> +	}
> +
> +	if (cmd->resp_type & MMC_RSP_136) {
> +		cmd->response[0] = readl(&meson_mmc_reg->gcmd_rsp3);
> +		cmd->response[1] = readl(&meson_mmc_reg->gcmd_rsp2);
> +		cmd->response[2] = readl(&meson_mmc_reg->gcmd_rsp1);
> +		cmd->response[3] = readl(&meson_mmc_reg->gcmd_rsp0);
> +	} else {
> +		cmd->response[0] = readl(&meson_mmc_reg->gcmd_rsp0);
> +	}
> +}
> +
> +static int meson_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
> +			      struct mmc_data *data)
> +{
> +	struct meson_mmc_platdata *pdata;
> +	struct meson_mmc_regs *meson_mmc_reg;
> +	uint32_t meson_mmc_irq = 0;
> +	int ret = 0;
> +
> +	pdata = mmc->priv;
> +	meson_mmc_reg = pdata->sd_emmc_reg;
> +
> +	meson_mmc_setup_cmd(mmc, data, cmd, meson_mmc_reg);
> +	meson_mmc_setup_addr(mmc, data, meson_mmc_reg);
> +
> +	writel(SD_IRQ_ALL, &meson_mmc_reg->gstatus);
> +	writel(cmd->cmdarg, &meson_mmc_reg->gcmd_arg);
> +
> +	while (1) {
> +		meson_mmc_irq = readl(&meson_mmc_reg->gstatus);
> +		if (meson_mmc_irq & STATUS_END_OF_CHAIN)
> +			break;
> +	}

I don't like this style...potential infinte loop.

> +
> +	if (meson_mmc_irq & STATUS_RXD_ERR_MASK)
> +		ret |= SD_EMMC_RXD_ERROR;
> +	if (meson_mmc_irq & STATUS_TXD_ERR)
> +		ret |= SD_EMMC_TXD_ERROR;
> +	if (meson_mmc_irq & STATUS_DESC_ERR)
> +		ret |= SD_EMMC_DESC_ERROR;
> +	if (meson_mmc_irq & STATUS_RESP_ERR)
> +		ret |= SD_EMMC_RESP_CRC_ERROR;
> +	if (meson_mmc_irq & STATUS_RESP_TIMEOUT)
> +		ret |= SD_EMMC_RESP_TIMEOUT_ERROR;
> +	if (meson_mmc_irq & STATUS_DESC_TIMEOUT)
> +		ret |= SD_EMMC_DESC_TIMEOUT_ERROR;

What are these ret values? Do you use the your specific error values?

> +
> +	meson_mmc_read_response(mmc, data, cmd, meson_mmc_reg);
> +
> +	if (data && data->flags == MMC_DATA_WRITE)
> +		free(pdata->w_buf);
> +
> +	if (ret) {
> +		if (meson_mmc_irq & STATUS_RESP_TIMEOUT)
> +			return TIMEOUT;

Strange this..why return at here...not above?

Best Regards,
Jaehoon Chung

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct mmc_ops meson_mmc_ops = {
> +	.send_cmd	= meson_mmc_send_cmd,
> +	.set_ios	= meson_mmc_set_ios,
> +	.init		= meson_mmc_init,
> +};
> +
> +static int meson_mmc_ofdata_to_platdata(struct udevice *dev)
> +{
> +	struct meson_mmc_platdata *pdata = dev->platdata;
> +	fdt_addr_t addr;
> +
> +	addr = dev_get_addr(dev);
> +	if (addr == FDT_ADDR_T_NONE)
> +		return -EINVAL;
> +
> +	pdata->sd_emmc_reg = (struct meson_mmc_regs *)addr;
> +
> +	return 0;
> +}
> +
> +static int meson_mmc_probe(struct udevice *dev)
> +{
> +	struct meson_mmc_platdata *pdata = dev->platdata;
> +	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
> +	struct mmc *mmc;
> +	struct mmc_config *cfg;
> +
> +	cfg = &pdata->cfg;
> +	cfg->ops = &meson_mmc_ops;
> +
> +	cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 |
> +			MMC_VDD_31_32 | MMC_VDD_165_195;
> +	cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT |
> +			 MMC_MODE_HS_52MHz | MMC_MODE_HS;
> +	cfg->f_min = 400000;
> +	cfg->f_max = 50000000;
> +	cfg->b_max = 256;
> +
> +	mmc = mmc_create(cfg, pdata);
> +	if (!mmc)
> +		return -ENOMEM;
> +
> +	upriv->mmc = mmc;
> +	return 0;
> +}
> +
> +static const struct udevice_id meson_mmc_match[] = {
> +	{ .compatible = "amlogic,meson-mmc" },
> +	{ /* sentinel */ }
> +};
> +
> +U_BOOT_DRIVER(meson_mmc) = {
> +	.name = "meson_mmc",
> +	.id = UCLASS_MMC,
> +	.of_match = meson_mmc_match,
> +	.probe = meson_mmc_probe,
> +	.ofdata_to_platdata = meson_mmc_ofdata_to_platdata,
> +	.platdata_auto_alloc_size = sizeof(struct meson_mmc_platdata),
> +};
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 1/2] mmc: Add Amlogic Meson driver
  2016-05-13 13:53       ` Carlo Caione
@ 2016-08-07 15:49         ` Andreas Färber
  -1 siblings, 0 replies; 28+ messages in thread
From: Andreas Färber @ 2016-08-07 15:49 UTC (permalink / raw)
  To: u-boot

Am 13.05.2016 um 15:53 schrieb Carlo Caione:
> [...] but since it is really unlikely that we will
> ever see a U-Boot port for the Meson8b I stuck with that.

Why do you consider that so unlikely? Please don't make such assumptions
for design decisions.

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [U-Boot] [PATCH 1/2] mmc: Add Amlogic Meson driver
@ 2016-08-07 15:49         ` Andreas Färber
  0 siblings, 0 replies; 28+ messages in thread
From: Andreas Färber @ 2016-08-07 15:49 UTC (permalink / raw)
  To: linus-amlogic

Am 13.05.2016 um 15:53 schrieb Carlo Caione:
> [...] but since it is really unlikely that we will
> ever see a U-Boot port for the Meson8b I stuck with that.

Why do you consider that so unlikely? Please don't make such assumptions
for design decisions.

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2016-08-07 15:49 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-12 12:41 [U-Boot] [PATCH 0/2] Add support for Amlogic Meson MMC controller Carlo Caione
2016-05-12 12:41 ` Carlo Caione
2016-05-12 12:41 ` [U-Boot] [PATCH 1/2] mmc: Add Amlogic Meson driver Carlo Caione
2016-05-12 12:41   ` Carlo Caione
2016-05-13 13:46   ` [U-Boot] " Kevin Hilman
2016-05-13 13:46     ` Kevin Hilman
2016-05-13 13:53     ` [U-Boot] " Carlo Caione
2016-05-13 13:53       ` Carlo Caione
2016-05-13 16:07       ` [U-Boot] " Kevin Hilman
2016-05-13 16:07         ` Kevin Hilman
2016-08-07 15:49       ` [U-Boot] " Andreas Färber
2016-08-07 15:49         ` Andreas Färber
2016-08-04  6:48   ` [U-Boot] [U-Boot,1/2] " Jaehoon Chung
2016-08-04  6:48     ` Jaehoon Chung
2016-05-12 12:41 ` [U-Boot] [PATCH 2/2] arm: amlogic: Enable MMC driver on Odroid-C2 Carlo Caione
2016-05-12 12:41   ` Carlo Caione
2016-05-20  4:51 ` [U-Boot] [PATCH 0/2] Add support for Amlogic Meson MMC controller Robert Gadsdon
2016-05-20  4:51   ` Robert Gadsdon
2016-05-20  6:27   ` [U-Boot] " Carlo Caione
2016-05-20  6:27     ` Carlo Caione
2016-05-20  8:07     ` [U-Boot] " Carlo Caione
2016-05-20  8:07       ` Carlo Caione
2016-05-20 18:58       ` [U-Boot] " Robert Gadsdon
2016-05-20 18:58         ` Robert Gadsdon
2016-05-20 19:34         ` [U-Boot] " Carlo Caione
2016-05-20 19:34           ` Carlo Caione
2016-05-21  2:28           ` [U-Boot] " Robert Gadsdon
2016-05-21  2:28             ` Robert Gadsdon

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.