[PATCH 1/3] ARM i.MX: Add driver to get sdram base and size

Sascha Hauer s.hauer at pengutronix.de
Tue Nov 27 15:48:46 EST 2012


The code initializing the SDRAM controller is not at the same
place where SDRAM is registered with barebox. To reduce the
risk of registering wrong SDRAM sizes this patch adds a
driver for the ESDCTL which reads back the configured SDRAM
size and registers the memory found with barebox.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-imx/Makefile                 |    3 +-
 arch/arm/mach-imx/esdctl.c                 |  348 ++++++++++++++++++++++++++++
 arch/arm/mach-imx/imx1.c                   |    2 +
 arch/arm/mach-imx/include/mach/esdctl.h    |    1 +
 arch/arm/mach-imx/include/mach/imx1-regs.h |    3 +
 5 files changed, 356 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-imx/esdctl.c

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 259733e..6bc2b79 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_NAND_IMX) += nand.o
 obj-$(CONFIG_ARCH_IMX_EXTERNAL_BOOT_NAND) += external-nand-boot.o
 pbl-$(CONFIG_ARCH_IMX_EXTERNAL_BOOT_NAND) += external-nand-boot.o
 obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-pfd.o
-obj-y += devices.o imx.o
+obj-y += devices.o imx.o esdctl.o
 obj-y += boot.o
 obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o
+pbl-y += esdctl.o
diff --git a/arch/arm/mach-imx/esdctl.c b/arch/arm/mach-imx/esdctl.c
new file mode 100644
index 0000000..99b7f80
--- /dev/null
+++ b/arch/arm/mach-imx/esdctl.c
@@ -0,0 +1,348 @@
+/*
+ * esdctl.c - i.MX sdram controller functions
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <io.h>
+#include <sizes.h>
+#include <init.h>
+#include <asm/barebox-arm.h>
+#include <asm/memory.h>
+#include <mach/esdctl.h>
+#include <mach/imx1-regs.h>
+#include <mach/imx21-regs.h>
+#include <mach/imx25-regs.h>
+#include <mach/imx27-regs.h>
+#include <mach/imx31-regs.h>
+#include <mach/imx35-regs.h>
+#include <mach/imx51-regs.h>
+#include <mach/imx53-regs.h>
+
+struct imx_esdctl_data {
+	unsigned long base0;
+	unsigned long base1;
+	void (*add_mem)(void *esdctlbase, struct imx_esdctl_data *);
+};
+
+/*
+ * v1 - found on i.MX1
+ */
+static inline unsigned long imx_v1_sdram_size(void __iomem *esdctlbase, int num)
+{
+	void __iomem *esdctl = esdctlbase + (num ? 4 : 0);
+	u32 ctlval = readl(esdctl);
+	unsigned long size;
+	int rows, cols, width = 2, banks = 4;
+
+	if (!(ctlval & ESDCTL0_SDE))
+		/* SDRAM controller disabled, so no RAM here */
+		return 0;
+
+	rows = ((ctlval >> 24) & 0x3) + 11;
+	cols = ((ctlval >> 20) & 0x3) + 8;
+
+	if (ctlval & (1 << 17))
+		width = 4;
+
+	size = (1 << cols) * (1 << rows) * banks * width;
+
+	if (size > SZ_64M)
+		size = SZ_64M;
+
+	return size;
+}
+
+/*
+ * v2 - found on i.MX25, i.MX27, i.MX31 and i.MX35
+ */
+static inline unsigned long imx_v2_sdram_size(void __iomem *esdctlbase, int num)
+{
+	void __iomem *esdctl = esdctlbase + (num ? IMX_ESDCTL1 : IMX_ESDCTL0);
+	u32 ctlval = readl(esdctl);
+	unsigned long size;
+	int rows, cols, width = 2, banks = 4;
+
+	if (!(ctlval & ESDCTL0_SDE))
+		/* SDRAM controller disabled, so no RAM here */
+		return 0;
+
+	rows = ((ctlval >> 24) & 0x7) + 11;
+	cols = ((ctlval >> 20) & 0x3) + 8;
+
+	if ((ctlval & ESDCTL0_DSIZ_MASK) == ESDCTL0_DSIZ_31_0)
+		width = 4;
+
+	size = (1 << cols) * (1 << rows) * banks * width;
+
+	if (size > SZ_256M)
+		size = SZ_256M;
+
+	return size;
+}
+
+/*
+ * v3 - found on i.MX51
+ */
+static inline unsigned long imx_v3_sdram_size(void __iomem *esdctlbase, int num)
+{
+	unsigned long size;
+
+	size = imx_v2_sdram_size(esdctlbase, num);
+
+	if (readl(esdctlbase + IMX_ESDMISC) & (1 << 6))
+		size *= 2;
+
+	if (size > SZ_256M)
+		size = SZ_256M;
+
+	return size;
+}
+
+#define IMX_ESDCTL_V4_ESDCTL	0x0
+#define IMX_ESDCTL_V4_ESDMISC	0x18
+
+#define ESDCTL_V4_ESDCTL_DSIZ		(1 << 16)
+#define ESDCTL_V4_ESDMISC_DDR_4_BANK	(1 << 5)
+#define ESDCTL_V4_ESDMISC_ONECS		(1 << 20)
+
+#define ESDCTL_V4_ESDCTL_SDE_0		(1 << 31)
+#define ESDCTL_V4_ESDCTL_SDE_1		(1 << 30)
+#define ESDCTL_V4_ESDMISC_BI		(1 << 12)
+
+/*
+ * v4 - found on i.MX53
+ */
+static inline unsigned long imx_v4_sdram_size(void __iomem *esdctlbase, int cs)
+{
+	u32 ctlval = readl(esdctlbase + IMX_ESDCTL_V4_ESDCTL);
+	u32 esdmisc = readl(esdctlbase + IMX_ESDCTL_V4_ESDMISC);
+	unsigned long size;
+	int rows, cols, width = 2, banks = 8;
+
+	if (cs == 0 && !(ctlval & ESDCTL_V4_ESDCTL_SDE_0))
+		return 0;
+	if (cs == 1 && !(ctlval & ESDCTL_V4_ESDCTL_SDE_1))
+		return 0;
+
+	/* one 2GiB cs, memory is returned for cs0 only */
+	if (cs == 1 && (esdmisc & ESDCTL_V4_ESDMISC_ONECS))
+		return 9;
+
+	rows = ((ctlval >> 24) & 0x7) + 11;
+	switch ((ctlval >> 20) & 0x7) {
+	case 0:
+		cols = 9;
+		break;
+	case 1:
+		cols = 10;
+		break;
+	case 2:
+		cols = 11;
+		break;
+	case 3:
+		cols = 8;
+		break;
+	case 4:
+		cols = 12;
+		break;
+	default:
+		cols = 0;
+		break;
+	}
+
+	if (ctlval & ESDCTL_V4_ESDCTL_DSIZ)
+		width = 4;
+
+	if (esdmisc & ESDCTL_V4_ESDMISC_DDR_4_BANK)
+		banks = 4;
+
+	size = (1 << cols) * (1 << rows) * banks * width;
+
+	/* bank interleaved, double size */
+	if (esdmisc & ESDCTL_V4_ESDMISC_BI)
+		return size * 2;
+
+	return size;
+}
+
+static void add_mem(unsigned long base0, unsigned long size0,
+		unsigned long base1, unsigned long size1)
+{
+	debug("%s: cs0 base: 0x%08x cs0 size: 0x%08x\n", __func__, base0, size0);
+	debug("%s: cs1 base: 0x%08x cs1 size: 0x%08x\n", __func__, base1, size1);
+
+	if (base0 + size0 == base1 && size1 > 0) {
+		/*
+		 * concatenate both chip selects to a single bank
+		 */
+		arm_add_mem_device("ram0", base0, size0 + size1);
+
+		return;
+	}
+
+	if (size0)
+		arm_add_mem_device("ram0", base0, size0);
+
+	if (size1)
+		arm_add_mem_device(size0 ? "ram1" : "ram0", base1, size1);
+}
+
+static void imx_esdctl_v1_add_mem(void *esdctlbase, struct imx_esdctl_data *data)
+{
+	add_mem(data->base0, imx_v1_sdram_size(esdctlbase, 0),
+			data->base1, imx_v1_sdram_size(esdctlbase, 1));
+}
+
+static void imx_esdctl_v2_add_mem(void *esdctlbase, struct imx_esdctl_data *data)
+{
+	add_mem(data->base0, imx_v2_sdram_size(esdctlbase, 0),
+			data->base1, imx_v2_sdram_size(esdctlbase, 1));
+}
+
+static void imx_esdctl_v3_add_mem(void *esdctlbase, struct imx_esdctl_data *data)
+{
+	add_mem(data->base0, imx_v3_sdram_size(esdctlbase, 0),
+			data->base1, imx_v3_sdram_size(esdctlbase, 1));
+}
+
+static void imx_esdctl_v4_add_mem(void *esdctlbase, struct imx_esdctl_data *data)
+{
+	add_mem(data->base0, imx_v4_sdram_size(esdctlbase, 0),
+			data->base1, imx_v4_sdram_size(esdctlbase, 1));
+}
+
+static __maybe_unused struct imx_esdctl_data imx1_data = {
+	.base0 = MX1_CSD0_BASE_ADDR,
+	.base1 = MX1_CSD1_BASE_ADDR,
+	.add_mem = imx_esdctl_v1_add_mem,
+};
+
+static int imx_esdctl_probe(struct device_d *dev)
+{
+	struct imx_esdctl_data *data;
+	int ret;
+	void *base;
+
+	ret = dev_get_drvdata(dev, (unsigned long *)&data);
+	if (ret)
+		return ret;
+
+	base = dev_request_mem_region(dev, 0);
+	if (!base)
+		return -ENOMEM;
+
+	data->add_mem(base, data);
+
+	return 0;
+}
+
+static __maybe_unused struct imx_esdctl_data imx25_data = {
+	.base0 = MX25_CSD0_BASE_ADDR,
+	.base1 = MX25_CSD1_BASE_ADDR,
+	.add_mem = imx_esdctl_v2_add_mem,
+};
+
+static __maybe_unused struct imx_esdctl_data imx27_data = {
+	.base0 = MX27_CSD0_BASE_ADDR,
+	.base1 = MX27_CSD1_BASE_ADDR,
+	.add_mem = imx_esdctl_v2_add_mem,
+};
+
+static __maybe_unused struct imx_esdctl_data imx31_data = {
+	.base0 = MX31_CSD0_BASE_ADDR,
+	.base1 = MX31_CSD1_BASE_ADDR,
+	.add_mem = imx_esdctl_v2_add_mem,
+};
+
+static __maybe_unused struct imx_esdctl_data imx35_data = {
+	.base0 = MX35_CSD0_BASE_ADDR,
+	.base1 = MX35_CSD1_BASE_ADDR,
+	.add_mem = imx_esdctl_v2_add_mem,
+};
+
+static __maybe_unused struct imx_esdctl_data imx51_data = {
+	.base0 = MX51_CSD0_BASE_ADDR,
+	.base1 = MX51_CSD1_BASE_ADDR,
+	.add_mem = imx_esdctl_v3_add_mem,
+};
+
+static __maybe_unused struct imx_esdctl_data imx53_data = {
+	.base0 = MX53_CSD0_BASE_ADDR,
+	.base1 = MX53_CSD1_BASE_ADDR,
+	.add_mem = imx_esdctl_v4_add_mem,
+};
+
+static struct platform_device_id imx_esdctl_ids[] = {
+#ifdef CONFIG_ARCH_IMX1
+	{
+		.name = "imx1-sdramc",
+		.driver_data = (unsigned long)&imx1_data,
+	},
+#endif
+#ifdef CONFIG_ARCH_IMX25
+	{
+		.name = "imx25-esdctl",
+		.driver_data = (unsigned long)&imx25_data,
+	},
+#endif
+#ifdef CONFIG_ARCH_IMX27
+	{
+		.name = "imx27-esdctl",
+		.driver_data = (unsigned long)&imx27_data,
+	},
+#endif
+#ifdef CONFIG_ARCH_IMX31
+	{
+		.name = "imx31-esdctl",
+		.driver_data = (unsigned long)&imx31_data,
+	},
+#endif
+#ifdef CONFIG_ARCH_IMX35
+	{
+		.name = "imx35-esdctl",
+		.driver_data = (unsigned long)&imx35_data,
+	},
+#endif
+#ifdef CONFIG_ARCH_IMX51
+	{
+		.name = "imx51-esdctl",
+		.driver_data = (unsigned long)&imx51_data,
+	},
+#endif
+#ifdef CONFIG_ARCH_IMX53
+	{
+		.name = "imx53-esdctl",
+		.driver_data = (unsigned long)&imx53_data,
+	},
+#endif
+	{
+		/* sentinel */
+	},
+};
+
+static struct driver_d imx_serial_driver = {
+	.name   = "imx-esdctl",
+	.probe  = imx_esdctl_probe,
+	.id_table = imx_esdctl_ids,
+};
+
+static int imx_esdctl_init(void)
+{
+	return platform_driver_register(&imx_serial_driver);
+}
+
+mem_initcall(imx_esdctl_init);
diff --git a/arch/arm/mach-imx/imx1.c b/arch/arm/mach-imx/imx1.c
index 18901ea..59cff28 100644
--- a/arch/arm/mach-imx/imx1.c
+++ b/arch/arm/mach-imx/imx1.c
@@ -49,6 +49,8 @@ void imx1_setup_eimcs(size_t cs, unsigned upper, unsigned lower)
 	writel(lower, MX1_EIM_BASE_ADDR + 4 + cs * 8);
 }
 
+#include <mach/esdctl.h>
+
 static int imx1_init(void)
 {
 	imx_iomuxv1_init((void *)MX1_GPIO1_BASE_ADDR);
diff --git a/arch/arm/mach-imx/include/mach/esdctl.h b/arch/arm/mach-imx/include/mach/esdctl.h
index 8124c87..1aec2a8 100644
--- a/arch/arm/mach-imx/include/mach/esdctl.h
+++ b/arch/arm/mach-imx/include/mach/esdctl.h
@@ -26,6 +26,7 @@
 #define ESDCTL0_DSIZ_31_16			(0 << 16)
 #define ESDCTL0_DSIZ_15_0			(1 << 16)
 #define ESDCTL0_DSIZ_31_0			(2 << 16)
+#define ESDCTL0_DSIZ_MASK			(3 << 16)
 #define ESDCTL0_REF1				(1 << 13)
 #define ESDCTL0_REF2				(2 << 13)
 #define ESDCTL0_REF4				(3 << 13)
diff --git a/arch/arm/mach-imx/include/mach/imx1-regs.h b/arch/arm/mach-imx/include/mach/imx1-regs.h
index df6ede5..69e57e3 100644
--- a/arch/arm/mach-imx/include/mach/imx1-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx1-regs.h
@@ -4,6 +4,9 @@
 #define MX1_IO_BASE_ADDR	0x00200000
 #define MX1_IO_SIZE		SZ_1M
 
+#define MX1_CSD0_BASE_ADDR	0x08000000
+#define MX1_CSD1_BASE_ADDR	0x0c000000
+
 #define MX1_CS0_PHYS		0x10000000
 #define MX1_CS0_SIZE		0x02000000
 
-- 
1.7.10.4




More information about the barebox mailing list