From c5c1af21764d9423b45c1d03e835c4547a8bc5cb Mon Sep 17 00:00:00 2001
From: Chin Liang See <clsee@altera.com>
Date: Mon, 30 Dec 2013 18:26:14 -0600
Subject: [PATCH] socfpga/dwmmc: Adding DesignWare MMC driver support for
 SOCFPGA

To add the DesignWare MMC driver support for Altera SOCFPGA. It
required information such as clocks and bus width from platform
specific files (SOCFPGA handoff files)

Signed-off-by: Chin Liang See <clsee@altera.com>
Cc: Rajeshwari Shinde <rajeshwari.s@samsung.com>
Cc: Jaehoon Chung <jh80.chung@samsung.com>
Cc: Pantelis Antoniou <panto@antoniou-consulting.com>
Cc: Wolfgang Denk <wd@denx.de>
Acked-by: Pantelis Antoniou <panto@antoniou-consulting.com>
---
 arch/arm/include/asm/arch-socfpga/dwmmc.h     | 12 ++++
 .../include/asm/arch-socfpga/system_manager.h | 65 ++++++++++++++++++
 doc/README.socfpga                            | 53 +++++++++++++++
 drivers/mmc/Makefile                          |  1 +
 drivers/mmc/socfpga_dw_mmc.c                  | 68 +++++++++++++++++++
 5 files changed, 199 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-socfpga/dwmmc.h
 create mode 100644 doc/README.socfpga
 create mode 100644 drivers/mmc/socfpga_dw_mmc.c

diff --git a/arch/arm/include/asm/arch-socfpga/dwmmc.h b/arch/arm/include/asm/arch-socfpga/dwmmc.h
new file mode 100644
index 0000000000..945eb646ce
--- /dev/null
+++ b/arch/arm/include/asm/arch-socfpga/dwmmc.h
@@ -0,0 +1,12 @@
+/*
+ * (C) Copyright 2013 Altera Corporation <www.altera.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef	_SOCFPGA_DWMMC_H_
+#define	_SOCFPGA_DWMMC_H_
+
+extern int socfpga_dwmmc_init(u32 regbase, int bus_width, int index);
+
+#endif /* _SOCFPGA_SDMMC_H_ */
diff --git a/arch/arm/include/asm/arch-socfpga/system_manager.h b/arch/arm/include/asm/arch-socfpga/system_manager.h
index d965d25eff..838d21053e 100644
--- a/arch/arm/include/asm/arch-socfpga/system_manager.h
+++ b/arch/arm/include/asm/arch-socfpga/system_manager.h
@@ -19,4 +19,69 @@ extern unsigned long sys_mgr_init_table[CONFIG_HPS_PINMUX_NUM];
 
 #define CONFIG_SYSMGR_PINMUXGRP_OFFSET	(0x400)
 
+#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel)	\
+	((((drvsel) << 0) & 0x7) | (((smplsel) << 3) & 0x38))
+
+struct socfpga_system_manager {
+	u32	siliconid1;
+	u32	siliconid2;
+	u32	_pad_0x8_0xf[2];
+	u32	wddbg;
+	u32	bootinfo;
+	u32	hpsinfo;
+	u32	parityinj;
+	u32	fpgaintfgrp_gbl;
+	u32	fpgaintfgrp_indiv;
+	u32	fpgaintfgrp_module;
+	u32	_pad_0x2c_0x2f;
+	u32	scanmgrgrp_ctrl;
+	u32	_pad_0x34_0x3f[3];
+	u32	frzctrl_vioctrl;
+	u32	_pad_0x44_0x4f[3];
+	u32	frzctrl_hioctrl;
+	u32	frzctrl_src;
+	u32	frzctrl_hwctrl;
+	u32	_pad_0x5c_0x5f;
+	u32	emacgrp_ctrl;
+	u32	emacgrp_l3master;
+	u32	_pad_0x68_0x6f[2];
+	u32	dmagrp_ctrl;
+	u32	dmagrp_persecurity;
+	u32	_pad_0x78_0x7f[2];
+	u32	iswgrp_handoff[8];
+	u32	_pad_0xa0_0xbf[8];
+	u32	romcodegrp_ctrl;
+	u32	romcodegrp_cpu1startaddr;
+	u32	romcodegrp_initswstate;
+	u32	romcodegrp_initswlastld;
+	u32	romcodegrp_bootromswstate;
+	u32	__pad_0xd4_0xdf[3];
+	u32	romcodegrp_warmramgrp_enable;
+	u32	romcodegrp_warmramgrp_datastart;
+	u32	romcodegrp_warmramgrp_length;
+	u32	romcodegrp_warmramgrp_execution;
+	u32	romcodegrp_warmramgrp_crc;
+	u32	__pad_0xf4_0xff[3];
+	u32	romhwgrp_ctrl;
+	u32	_pad_0x104_0x107;
+	u32	sdmmcgrp_ctrl;
+	u32	sdmmcgrp_l3master;
+	u32	nandgrp_bootstrap;
+	u32	nandgrp_l3master;
+	u32	usbgrp_l3master;
+	u32	_pad_0x11c_0x13f[9];
+	u32	eccgrp_l2;
+	u32	eccgrp_ocram;
+	u32	eccgrp_usb0;
+	u32	eccgrp_usb1;
+	u32	eccgrp_emac0;
+	u32	eccgrp_emac1;
+	u32	eccgrp_dma;
+	u32	eccgrp_can0;
+	u32	eccgrp_can1;
+	u32	eccgrp_nand;
+	u32	eccgrp_qspi;
+	u32	eccgrp_sdmmc;
+};
+
 #endif /* _SYSTEM_MANAGER_H_ */
diff --git a/doc/README.socfpga b/doc/README.socfpga
new file mode 100644
index 0000000000..cfcbbfe379
--- /dev/null
+++ b/doc/README.socfpga
@@ -0,0 +1,53 @@
+
+--------------------------------------------
+SOCFPGA Documentation for U-Boot and SPL
+--------------------------------------------
+
+This README is about U-Boot and SPL support for Altera's ARM Cortex-A9MPCore
+based SOCFPGA. To know more about the hardware itself, please refer to
+www.altera.com.
+
+
+--------------------------------------------
+socfpga_dw_mmc
+--------------------------------------------
+Here are macro and detailed configuration required to enable DesignWare SDMMC
+controller support within SOCFPGA
+
+#define CONFIG_MMC
+-> To enable the SD MMC framework support
+
+#define CONFIG_SDMMC_BASE		(SOCFPGA_SDMMC_ADDRESS)
+-> The base address of CSR register for DesignWare SDMMC controller
+
+#define CONFIG_GENERIC_MMC
+-> Enable the generic MMC driver
+
+#define CONFIG_SYS_MMC_MAX_BLK_COUNT	256
+-> Using smaller max blk cnt to avoid flooding the limited stack in OCRAM
+
+#define CONFIG_DWMMC
+-> Enable the common DesignWare SDMMC controller framework
+
+#define CONFIG_SOCFPGA_DWMMC
+-> Enable the SOCFPGA specific driver for DesignWare SDMMC controller
+
+#define CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH		1024
+-> The FIFO depth for SOCFPGA DesignWare SDMMC controller
+
+#define CONFIG_SOCFPGA_DWMMC_DRVSEL	3
+-> Phase-shifted clock of sdmmc_clk for controller to drive command and data to
+the card to meet hold time requirements. SD clock is running at 50MHz and
+drvsel is set to shift 135 degrees (3 * 45 degrees). With that, the hold time
+is 135 / 360 * 20ns = 7.5ns.
+
+#define CONFIG_SOCFPGA_DWMMC_SMPSEL	0
+-> Phase-shifted clock of sdmmc_clk used to sample the command and data from
+the card
+
+#define CONFIG_SOCFPGA_DWMMC_BUS_WIDTH	4
+-> Bus width of data line which either 1, 4 or 8 and based on board routing.
+
+#define CONFIG_SOCFPGA_DWMMC_BUS_HZ	50000000
+-> The clock rate to controller. Do note the controller have a wrapper which
+divide the clock from PLL by 4.
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 1ed26cab34..e793ed994e 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
 obj-$(CONFIG_DWMMC) += dw_mmc.o
 obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
 obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
+obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
 else
diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
new file mode 100644
index 0000000000..bc53a5da27
--- /dev/null
+++ b/drivers/mmc/socfpga_dw_mmc.c
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2013 Altera Corporation <www.altera.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <dwmmc.h>
+#include <asm/arch/dwmmc.h>
+#include <asm/arch/clock_manager.h>
+#include <asm/arch/system_manager.h>
+
+static const struct socfpga_clock_manager *clock_manager_base =
+		(void *)SOCFPGA_CLKMGR_ADDRESS;
+static const struct socfpga_system_manager *system_manager_base =
+		(void *)SOCFPGA_SYSMGR_ADDRESS;
+
+static char *SOCFPGA_NAME = "SOCFPGA DWMMC";
+
+static void socfpga_dwmci_clksel(struct dwmci_host *host)
+{
+	unsigned int drvsel;
+	unsigned int smplsel;
+
+	/* Disable SDMMC clock. */
+	clrbits_le32(&clock_manager_base->per_pll_en,
+		CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
+
+	/* Configures drv_sel and smpl_sel */
+	drvsel = CONFIG_SOCFPGA_DWMMC_DRVSEL;
+	smplsel = CONFIG_SOCFPGA_DWMMC_SMPSEL;
+
+	debug("%s: drvsel %d smplsel %d\n", __func__, drvsel, smplsel);
+	writel(SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel),
+		&system_manager_base->sdmmcgrp_ctrl);
+
+	debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__,
+		readl(&system_manager_base->sdmmcgrp_ctrl));
+
+	/* Enable SDMMC clock */
+	setbits_le32(&clock_manager_base->per_pll_en,
+		CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
+}
+
+int socfpga_dwmmc_init(u32 regbase, int bus_width, int index)
+{
+	struct dwmci_host *host = NULL;
+	host = calloc(sizeof(struct dwmci_host), 1);
+	if (!host) {
+		printf("dwmci_host calloc fail!\n");
+		return -1;
+	}
+
+	host->name = SOCFPGA_NAME;
+	host->ioaddr = (void *)regbase;
+	host->buswidth = bus_width;
+	host->clksel = socfpga_dwmci_clksel;
+	host->dev_index = index;
+	/* fixed clock divide by 4 which due to the SDMMC wrapper */
+	host->bus_hz = CONFIG_SOCFPGA_DWMMC_BUS_HZ;
+	host->fifoth_val = MSIZE(0x2) |
+		RX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2 - 1) |
+		TX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2);
+
+	return add_dwmci(host, host->bus_hz, 400000);
+}
+
-- 
2.39.5