[RFC PATCH] ARM: phytec-som-imx6: phycard DRAM autodetection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add support for automatic DRAM size detection on phytec phycard imx6q
machines. Currently supported SoM variants are 1 GiB (1 bank) and 2 GiB
variant. Machines now boot from internal SRAM (see DCD table loadaddr
0x00907000) and then do DRAM size detection and configuration in plain
C code (instead of hardcoded DCD table values). After initializing DRAM,
remaining barebox image is xloaded from GPMI NAND to DRAM and started
from there.

Booting process / strategy on phycard machines:
 1) lowlevel in SRAM (PBL)
  1.1) detect DRAM size
  1.2) configure DRAM accordingly
  1.3) copy remaining barebox image from NAND to DRAM (addr 0x10000000)
  1.4) jump to DRAM (addr 0x10000000)
 2) lowlevel in DRAM (PBL)
  2.1) skip DRAM detection since already running from DRAM
  2.2) main barebox entry
 3) board code
 4) ...

Signed-off-by: Primoz Fiser <primoz.fiser@xxxxxxxxx>
Signed-off-by: Andrej Picej <andrej.picej@xxxxxxxxx>
---
 .../flash-header-phytec-pcaaxl3.imxcfg        |   4 +
 arch/arm/boards/phytec-som-imx6/lowlevel.c    | 255 ++++++++++++++++++
 images/Makefile.imx                           |   2 +
 3 files changed, 261 insertions(+)
 create mode 100644 arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.imxcfg

diff --git a/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.imxcfg b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.imxcfg
new file mode 100644
index 000000000..fcfef9c23
--- /dev/null
+++ b/arch/arm/boards/phytec-som-imx6/flash-header-phytec-pcaaxl3.imxcfg
@@ -0,0 +1,4 @@
+soc imx6
+loadaddr 0x00907000
+max_load_size 0x31000
+ivtofs 0x400
diff --git a/arch/arm/boards/phytec-som-imx6/lowlevel.c b/arch/arm/boards/phytec-som-imx6/lowlevel.c
index 62a1c8de7..7bc9d123a 100644
--- a/arch/arm/boards/phytec-som-imx6/lowlevel.c
+++ b/arch/arm/boards/phytec-som-imx6/lowlevel.c
@@ -16,6 +16,261 @@
 #include <asm/cache.h>
 #include <asm/mmu.h>
 #include <mach/imx6.h>
+#include <mach/imx6-mmdc.h>
+#include <mach/esdctl.h>
+#include <mach/xload.h>
+
+/* udelay() is not available in PBL, need to improvise */
+static void __udelay(int us)
+{
+	volatile int i;
+
+	for (i = 0; i < us * 4; i++);
+}
+
+#define	IMX6Q_UART2			2
+#define	IMX6Q_UART3			3
+#define	DRIVE_STRENGTH_40_OHM		0x30
+#define	DRIVE_STRENGTH_48_OHM		0x28
+
+/* mmdc DDR io registers */
+static struct mx6dq_iomux_ddr_regs mx6dq_ddr_ioregs = {
+	.dram_sdclk_0 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdclk_1 = DRIVE_STRENGTH_40_OHM,
+	.dram_cas = DRIVE_STRENGTH_40_OHM,
+	.dram_ras = DRIVE_STRENGTH_40_OHM,
+	.dram_reset = DRIVE_STRENGTH_40_OHM,
+	.dram_sdcke0 = 0x00003000,
+	.dram_sdcke1 = 0x00003000,
+	.dram_sdba2 = 0x00000000,
+	.dram_sdodt0 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdodt1 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdqs0 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdqs1 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdqs2 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdqs3 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdqs4 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdqs5 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdqs6 = DRIVE_STRENGTH_40_OHM,
+	.dram_sdqs7 = DRIVE_STRENGTH_40_OHM,
+	.dram_dqm0 = DRIVE_STRENGTH_40_OHM,
+	.dram_dqm1 = DRIVE_STRENGTH_40_OHM,
+	.dram_dqm2 = DRIVE_STRENGTH_40_OHM,
+	.dram_dqm3 = DRIVE_STRENGTH_40_OHM,
+	.dram_dqm4 = DRIVE_STRENGTH_40_OHM,
+	.dram_dqm5 = DRIVE_STRENGTH_40_OHM,
+	.dram_dqm6 = DRIVE_STRENGTH_40_OHM,
+	.dram_dqm7 = DRIVE_STRENGTH_40_OHM,
+};
+
+static struct mx6_mmdc_calibration mx6q_mmdc_calib = {
+	.p0_mpwldectrl0 = 0x0013001b,
+	.p0_mpwldectrl1 = 0x003b0034,
+	.p1_mpwldectrl0 = 0x0037004b,
+	.p1_mpwldectrl1 = 0x004b0055,
+	.p0_mpdgctrl0 = 0x4350035e,
+	.p0_mpdgctrl1 = 0x035c0358,
+	.p1_mpdgctrl0 = 0x436e0376,
+	.p1_mpdgctrl1 = 0x03770352,
+	.p0_mprddlctl = 0x3c333436,
+	.p1_mprddlctl = 0x35332f3b,
+	.p0_mpwrdlctl = 0x37363e39,
+	.p1_mpwrdlctl = 0x432f433d,
+};
+
+/* MT41K128M16JT-125 IT */
+static struct mx6_ddr3_cfg mt41k128m16jt = {
+	.mem_speed = 1600,
+	.density = 2,
+	.width = 16,
+	.banks = 8,
+	.rowaddr = 14,
+	.coladdr = 10,
+	.pagesz = 2,
+	.trcd = 1375,
+	.trcmin = 4875,
+	.trasmin = 3500,
+};
+
+/* DDR 64bit 1GB */
+static struct mx6_ddr_sysinfo mem1g_q = {
+	.dsize		= 2,
+	.cs1_mirror	= 1,
+	.cs_density	= 8,
+	.ncs		= 1,
+	.bi_on		= 1,
+	.rtt_nom	= 1,
+	.rtt_wr		= 0,
+	.ralat		= 5,
+	.walat		= 1,
+	.mif3_mode	= 3,
+	.rst_to_cke	= 0x23,
+	.sde_to_rst	= 0x10,
+};
+
+/* DDR 64bit 2GB */
+static struct mx6_ddr_sysinfo mem2g_q = {
+	.dsize		= 2,
+	.cs1_mirror	= 1,
+	.cs_density	= 8,
+	.ncs		= 2,
+	.bi_on		= 1,
+	.rtt_nom	= 1,
+	.rtt_wr		= 0,
+	.ralat		= 5,
+	.walat		= 1,
+	.mif3_mode	= 3,
+	.rst_to_cke	= 0x23,
+	.sde_to_rst	= 0x10,
+};
+
+/* mmdc GRP io registers */
+static struct mx6dq_iomux_grp_regs mx6dq_grp_ioregs = {
+	.grp_ddr_type = 0x000c0000,
+	.grp_ddrmode_ctl = 0x00020000,
+	.grp_ddrpke = 0x00000000,
+	.grp_addds = DRIVE_STRENGTH_40_OHM,
+	.grp_ctlds = DRIVE_STRENGTH_40_OHM,
+	.grp_ddrmode = 0x00020000,
+	.grp_b0ds = DRIVE_STRENGTH_40_OHM,
+	.grp_b1ds = DRIVE_STRENGTH_40_OHM,
+	.grp_b2ds = DRIVE_STRENGTH_40_OHM,
+	.grp_b3ds = DRIVE_STRENGTH_40_OHM,
+	.grp_b4ds = DRIVE_STRENGTH_40_OHM,
+	.grp_b5ds = DRIVE_STRENGTH_40_OHM,
+	.grp_b6ds = DRIVE_STRENGTH_40_OHM,
+	.grp_b7ds = DRIVE_STRENGTH_40_OHM,
+};
+
+static inline void setup_uart_phycard_imx6q(int UARTn)
+{
+	void __iomem *iomuxbase = (void *)MX6_IOMUXC_BASE_ADDR;
+
+	switch (UARTn) {
+	case IMX6Q_UART2:
+		/* Setup UART2 pin muxing */
+		writel(0x4, iomuxbase + 0xc0);
+		writel(0x4, iomuxbase + 0xbc);
+		writel(0x1, iomuxbase + 0x928);
+
+		imx6_ungate_all_peripherals();
+		imx6_uart_setup((void *)MX6_UART2_BASE_ADDR);
+		pbl_set_putc(imx_uart_putc, (void *)MX6_UART2_BASE_ADDR);
+		break;
+	case IMX6Q_UART3:
+		/* Setup UART3 pin muxing */
+		writel(0x2, iomuxbase + 0xb4);
+		writel(0x2, iomuxbase + 0xb8);
+		writel(0x1, iomuxbase + 0x930);
+
+		imx6_ungate_all_peripherals();
+		imx6_uart_setup((void *)MX6_UART3_BASE_ADDR);
+		pbl_set_putc(imx_uart_putc, (void *)MX6_UART3_BASE_ADDR);
+		break;
+	default:
+		return;
+	}
+
+	putc_ll('>');
+}
+
+#define DRAM_CONFIG_DELAY	5000
+#define DRAM_CALIB_DELAY	50000
+
+static unsigned long phycard_imx6q_ll_autodetect_dram_init(void)
+{
+	unsigned long memsize = SZ_2G;
+	unsigned long dram_size = 0;
+
+	pr_debug("DRAM init & size detection\n");
+
+	/* First try with 2 GiB DRAM configuration */
+	mx6dq_dram_iocfg(64, &mx6dq_ddr_ioregs, &mx6dq_grp_ioregs);
+	mx6_dram_cfg(&mem2g_q, &mx6q_mmdc_calib, &mt41k128m16jt);
+	__udelay(DRAM_CONFIG_DELAY);
+
+	mmdc_do_write_level_calibration();
+	mmdc_do_dqs_calibration();
+	__udelay(DRAM_CALIB_DELAY);
+
+	pr_debug("DRAM probe with 2 GiB config\n");
+
+	dram_size = get_ram_size((volatile long *)0x10000000, (long)memsize);
+	pr_debug("DRAM detected size: 0x%lx\n", dram_size);
+
+	if (dram_size != SZ_2G) {
+		/* Next try with 1 GiB DRAM configuration */
+		memsize = SZ_1G;
+
+		mx6dq_dram_iocfg(64, &mx6dq_ddr_ioregs, &mx6dq_grp_ioregs);
+		mx6_dram_cfg(&mem1g_q, &mx6q_mmdc_calib, &mt41k128m16jt);
+		__udelay(DRAM_CONFIG_DELAY);
+
+		mmdc_do_write_level_calibration();
+		mmdc_do_dqs_calibration();
+		__udelay(DRAM_CALIB_DELAY);
+
+		pr_debug("DRAM probe with 1 GiB config\n");
+	} else {
+		pr_debug("DRAM size 0x%lx already detected, " \
+			"skipping DRAM re-configuration\n", dram_size);
+	}
+
+	dram_size = get_ram_size((volatile long *)0x10000000, (long)memsize);
+	pr_debug("DRAM final detected size: 0x%lx\n", dram_size);
+
+#ifdef DEBUG
+	pr_debug("DRAM calibration results:\n");
+	mmdc_print_calibration_results();
+#endif
+	return memsize;
+}
+
+static void phycard_imx6q_ll_autodetect_init(void)
+{
+	if (IS_ENABLED(CONFIG_DEBUG_LL))
+		setup_uart_phycard_imx6q(IMX6Q_UART3);
+
+	/* Already running from DRAM? */
+	if (get_pc() > 0x10000000) {
+		pr_debug("DRAM already initialized, skipping...\n");
+		return;
+	}
+
+	/* Running from SRAM, need to configure DRAM */
+	phycard_imx6q_ll_autodetect_dram_init();
+
+	/* Now xload remaining part of barebox image from NAND */
+	pr_debug("xloading barebox image from NAND\n");
+	imx6_nand_start_image();
+
+	pr_err("Booting failed!\n");
+	hang();
+}
+
+extern char __dtb_imx6q_phytec_phycard_start[];
+
+static noinline void phycard_imx6q_ll_autodetect_start(void)
+{
+	void *fdt = __dtb_imx6q_phytec_phycard_start + get_runtime_offset();
+
+	phycard_imx6q_ll_autodetect_init();
+
+	imx6q_barebox_entry(fdt);
+}
+
+ENTRY_FUNCTION(start_phycard_imx6q_ll_autodetect, r0, r1, r2)
+{
+	imx6_cpu_lowlevel_init();
+
+	arm_setup_stack(0x00940000);
+
+	relocate_to_current_adr();
+	setup_c();
+	barrier();
+
+	phycard_imx6q_ll_autodetect_start();
+}
 
 static inline void setup_uart(void)
 {
diff --git a/images/Makefile.imx b/images/Makefile.imx
index 514db326b..80d2fd805 100644
--- a/images/Makefile.imx
+++ b/images/Makefile.imx
@@ -205,6 +205,8 @@ $(call build_imx_habv4img, CONFIG_MACH_PHYTEC_SOM_IMX6, start_phytec_phyboard_su
 
 $(call build_imx_habv4img, CONFIG_MACH_PHYTEC_SOM_IMX6, start_phytec_phyboard_subra_1gib_1bank, phytec-som-imx6/flash-header-phytec-pfla02-1gib-1bank, phytec-phyboard-subra-1gib-1bank)
 
+$(call build_imx_habv4img, CONFIG_MACH_PHYTEC_SOM_IMX6, start_phycard_imx6q_ll_autodetect, phytec-som-imx6/flash-header-phytec-pcaaxl3, phytec-phycard-imx6q-som-nand)
+
 $(call build_imx_habv4img, CONFIG_MACH_DFI_FS700_M60, start_imx6dl_dfi_fs700_m60_6s, dfi-fs700-m60/flash-header-fs700-m60-6s, dfi-fs700-m60-6s)
 
 $(call build_imx_habv4img, CONFIG_MACH_DFI_FS700_M60, start_imx6q_dfi_fs700_m60_6q_micron, dfi-fs700-m60/flash-header-fs700-m60-6q-micron, dfi-fs700-m60-6q-micron)
-- 
2.25.1


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



[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux