mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH] ARM: i.MX: xload: implement esdhc xload for i.MX6
@ 2015-07-29  7:47 Sascha Hauer
  2015-07-30  9:31 ` Holger Schurig
  0 siblings, 1 reply; 3+ messages in thread
From: Sascha Hauer @ 2015-07-29  7:47 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-imx/Makefile             |   2 +-
 arch/arm/mach-imx/include/mach/xload.h |   2 +
 arch/arm/mach-imx/xload-esdhc.c        | 274 +++++++++++++++++++++++++++++++++
 3 files changed, 277 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-imx/xload-esdhc.c

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 09b7459..db1cf7d 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -23,4 +23,4 @@ obj-pbl-y += esdctl.o boot.o
 obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o
 obj-$(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) += imx-bbu-external-nand.o
 lwl-y += cpu_init.o
-pbl-y += xload-spi.o xload-common.o
+pbl-y += xload-spi.o xload-esdhc.o xload-common.o
diff --git a/arch/arm/mach-imx/include/mach/xload.h b/arch/arm/mach-imx/include/mach/xload.h
index 0e6fe09..997522e 100644
--- a/arch/arm/mach-imx/include/mach/xload.h
+++ b/arch/arm/mach-imx/include/mach/xload.h
@@ -3,6 +3,8 @@
 
 int imx6_spi_load_image(int instance, unsigned int flash_offset, void *buf, int len);
 int imx6_spi_start_image(int instance);
+int imx6_esdhc_load_image(int instance, void *buf, int len);
+int imx6_esdhc_start_image(int instance);
 
 int imx_image_size(void);
 
diff --git a/arch/arm/mach-imx/xload-esdhc.c b/arch/arm/mach-imx/xload-esdhc.c
new file mode 100644
index 0000000..4134161
--- /dev/null
+++ b/arch/arm/mach-imx/xload-esdhc.c
@@ -0,0 +1,274 @@
+#define pr_fmt(fmt) "xload-esdhc: " fmt
+
+#include <common.h>
+#include <io.h>
+#include <mci.h>
+#include <mach/imx6-regs.h>
+#include <mach/xload.h>
+#include <linux/sizes.h>
+#include "../../../drivers/mci/sdhci.h"
+#include "../../../drivers/mci/imx-esdhc.h"
+
+#define SECTOR_SIZE 512
+
+#define esdhc_read32(a)                    readl(a)
+#define esdhc_write32(a, v)                writel(v,a)
+#define IMX_SDHCI_MIXCTRL  0x48
+
+struct esdhc {
+	void __iomem *regs;
+	int is_mx6;
+};
+
+static void __udelay(int us)
+{
+	volatile int i;
+
+	for (i = 0; i < us * 4; i++);
+}
+
+static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data)
+{
+	u32 xfertyp = 0;
+
+	if (data)
+		xfertyp |= COMMAND_DPSEL | TRANSFER_MODE_MSBSEL |
+			TRANSFER_MODE_BCEN |TRANSFER_MODE_DTDSEL;
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		xfertyp |= COMMAND_CCCEN;
+	if (cmd->resp_type & MMC_RSP_OPCODE)
+		xfertyp |= COMMAND_CICEN;
+	if (cmd->resp_type & MMC_RSP_136)
+		xfertyp |= COMMAND_RSPTYP_136;
+	else if (cmd->resp_type & MMC_RSP_BUSY)
+		xfertyp |= COMMAND_RSPTYP_48_BUSY;
+	else if (cmd->resp_type & MMC_RSP_PRESENT)
+		xfertyp |= COMMAND_RSPTYP_48;
+
+	return COMMAND_CMD(cmd->cmdidx) | xfertyp;
+}
+
+static int esdhc_do_data(struct esdhc *esdhc, struct mci_data *data)
+{
+	void __iomem *regs = esdhc->regs;
+	char *buffer;
+	u32 databuf;
+	u32 size;
+	u32 irqstat;
+	u32 timeout;
+	u32 present;
+
+	buffer = data->dest;
+
+	timeout = 1000000;
+	size = data->blocksize * data->blocks;
+	irqstat = esdhc_read32(regs + SDHCI_INT_STATUS);
+
+	while (size) {
+		present = esdhc_read32(regs + SDHCI_PRESENT_STATE) & PRSSTAT_BREN;
+		if (present) {
+			databuf = esdhc_read32(regs + SDHCI_BUFFER);
+			*((u32 *)buffer) = databuf;
+			buffer += 4;
+			size -= 4;
+		}
+
+		if (!timeout--) {
+			pr_err("read time out\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static int
+esdhc_send_cmd(struct esdhc *esdhc, struct mci_cmd *cmd, struct mci_data *data)
+{
+	u32	xfertyp, mixctrl;
+	u32	irqstat;
+	void __iomem *regs = esdhc->regs;
+	int ret;
+	int timeout;
+
+	esdhc_write32(regs + SDHCI_INT_STATUS, -1);
+
+	/* Wait at least 8 SD clock cycles before the next command */
+	__udelay(1);
+
+	if (data) {
+		/* Set up for a data transfer if we have one */
+		esdhc_write32(regs + SDHCI_DMA_ADDRESS, (u32)data->dest);
+		esdhc_write32(regs + SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | SECTOR_SIZE);
+	}
+
+	/* Figure out the transfer arguments */
+	xfertyp = esdhc_xfertyp(cmd, data);
+
+	/* Send the command */
+	esdhc_write32(regs + SDHCI_ARGUMENT, cmd->cmdarg);
+
+	if (esdhc->is_mx6) {
+		/* write lower-half of xfertyp to mixctrl */
+		mixctrl = xfertyp & 0xFFFF;
+		/* Keep the bits 22-25 of the register as is */
+		mixctrl |= (esdhc_read32(regs + IMX_SDHCI_MIXCTRL) & (0xF << 22));
+		esdhc_write32(regs + IMX_SDHCI_MIXCTRL, mixctrl);
+	}
+
+	esdhc_write32(regs + SDHCI_TRANSFER_MODE__COMMAND, xfertyp);
+
+	/* Wait for the command to complete */
+	timeout = 10000;
+	while (!(esdhc_read32(regs + SDHCI_INT_STATUS) & IRQSTAT_CC)) {
+		__udelay(1);
+		if (!timeout--)
+			return -ETIMEDOUT;
+	}
+
+	irqstat = esdhc_read32(regs + SDHCI_INT_STATUS);
+	esdhc_write32(regs + SDHCI_INT_STATUS, irqstat);
+
+	if (irqstat & CMD_ERR)
+		return -EIO;
+
+	if (irqstat & IRQSTAT_CTOE)
+		return -ETIMEDOUT;
+
+	/* Copy the response to the response buffer */
+	cmd->response[0] = esdhc_read32(regs + SDHCI_RESPONSE_0);
+
+	/* Wait until all of the blocks are transferred */
+	if (data) {
+		ret = esdhc_do_data(esdhc, data);
+		if (ret)
+			return ret;
+	}
+
+	esdhc_write32(regs + SDHCI_INT_STATUS, -1);
+
+	/* Wait for the bus to be idle */
+	timeout = 10000;
+	while (esdhc_read32(regs + SDHCI_PRESENT_STATE) &
+			(PRSSTAT_CICHB | PRSSTAT_CIDHB | PRSSTAT_DLA)) {
+		__udelay(1);
+		if (!timeout--)
+			return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
+{
+	struct mci_cmd cmd;
+	struct mci_data data;
+	u32 val;
+	int ret;
+
+	writel(IRQSTATEN_CC | IRQSTATEN_TC | IRQSTATEN_CINT | IRQSTATEN_CTOE |
+			IRQSTATEN_CCE | IRQSTATEN_CEBE | IRQSTATEN_CIE |
+			IRQSTATEN_DTOE | IRQSTATEN_DCE | IRQSTATEN_DEBE |
+			IRQSTATEN_DINT, esdhc->regs + SDHCI_INT_ENABLE);
+
+	val = readl(esdhc->regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
+	val |= SYSCTL_HCKEN | SYSCTL_IPGEN;
+	writel(val, esdhc->regs + SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
+
+	cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
+	cmd.cmdarg = 0;
+	cmd.resp_type = MMC_RSP_R1;
+
+	data.dest = dst;
+	data.blocks = len / SECTOR_SIZE;
+	data.blocksize = SECTOR_SIZE;
+	data.flags = MMC_DATA_READ;
+
+	ret = esdhc_send_cmd(esdhc, &cmd, &data);
+	if (ret) {
+		pr_debug("send command failed with %d\n", ret);
+		return ret;
+	}
+
+	cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+	cmd.cmdarg = 0;
+	cmd.resp_type = MMC_RSP_R1b;
+
+	esdhc_send_cmd(esdhc, &cmd, NULL);
+
+	return 0;
+}
+
+int imx6_esdhc_load_image(int instance, void *buf, int len)
+{
+	struct esdhc esdhc;
+	int ret;
+
+	switch (instance) {
+	case 0:
+		esdhc.regs = IOMEM(MX6_USDHC1_BASE_ADDR);
+		break;
+	case 1:
+		esdhc.regs = IOMEM(MX6_USDHC2_BASE_ADDR);
+		break;
+	case 2:
+		esdhc.regs = IOMEM(MX6_USDHC3_BASE_ADDR);
+		break;
+	case 3:
+		esdhc.regs = IOMEM(MX6_USDHC4_BASE_ADDR);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	esdhc.is_mx6 = 1;
+
+	ret = esdhc_read_blocks(&esdhc, buf, len);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/**
+ * imx6_esdhc_start_image - Load and start an image from USDHC controller
+ * @instance: The USDHC controller instance (0..4)
+ *
+ * This uses imx6_esdhc_load_image() to load an image from SPI NOR flash.
+ * It is assumed that the image is the currently running barebox image
+ * (This information is used to calculate the length of the image). The
+ * image is started afterwards.
+ *
+ * Return: If successul, this function does not return. A negative error
+ * code is returned when this function fails.
+ */
+int imx6_esdhc_start_image(int instance)
+{
+	void *buf = (void *)0x10000000;
+	u32 *ivt = buf + SZ_1K;
+	int ret, len;
+	void __noreturn (*bb)(void);
+
+	len = imx_image_size();
+	len = ALIGN(len, SECTOR_SIZE);
+
+	ret = imx6_esdhc_load_image(instance, buf, 3 * SECTOR_SIZE);
+	if (ret)
+		return ret;
+	if (*(u32 *)(ivt) != 0x402000d1) {
+		pr_debug("IVT header not found on SD card. Found 0x%08x instead of 0x402000d1\n",
+				*ivt);
+		return -EINVAL;
+	}
+
+	pr_debug("Check ok, loading image\n");
+
+	ret = imx6_esdhc_load_image(instance, buf, len);
+	if (ret)
+		return ret;
+
+	bb = buf;
+
+	bb();
+}
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH] ARM: i.MX: xload: implement esdhc xload for i.MX6
  2015-07-29  7:47 [PATCH] ARM: i.MX: xload: implement esdhc xload for i.MX6 Sascha Hauer
@ 2015-07-30  9:31 ` Holger Schurig
  2015-07-30  9:59   ` Sascha Hauer
  0 siblings, 1 reply; 3+ messages in thread
From: Holger Schurig @ 2015-07-30  9:31 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List

2015-07-29 9:47 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>:
> + * imx6_esdhc_start_image - Load and start an image from USDHC controller
> + * @instance: The USDHC controller instance (0..4)
> + *
> + * This uses imx6_esdhc_load_image() to load an image from SPI NOR flash.

Hmm, either it's from USDHC or from SPI-NOR :-)


Question: does this load an image from an eMMC boot partition (e.g.
the tiny ones that some of them have?)

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH] ARM: i.MX: xload: implement esdhc xload for i.MX6
  2015-07-30  9:31 ` Holger Schurig
@ 2015-07-30  9:59   ` Sascha Hauer
  0 siblings, 0 replies; 3+ messages in thread
From: Sascha Hauer @ 2015-07-30  9:59 UTC (permalink / raw)
  To: Holger Schurig; +Cc: Barebox List

Hi Holger,

On Thu, Jul 30, 2015 at 11:31:38AM +0200, Holger Schurig wrote:
> 2015-07-29 9:47 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>:
> > + * imx6_esdhc_start_image - Load and start an image from USDHC controller
> > + * @instance: The USDHC controller instance (0..4)
> > + *
> > + * This uses imx6_esdhc_load_image() to load an image from SPI NOR flash.
> 
> Hmm, either it's from USDHC or from SPI-NOR :-)

Right, will fix.

> 
> 
> Question: does this load an image from an eMMC boot partition (e.g.
> the tiny ones that some of them have?)

Hm, I don't know. The partition must actively be switched. I know that
the i.MX6 boot ROM actually loads the image from the boot partition
configured in the eMMC. imx6_esdhc_load_image() relies on the
initialization done by the boot ROM, so if the boot ROM just leaves
the eMMC in the state it is before jumping to barebox then barebox
should automatically load the image from the correct place. I haven't
tested it though.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

end of thread, other threads:[~2015-07-30  9:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-29  7:47 [PATCH] ARM: i.MX: xload: implement esdhc xload for i.MX6 Sascha Hauer
2015-07-30  9:31 ` Holger Schurig
2015-07-30  9:59   ` Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox