summaryrefslogtreecommitdiff
path: root/board/kontron
diff options
context:
space:
mode:
authorFrieder Schrempf <frieder.schrempf@kontron.de>2021-09-29 16:42:41 +0200
committerStefano Babic <sbabic@denx.de>2021-10-07 16:53:50 +0200
commite6f48aad153ae901ca3340b3207968e2f9c47f66 (patch)
treeb998a57bd5a69fbfd9e41533e89a136dd47eb478 /board/kontron
parentbc959905df4b31c2b9f77e5745e9d10d229a9bfa (diff)
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/kontron')
-rw-r--r--board/kontron/sl-mx6ul/Kconfig15
-rw-r--r--board/kontron/sl-mx6ul/MAINTAINERS9
-rw-r--r--board/kontron/sl-mx6ul/Makefile8
-rw-r--r--board/kontron/sl-mx6ul/sl-mx6ul.c85
-rw-r--r--board/kontron/sl-mx6ul/spl.c377
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 0000000000..4e58de2094
--- /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 0000000000..0f8b5512d6
--- /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 0000000000..cae273c930
--- /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 0000000000..79d4d8753b
--- /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 0000000000..12b0352146
--- /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;
+}