// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Amarula Solutions B.V. * Copyright (C) 2016 Engicam S.r.l. * Author: Jagan Teki <jagan@amarulasolutions.com> */ #include <common.h> #include <spl.h> #include <asm/io.h> #include <asm/gpio.h> #include <linux/sizes.h> #include <asm/arch/clock.h> #include <asm/arch/crm_regs.h> #include <asm/arch/iomux.h> #include <asm/arch/mx6-ddr.h> #include <asm/arch/mx6-pins.h> #include <asm/arch/sys_proto.h> #include <asm/mach-imx/iomux-v3.h> #include <asm/mach-imx/video.h> #define UART_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \ PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED | \ PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS) static iomux_v3_cfg_t const uart_pads[] = { #ifdef CONFIG_MX6QDL IOMUX_PADS(PAD_KEY_COL0__UART4_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), IOMUX_PADS(PAD_KEY_ROW0__UART4_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), #elif CONFIG_MX6UL IOMUX_PADS(PAD_UART1_TX_DATA__UART1_DCE_TX | MUX_PAD_CTRL(UART_PAD_CTRL)), IOMUX_PADS(PAD_UART1_RX_DATA__UART1_DCE_RX | MUX_PAD_CTRL(UART_PAD_CTRL)), #endif }; #ifdef CONFIG_SPL_LOAD_FIT int board_fit_config_name_match(const char *name) { if (is_mx6dq() && !strcmp(name, "imx6q-icore")) return 0; else if (is_mx6dq() && !strcmp(name, "imx6q-icore-rqs")) return 0; else if (is_mx6dq() && !strcmp(name, "imx6q-icore-mipi")) return 0; else if ((is_mx6dl() || is_mx6solo()) && !strcmp(name, "imx6dl-icore")) return 0; else if ((is_mx6dl() || is_mx6solo()) && !strcmp(name, "imx6dl-icore-rqs")) return 0; else if ((is_mx6dl() || is_mx6solo()) && !strcmp(name, "imx6dl-icore-mipi")) return 0; else return -1; } #endif #ifdef CONFIG_ENV_IS_IN_MMC void board_boot_order(u32 *spl_boot_list) { u32 bmode = imx6_src_get_boot_mode(); u8 boot_dev = BOOT_DEVICE_MMC1; switch ((bmode & IMX6_BMODE_MASK) >> IMX6_BMODE_SHIFT) { case IMX6_BMODE_SD: case IMX6_BMODE_ESD: /* SD/eSD - BOOT_DEVICE_MMC1 */ break; case IMX6_BMODE_MMC: case IMX6_BMODE_EMMC: /* MMC/eMMC */ boot_dev = BOOT_DEVICE_MMC2; break; default: /* Default - BOOT_DEVICE_MMC1 */ printf("Wrong board boot order\n"); break; } spl_boot_list[0] = boot_dev; } #endif #ifdef CONFIG_SPL_OS_BOOT int spl_start_uboot(void) { /* break into full u-boot on 'c' */ if (serial_tstc() && serial_getc() == 'c') return 1; return 0; } #endif #ifdef CONFIG_MX6QDL /* * Driving strength: * 0x30 == 40 Ohm * 0x28 == 48 Ohm */ #define IMX6DQ_DRIVE_STRENGTH 0x30 #define IMX6SDL_DRIVE_STRENGTH 0x28 /* configure MX6Q/DUAL mmdc DDR io registers */ static struct mx6dq_iomux_ddr_regs mx6dq_ddr_ioregs = { .dram_sdqs0 = IMX6DQ_DRIVE_STRENGTH, .dram_sdqs1 = IMX6DQ_DRIVE_STRENGTH, .dram_sdqs2 = IMX6DQ_DRIVE_STRENGTH, .dram_sdqs3 = IMX6DQ_DRIVE_STRENGTH, .dram_sdqs4 = IMX6DQ_DRIVE_STRENGTH, .dram_sdqs5 = IMX6DQ_DRIVE_STRENGTH, .dram_sdqs6 = IMX6DQ_DRIVE_STRENGTH, .dram_sdqs7 = IMX6DQ_DRIVE_STRENGTH, .dram_dqm0 = IMX6DQ_DRIVE_STRENGTH, .dram_dqm1 = IMX6DQ_DRIVE_STRENGTH, .dram_dqm2 = IMX6DQ_DRIVE_STRENGTH, .dram_dqm3 = IMX6DQ_DRIVE_STRENGTH, .dram_dqm4 = IMX6DQ_DRIVE_STRENGTH, .dram_dqm5 = IMX6DQ_DRIVE_STRENGTH, .dram_dqm6 = IMX6DQ_DRIVE_STRENGTH, .dram_dqm7 = IMX6DQ_DRIVE_STRENGTH, .dram_cas = IMX6DQ_DRIVE_STRENGTH, .dram_ras = IMX6DQ_DRIVE_STRENGTH, .dram_sdclk_0 = IMX6DQ_DRIVE_STRENGTH, .dram_sdclk_1 = IMX6DQ_DRIVE_STRENGTH, .dram_reset = IMX6DQ_DRIVE_STRENGTH, .dram_sdcke0 = IMX6DQ_DRIVE_STRENGTH, .dram_sdcke1 = IMX6DQ_DRIVE_STRENGTH, .dram_sdba2 = 0x00000000, .dram_sdodt0 = IMX6DQ_DRIVE_STRENGTH, .dram_sdodt1 = IMX6DQ_DRIVE_STRENGTH, }; /* configure MX6Q/DUAL mmdc GRP io registers */ static struct mx6dq_iomux_grp_regs mx6dq_grp_ioregs = { .grp_b0ds = IMX6DQ_DRIVE_STRENGTH, .grp_b1ds = IMX6DQ_DRIVE_STRENGTH, .grp_b2ds = IMX6DQ_DRIVE_STRENGTH, .grp_b3ds = IMX6DQ_DRIVE_STRENGTH, .grp_b4ds = IMX6DQ_DRIVE_STRENGTH, .grp_b5ds = IMX6DQ_DRIVE_STRENGTH, .grp_b6ds = IMX6DQ_DRIVE_STRENGTH, .grp_b7ds = IMX6DQ_DRIVE_STRENGTH, .grp_addds = IMX6DQ_DRIVE_STRENGTH, .grp_ddrmode_ctl = 0x00020000, .grp_ddrpke = 0x00000000, .grp_ddrmode = 0x00020000, .grp_ctlds = IMX6DQ_DRIVE_STRENGTH, .grp_ddr_type = 0x000c0000, }; /* configure MX6SOLO/DUALLITE mmdc DDR io registers */ struct mx6sdl_iomux_ddr_regs mx6sdl_ddr_ioregs = { .dram_sdclk_0 = IMX6SDL_DRIVE_STRENGTH, .dram_sdclk_1 = IMX6SDL_DRIVE_STRENGTH, .dram_cas = IMX6SDL_DRIVE_STRENGTH, .dram_ras = IMX6SDL_DRIVE_STRENGTH, .dram_reset = IMX6SDL_DRIVE_STRENGTH, .dram_sdcke0 = IMX6SDL_DRIVE_STRENGTH, .dram_sdcke1 = IMX6SDL_DRIVE_STRENGTH, .dram_sdba2 = 0x00000000, .dram_sdodt0 = IMX6SDL_DRIVE_STRENGTH, .dram_sdodt1 = IMX6SDL_DRIVE_STRENGTH, .dram_sdqs0 = IMX6SDL_DRIVE_STRENGTH, .dram_sdqs1 = IMX6SDL_DRIVE_STRENGTH, .dram_sdqs2 = IMX6SDL_DRIVE_STRENGTH, .dram_sdqs3 = IMX6SDL_DRIVE_STRENGTH, .dram_sdqs4 = IMX6SDL_DRIVE_STRENGTH, .dram_sdqs5 = IMX6SDL_DRIVE_STRENGTH, .dram_sdqs6 = IMX6SDL_DRIVE_STRENGTH, .dram_sdqs7 = IMX6SDL_DRIVE_STRENGTH, .dram_dqm0 = IMX6SDL_DRIVE_STRENGTH, .dram_dqm1 = IMX6SDL_DRIVE_STRENGTH, .dram_dqm2 = IMX6SDL_DRIVE_STRENGTH, .dram_dqm3 = IMX6SDL_DRIVE_STRENGTH, .dram_dqm4 = IMX6SDL_DRIVE_STRENGTH, .dram_dqm5 = IMX6SDL_DRIVE_STRENGTH, .dram_dqm6 = IMX6SDL_DRIVE_STRENGTH, .dram_dqm7 = IMX6SDL_DRIVE_STRENGTH, }; /* configure MX6SOLO/DUALLITE mmdc GRP io registers */ struct mx6sdl_iomux_grp_regs mx6sdl_grp_ioregs = { .grp_ddr_type = 0x000c0000, .grp_ddrmode_ctl = 0x00020000, .grp_ddrpke = 0x00000000, .grp_addds = IMX6SDL_DRIVE_STRENGTH, .grp_ctlds = IMX6SDL_DRIVE_STRENGTH, .grp_ddrmode = 0x00020000, .grp_b0ds = IMX6SDL_DRIVE_STRENGTH, .grp_b1ds = IMX6SDL_DRIVE_STRENGTH, .grp_b2ds = IMX6SDL_DRIVE_STRENGTH, .grp_b3ds = IMX6SDL_DRIVE_STRENGTH, .grp_b4ds = IMX6SDL_DRIVE_STRENGTH, .grp_b5ds = IMX6SDL_DRIVE_STRENGTH, .grp_b6ds = IMX6SDL_DRIVE_STRENGTH, .grp_b7ds = IMX6SDL_DRIVE_STRENGTH, }; /* mt41j256 */ static struct mx6_ddr3_cfg mt41j256 = { .mem_speed = 1066, .density = 2, .width = 16, .banks = 8, .rowaddr = 13, .coladdr = 10, .pagesz = 2, .trcd = 1375, .trcmin = 4875, .trasmin = 3500, .SRT = 0, }; static struct mx6_mmdc_calibration mx6dq_mmdc_calib = { .p0_mpwldectrl0 = 0x000E0009, .p0_mpwldectrl1 = 0x0018000E, .p1_mpwldectrl0 = 0x00000007, .p1_mpwldectrl1 = 0x00000000, .p0_mpdgctrl0 = 0x43280334, .p0_mpdgctrl1 = 0x031C0314, .p1_mpdgctrl0 = 0x4318031C, .p1_mpdgctrl1 = 0x030C0258, .p0_mprddlctl = 0x3E343A40, .p1_mprddlctl = 0x383C3844, .p0_mpwrdlctl = 0x40404440, .p1_mpwrdlctl = 0x4C3E4446, }; /* DDR 64bit */ static struct mx6_ddr_sysinfo mem_q = { .ddr_type = DDR_TYPE_DDR3, .dsize = 2, .cs1_mirror = 0, /* config for full 4GB range so that get_mem_size() works */ .cs_density = 32, .ncs = 1, .bi_on = 1, .rtt_nom = 2, .rtt_wr = 2, .ralat = 5, .walat = 0, .mif3_mode = 3, .rst_to_cke = 0x23, .sde_to_rst = 0x10, }; static struct mx6_mmdc_calibration mx6dl_mmdc_calib = { .p0_mpwldectrl0 = 0x001F0024, .p0_mpwldectrl1 = 0x00110018, .p1_mpwldectrl0 = 0x001F0024, .p1_mpwldectrl1 = 0x00110018, .p0_mpdgctrl0 = 0x4230022C, .p0_mpdgctrl1 = 0x02180220, .p1_mpdgctrl0 = 0x42440248, .p1_mpdgctrl1 = 0x02300238, .p0_mprddlctl = 0x44444A48, .p1_mprddlctl = 0x46484A42, .p0_mpwrdlctl = 0x38383234, .p1_mpwrdlctl = 0x3C34362E, }; /* DDR 64bit 1GB */ static struct mx6_ddr_sysinfo mem_dl = { .dsize = 2, .cs1_mirror = 0, /* config for full 4GB range so that get_mem_size() works */ .cs_density = 32, .ncs = 1, .bi_on = 1, .rtt_nom = 1, .rtt_wr = 1, .ralat = 5, .walat = 0, .mif3_mode = 3, .rst_to_cke = 0x23, .sde_to_rst = 0x10, }; /* DDR 32bit 512MB */ static struct mx6_ddr_sysinfo mem_s = { .dsize = 1, .cs1_mirror = 0, /* config for full 4GB range so that get_mem_size() works */ .cs_density = 32, .ncs = 1, .bi_on = 1, .rtt_nom = 1, .rtt_wr = 1, .ralat = 5, .walat = 0, .mif3_mode = 3, .rst_to_cke = 0x23, .sde_to_rst = 0x10, }; #endif /* CONFIG_MX6QDL */ #ifdef CONFIG_MX6UL static struct mx6ul_iomux_grp_regs mx6_grp_ioregs = { .grp_addds = 0x00000030, .grp_ddrmode_ctl = 0x00020000, .grp_b0ds = 0x00000030, .grp_ctlds = 0x00000030, .grp_b1ds = 0x00000030, .grp_ddrpke = 0x00000000, .grp_ddrmode = 0x00020000, .grp_ddr_type = 0x000c0000, }; static struct mx6ul_iomux_ddr_regs mx6_ddr_ioregs = { .dram_dqm0 = 0x00000030, .dram_dqm1 = 0x00000030, .dram_ras = 0x00000030, .dram_cas = 0x00000030, .dram_odt0 = 0x00000030, .dram_odt1 = 0x00000030, .dram_sdba2 = 0x00000000, .dram_sdclk_0 = 0x00000008, .dram_sdqs0 = 0x00000038, .dram_sdqs1 = 0x00000030, .dram_reset = 0x00000030, }; static struct mx6_mmdc_calibration mx6_mmcd_calib = { .p0_mpwldectrl0 = 0x00070007, .p0_mpdgctrl0 = 0x41490145, .p0_mprddlctl = 0x40404546, .p0_mpwrdlctl = 0x4040524D, }; struct mx6_ddr_sysinfo ddr_sysinfo = { .dsize = 0, .cs_density = 20, .ncs = 1, .cs1_mirror = 0, .rtt_wr = 2, .rtt_nom = 1, /* RTT_Nom = RZQ/2 */ .walat = 1, /* Write additional latency */ .ralat = 5, /* Read additional latency */ .mif3_mode = 3, /* Command prediction working mode */ .bi_on = 1, /* Bank interleaving enabled */ .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ .ddr_type = DDR_TYPE_DDR3, }; static struct mx6_ddr3_cfg mem_ddr = { .mem_speed = 800, .density = 4, .width = 16, .banks = 8, #ifdef TARGET_MX6UL_ISIOT .rowaddr = 15, #else .rowaddr = 13, #endif .coladdr = 10, .pagesz = 2, .trcd = 1375, .trcmin = 4875, .trasmin = 3500, }; #endif /* CONFIG_MX6UL */ static void ccgr_init(void) { struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; #ifdef CONFIG_MX6QDL writel(0x00003F3F, &ccm->CCGR0); writel(0x0030FC00, &ccm->CCGR1); writel(0x000FC000, &ccm->CCGR2); writel(0x3F300000, &ccm->CCGR3); writel(0xFF00F300, &ccm->CCGR4); writel(0x0F0000C3, &ccm->CCGR5); writel(0x000003CC, &ccm->CCGR6); #elif CONFIG_MX6UL writel(0x00c03f3f, &ccm->CCGR0); writel(0xfcffff00, &ccm->CCGR1); writel(0x0cffffcc, &ccm->CCGR2); writel(0x3f3c3030, &ccm->CCGR3); writel(0xff00fffc, &ccm->CCGR4); writel(0x033f30ff, &ccm->CCGR5); writel(0x00c00fff, &ccm->CCGR6); #endif } static void spl_dram_init(void) { #ifdef CONFIG_MX6QDL if (is_mx6solo()) { mx6sdl_dram_iocfg(32, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); mx6_dram_cfg(&mem_s, &mx6dl_mmdc_calib, &mt41j256); } else if (is_mx6dl()) { mx6sdl_dram_iocfg(64, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); mx6_dram_cfg(&mem_dl, &mx6dl_mmdc_calib, &mt41j256); } else if (is_mx6dq()) { mx6dq_dram_iocfg(64, &mx6dq_ddr_ioregs, &mx6dq_grp_ioregs); mx6_dram_cfg(&mem_q, &mx6dq_mmdc_calib, &mt41j256); } #elif CONFIG_MX6UL mx6ul_dram_iocfg(mem_ddr.width, &mx6_ddr_ioregs, &mx6_grp_ioregs); mx6_dram_cfg(&ddr_sysinfo, &mx6_mmcd_calib, &mem_ddr); #endif udelay(100); } void board_init_f(ulong dummy) { ccgr_init(); /* setup AIPS and disable watchdog */ arch_cpu_init(); gpr_init(); /* iomux */ SETUP_IOMUX_PADS(uart_pads); /* setup GP timer */ timer_init(); /* UART clocks enabled and gd valid - init serial console */ preloader_console_init(); /* DDR initialization */ spl_dram_init(); }