+Cc some Phytec guys On Wed, Jan 20, 2021 at 01:52:03PM +0100, Andrej Picej wrote: > 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(); You should detect where we are booting from and load the rest from the same device. Speaking of which, we should finally add some imx6_xload_start_image() function which does that generically for i.MX6. > + > + 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 > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox