diff options
author | Frieder Schrempf <frieder.schrempf@kontron.de> | 2021-09-29 16:42:41 +0200 |
---|---|---|
committer | Stefano Babic <sbabic@denx.de> | 2021-10-07 16:53:50 +0200 |
commit | e6f48aad153ae901ca3340b3207968e2f9c47f66 (patch) | |
tree | b998a57bd5a69fbfd9e41533e89a136dd47eb478 /board | |
parent | bc959905df4b31c2b9f77e5745e9d10d229a9bfa (diff) | |
download | u-boot-e6f48aad153ae901ca3340b3207968e2f9c47f66.zip u-boot-e6f48aad153ae901ca3340b3207968e2f9c47f66.tar.gz u-boot-e6f48aad153ae901ca3340b3207968e2f9c47f66.tar.bz2 |
imx: imx6ul: Add support for Kontron Electronics SL/BL i.MX6UL/ULL boards (N63xx/N64xx)
This adds support for i.MX6UL/ULL-based evaluation kits with SoMs by
Kontron Electronics GmbH.
Currently there are the following SoM flavors (SoM-Line):
* N6310: SOM with i.MX6UL-2, 256MB RAM, 256MB SPI NAND
* N6311: SOM with i.MX6UL-2, 512MB RAM, 512MB SPI NAND
* N6411: SOM with i.MX6ULL, 512MB RAM, 512MB SPI NAND
And the according evaluation boards (Board-Line):
* N6310-S: Baseboard with SOM N6310, eMMC, display (optional), ...
* N6311-S: Baseboard with SOM N6311, eMMC, display (optional), ...
* N6411-S: Baseboard with SOM N6411, eMMC, display (optional), ...
Currently U-Boot describes i.MX6UL and i.MX6ULL through separate config
options at compile-time. Though the differences are so minor, that for
the scope of these SoMs we just use a single defconfig that is compatible
with both SoCs.
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Reviewed-by: Stefano Babic <sbabic@denx.de>
Diffstat (limited to 'board')
-rw-r--r-- | board/kontron/sl-mx6ul/Kconfig | 15 | ||||
-rw-r--r-- | board/kontron/sl-mx6ul/MAINTAINERS | 9 | ||||
-rw-r--r-- | board/kontron/sl-mx6ul/Makefile | 8 | ||||
-rw-r--r-- | board/kontron/sl-mx6ul/sl-mx6ul.c | 85 | ||||
-rw-r--r-- | board/kontron/sl-mx6ul/spl.c | 377 |
5 files changed, 494 insertions, 0 deletions
diff --git a/board/kontron/sl-mx6ul/Kconfig b/board/kontron/sl-mx6ul/Kconfig new file mode 100644 index 0000000..4e58de2 --- /dev/null +++ b/board/kontron/sl-mx6ul/Kconfig @@ -0,0 +1,15 @@ +if TARGET_KONTRON_MX6UL + +config SYS_BOARD + string + default "sl-mx6ul" + +config SYS_VENDOR + string + default "kontron" + +config SYS_CONFIG_NAME + string + default "kontron-sl-mx6ul" + +endif diff --git a/board/kontron/sl-mx6ul/MAINTAINERS b/board/kontron/sl-mx6ul/MAINTAINERS new file mode 100644 index 0000000..0f8b551 --- /dev/null +++ b/board/kontron/sl-mx6ul/MAINTAINERS @@ -0,0 +1,9 @@ +Kontron SL/BL i.MX6UL/ULL Boards (N63xx/N64xx) +M: Frieder Schrempf <frieder.schrempf@kontron.de> +S: Maintained +F: arch/arm/dts/imx6ul-kontron-n6* +F: arch/arm/dts/imx6ull-kontron-n6* +F: board/kontron/sl-mx6ul +F: configs/kontron-sl-mx6ul_defconfig +F: doc/board/kontron/sl-mx6ul.rst +F: include/configs/kontron-sl-mx6ul.h diff --git a/board/kontron/sl-mx6ul/Makefile b/board/kontron/sl-mx6ul/Makefile new file mode 100644 index 0000000..cae273c --- /dev/null +++ b/board/kontron/sl-mx6ul/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# (C) Copyright 2018 Kontron Electronics GmbH + +ifdef CONFIG_SPL_BUILD +obj-y := spl.o +else +obj-y := sl-mx6ul.o +endif diff --git a/board/kontron/sl-mx6ul/sl-mx6ul.c b/board/kontron/sl-mx6ul/sl-mx6ul.c new file mode 100644 index 0000000..79d4d87 --- /dev/null +++ b/board/kontron/sl-mx6ul/sl-mx6ul.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Kontron Electronics GmbH + */ + +#include <asm/arch/clock.h> +#include <asm/arch/sys_proto.h> +#include <asm/global_data.h> +#include <fdt_support.h> +#include <phy.h> + +DECLARE_GLOBAL_DATA_PTR; + +int dram_init(void) +{ + gd->ram_size = imx_ddr_size(); + + return 0; +} + +int ft_board_setup(void *blob, struct bd_info *bd) +{ + /* + * Overwrite the memory size in the devicetree that is + * passed to the kernel with the actual size detected. + */ + return fdt_fixup_memory(blob, PHYS_SDRAM, gd->ram_size); +} + +static int setup_fec(void) +{ + struct iomuxc *const iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; + int ret; + + /* + * Use 50M anatop loopback REF_CLK1 for ENET1, + * clear gpr1[13], set gpr1[17]. + */ + clrsetbits_le32(&iomuxc_regs->gpr[1], IOMUX_GPR1_FEC1_MASK, + IOMUX_GPR1_FEC1_CLOCK_MUX1_SEL_MASK); + + /* + * Use 50M anatop loopback REF_CLK2 for ENET2, + * clear gpr1[14], set gpr1[18]. + */ + clrsetbits_le32(&iomuxc_regs->gpr[1], IOMUX_GPR1_FEC2_MASK, + IOMUX_GPR1_FEC2_CLOCK_MUX1_SEL_MASK); + + ret = enable_fec_anatop_clock(0, ENET_50MHZ); + if (ret) + return ret; + + ret = enable_fec_anatop_clock(1, ENET_50MHZ); + if (ret) + return ret; + + return 0; +} + +int board_phy_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, 0x1f, 0x8190); + + if (phydev->drv->config) + phydev->drv->config(phydev); + + return 0; +} + +int board_early_init_f(void) +{ + enable_qspi_clk(0); + + return 0; +} + +int board_init(void) +{ + /* Address of boot parameters */ + gd->bd->bi_boot_params = PHYS_SDRAM + 0x100; + + setup_fec(); + + return 0; +} diff --git a/board/kontron/sl-mx6ul/spl.c b/board/kontron/sl-mx6ul/spl.c new file mode 100644 index 0000000..12b0352 --- /dev/null +++ b/board/kontron/sl-mx6ul/spl.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Kontron Electronics GmbH + */ + +#include <asm/arch/clock.h> +#include <asm/arch/crm_regs.h> +#include <asm/arch/mx6-pins.h> +#include <asm/arch/sys_proto.h> +#include <asm/global_data.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/mach-imx/iomux-v3.h> +#include <fsl_esdhc_imx.h> +#include <init.h> +#include <linux/delay.h> +#include <linux/sizes.h> +#include <linux/errno.h> +#include <mmc.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum { + BOARD_TYPE_KTN_N631X = 1, + BOARD_TYPE_KTN_N641X, + BOARD_TYPE_MAX +}; + +#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) + +#define USDHC_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \ + PAD_CTL_PUS_22K_UP | PAD_CTL_SPEED_LOW | \ + PAD_CTL_DSE_80ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS) + +#define USDHC_CD_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \ + PAD_CTL_PUS_100K_DOWN | PAD_CTL_SPEED_LOW | \ + PAD_CTL_DSE_80ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS) + +#define SPI_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_SPEED_MED | \ + PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST) + +#include <spl.h> +#include <asm/arch/mx6-ddr.h> + +static iomux_v3_cfg_t const usdhc1_pads[] = { + MX6_PAD_SD1_CLK__USDHC1_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_SD1_CMD__USDHC1_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_SD1_DATA0__USDHC1_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_SD1_DATA1__USDHC1_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_SD1_DATA2__USDHC1_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_SD1_DATA3__USDHC1_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL), + + /* CD */ + MX6_PAD_UART1_RTS_B__GPIO1_IO19 | MUX_PAD_CTRL(USDHC_CD_PAD_CTRL), +}; + +#define USDHC1_CD_GPIO IMX_GPIO_NR(1, 19) + +static iomux_v3_cfg_t const usdhc2_pads[] = { + MX6_PAD_NAND_RE_B__USDHC2_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_NAND_WE_B__USDHC2_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_NAND_DATA00__USDHC2_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_NAND_DATA01__USDHC2_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_NAND_DATA02__USDHC2_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL), + MX6_PAD_NAND_DATA03__USDHC2_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL), + /* RST */ + MX6_PAD_NAND_ALE__GPIO4_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL), +}; + +#define USDHC2_PWR_GPIO IMX_GPIO_NR(4, 10) + +static struct fsl_esdhc_cfg usdhc_cfg[2] = { + {USDHC1_BASE_ADDR, 0, 4}, + {USDHC2_BASE_ADDR, 0, 4}, +}; + +int board_mmc_getcd(struct mmc *mmc) +{ + struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; + int ret = 0; + + switch (cfg->esdhc_base) { + case USDHC1_BASE_ADDR: + ret = !gpio_get_value(USDHC1_CD_GPIO); + break; + case USDHC2_BASE_ADDR: + // This SDHC interface does not use a CD pin + ret = 1; + break; + } + + return ret; +} + +int board_mmc_init(struct bd_info *bis) +{ + int i, ret; + + /* + * According to the board_mmc_init() the following map is done: + * (U-boot device node) (Physical Port) + * mmc0 USDHC1 + * mmc1 USDHC2 + */ + for (i = 0; i < CONFIG_SYS_FSL_USDHC_NUM; i++) { + switch (i) { + case 0: + imx_iomux_v3_setup_multiple_pads(usdhc1_pads, ARRAY_SIZE(usdhc1_pads)); + gpio_direction_input(USDHC1_CD_GPIO); + usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); + break; + case 1: + imx_iomux_v3_setup_multiple_pads(usdhc2_pads, ARRAY_SIZE(usdhc2_pads)); + gpio_direction_output(USDHC2_PWR_GPIO, 0); + udelay(500); + gpio_direction_output(USDHC2_PWR_GPIO, 1); + usdhc_cfg[1].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); + break; + default: + printf("Warning: you configured more USDHC controllers (%d) than supported by the board\n", + i + 1); + return -EINVAL; + } + + ret = fsl_esdhc_initialize(bis, &usdhc_cfg[i]); + if (ret) { + printf("Warning: failed to initialize mmc dev %d\n", i); + return ret; + } + } + return 0; +} + +iomux_v3_cfg_t const ecspi2_pads[] = { + MX6_PAD_CSI_DATA00__ECSPI2_SCLK | MUX_PAD_CTRL(SPI_PAD_CTRL), + MX6_PAD_CSI_DATA02__ECSPI2_MOSI | MUX_PAD_CTRL(SPI_PAD_CTRL), + MX6_PAD_CSI_DATA03__ECSPI2_MISO | MUX_PAD_CTRL(SPI_PAD_CTRL), + MX6_PAD_CSI_DATA01__GPIO4_IO22 | MUX_PAD_CTRL(NO_PAD_CTRL), +}; + +int board_spi_cs_gpio(unsigned int bus, unsigned int cs) +{ + return (bus == CONFIG_SF_DEFAULT_BUS && cs == CONFIG_SF_DEFAULT_CS) + ? (IMX_GPIO_NR(4, 22)) : -1; +} + +static void setup_spi(void) +{ + gpio_request(IMX_GPIO_NR(4, 22), "spi2_cs0"); + gpio_direction_output(IMX_GPIO_NR(4, 22), 1); + imx_iomux_v3_setup_multiple_pads(ecspi2_pads, ARRAY_SIZE(ecspi2_pads)); + + enable_spi_clk(true, 1); +} + +static iomux_v3_cfg_t const uart4_pads[] = { + MX6_PAD_UART4_TX_DATA__UART4_DCE_TX | MUX_PAD_CTRL(UART_PAD_CTRL), + MX6_PAD_UART4_RX_DATA__UART4_DCE_RX | MUX_PAD_CTRL(UART_PAD_CTRL), +}; + +static void setup_iomux_uart(void) +{ + imx_iomux_v3_setup_multiple_pads(uart4_pads, ARRAY_SIZE(uart4_pads)); +} + +// DDR 256MB (Hynix H5TQ2G63DFR) +static struct mx6_ddr3_cfg mem_256M_ddr = { + .mem_speed = 800, + .density = 2, + .width = 16, + .banks = 8, + .rowaddr = 14, + .coladdr = 10, + .pagesz = 2, + .trcd = 1350, + .trcmin = 4950, + .trasmin = 3600, +}; + +static struct mx6_mmdc_calibration mx6_mmcd_256M_calib = { + .p0_mpwldectrl0 = 0x00000000, + .p0_mpdgctrl0 = 0x01340134, + .p0_mprddlctl = 0x40405052, + .p0_mpwrdlctl = 0x40404E48, +}; + +// DDR 512MB (Hynix H5TQ4G63DFR) +static struct mx6_ddr3_cfg mem_512M_ddr = { + .mem_speed = 800, + .density = 4, + .width = 16, + .banks = 8, + .rowaddr = 15, + .coladdr = 10, + .pagesz = 2, + .trcd = 1350, + .trcmin = 4950, + .trasmin = 3600, +}; + +static struct mx6_mmdc_calibration mx6_mmcd_512M_calib = { + .p0_mpwldectrl0 = 0x00000000, + .p0_mpdgctrl0 = 0X01440144, + .p0_mprddlctl = 0x40405454, + .p0_mpwrdlctl = 0x40404E4C, +}; + +// Common DDR parameters (256MB and 512MB) +static struct mx6ul_iomux_grp_regs mx6_grp_ioregs = { + .grp_addds = 0x00000028, + .grp_ddrmode_ctl = 0x00020000, + .grp_b0ds = 0x00000028, + .grp_ctlds = 0x00000028, + .grp_b1ds = 0x00000028, + .grp_ddrpke = 0x00000000, + .grp_ddrmode = 0x00020000, + .grp_ddr_type = 0x000c0000, +}; + +static struct mx6ul_iomux_ddr_regs mx6_ddr_ioregs = { + .dram_dqm0 = 0x00000028, + .dram_dqm1 = 0x00000028, + .dram_ras = 0x00000028, + .dram_cas = 0x00000028, + .dram_odt0 = 0x00000028, + .dram_odt1 = 0x00000028, + .dram_sdba2 = 0x00000000, + .dram_sdclk_0 = 0x00000028, + .dram_sdqs0 = 0x00000028, + .dram_sdqs1 = 0x00000028, + .dram_reset = 0x00000028, +}; + +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, + .refsel = 0, /* Refresh cycles at 64KHz */ + .refr = 1, /* 2 refresh commands per refresh cycle */ +}; + +static void ccgr_init(void) +{ + struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + writel(0xFFFFFFFF, &ccm->CCGR0); + writel(0xFFFFFFFF, &ccm->CCGR1); + writel(0xFFFFFFFF, &ccm->CCGR2); + writel(0xFFFFFFFF, &ccm->CCGR3); + writel(0xFFFFFFFF, &ccm->CCGR4); + writel(0xFFFFFFFF, &ccm->CCGR5); + writel(0xFFFFFFFF, &ccm->CCGR6); + writel(0xFFFFFFFF, &ccm->CCGR7); +} + +static void spl_dram_init(void) +{ + unsigned int size; + + // DDR RAM connection is always 16 bit wide. Init IOs. + mx6ul_dram_iocfg(16, &mx6_ddr_ioregs, &mx6_grp_ioregs); + + // Try to detect the 512MB RAM chip first. + mx6_dram_cfg(&ddr_sysinfo, &mx6_mmcd_512M_calib, &mem_512M_ddr); + + // Get the available RAM size + size = get_ram_size((void *)PHYS_SDRAM, SZ_512M); + + gd->ram_size = size; + + if (size == SZ_512M) { + // 512MB RAM was detected + return; + } else if (size == SZ_256M) { + // 256MB RAM was detected, use correct config and calibration + mx6_dram_cfg(&ddr_sysinfo, &mx6_mmcd_256M_calib, &mem_256M_ddr); + } else { + printf("Invalid DDR RAM size detected: %x\n", size); + } +} + +static int do_board_detect(void) +{ + if (is_mx6ul()) + gd->board_type = BOARD_TYPE_KTN_N631X; + else if (is_mx6ull()) + gd->board_type = BOARD_TYPE_KTN_N641X; + + printf("Kontron SL i.MX6UL%s (N6%s1x) module, %lu MB RAM detected\n", + is_mx6ull() ? "L" : "", is_mx6ull() ? "4" : "3", gd->ram_size / SZ_1M); + + return 0; +} + +void board_init_f(ulong dummy) +{ + ccgr_init(); + + /* setup AIPS and disable watchdog */ + arch_cpu_init(); + + /* iomux and setup of UART and SPI */ + board_early_init_f(); + + /* setup GP timer */ + timer_init(); + + /* UART clocks enabled and gd valid - init serial console */ + preloader_console_init(); + + /* DDR initialization */ + spl_dram_init(); + + /* Clear the BSS. */ + memset(__bss_start, 0, __bss_end - __bss_start); + + /* Detect the board type */ + do_board_detect(); + + /* load/boot image from boot device */ + board_init_r(NULL, 0); +} + +void board_boot_order(u32 *spl_boot_list) +{ + u32 bootdev = spl_boot_device(); + + /* + * The default boot fuse settings use the SD card (MMC1) as primary + * boot device, but allow SPI NOR as a fallback boot device. + * We can't detect the fallback case and spl_boot_device() will return + * BOOT_DEVICE_MMC1 despite the actual boot device being SPI NOR. + * Therefore we try to load U-Boot proper vom SPI NOR after loading + * from MMC has failed. + */ + spl_boot_list[0] = bootdev; + + switch (bootdev) { + case BOOT_DEVICE_MMC1: + case BOOT_DEVICE_MMC2: + spl_boot_list[1] = BOOT_DEVICE_SPI; + break; + } +} + +int board_early_init_f(void) +{ + setup_iomux_uart(); + setup_spi(); + + return 0; +} + +int board_fit_config_name_match(const char *name) +{ + if (gd->board_type == BOARD_TYPE_KTN_N631X && is_mx6ul() && + !strcmp(name, "imx6ul-kontron-n631x-s")) + return 0; + + if (gd->board_type == BOARD_TYPE_KTN_N641X && is_mx6ull() && + !strcmp(name, "imx6ull-kontron-n641x-s")) + return 0; + + return -1; +} |