imx: add imx8x capricorn giedi board

Add support for i.MX8X based Capricorn Giedi SoM.

Supported interfaces: GPIO, ENET, eMMC, I2C, UART.

Console output:

  U-Boot SPL 2020.01-00003-gfd1c98f (Jan 07 2020 - 15:51:25 +0100)
  Trying to boot from MMC1
  Load image from MMC/SD 0x3e400

  U-Boot 2020.01-00003-gfd1c98f (Jan 07 2020 - 15:51:25 +0100) ##v01.07

  CPU:   NXP i.MX8QXP RevB A35 at 1200 MHz at 30C

  Model: Siemens Giedi
  Board: Capricorn
  Boot:  MMC0
  DRAM:  1022 MiB
  MMC:   FSL_SDHC: 0
  Loading Environment from MMC... OK
  In:    serial@5a080000
  Out:   serial@5a080000
  Err:   serial@5a080000
  Net:   eth1: ethernet@5b050000 [PRIME]
  Autobooting in 1 seconds, press "<Esc><Esc>" to stop

Signed-off-by: Anatolij Gustschin <agust@denx.de>
diff --git a/board/siemens/capricorn/Kconfig b/board/siemens/capricorn/Kconfig
new file mode 100644
index 0000000..ed1f793
--- /dev/null
+++ b/board/siemens/capricorn/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_GIEDI
+
+config SYS_BOARD
+	default "capricorn"
+
+config SYS_VENDOR
+	default "siemens"
+
+config SYS_CONFIG_NAME
+	default "giedi"
+
+endif
diff --git a/board/siemens/capricorn/MAINTAINERS b/board/siemens/capricorn/MAINTAINERS
new file mode 100644
index 0000000..5d81aaf
--- /dev/null
+++ b/board/siemens/capricorn/MAINTAINERS
@@ -0,0 +1,9 @@
+CAPRICORN BOARD
+M:	Anatolij Gustschin <agust@denx.de>
+S:	Maintained
+F:	board/siemens/capricorn/
+F:	include/configs/capricorn-common.h
+F:	include/configs/giedi.h
+F:	include/configs/siemens-ccp-common.h
+F:	include/configs/siemens-env-common.h
+F:	configs/giedi_defconfig
diff --git a/board/siemens/capricorn/Makefile b/board/siemens/capricorn/Makefile
new file mode 100644
index 0000000..d5846cc
--- /dev/null
+++ b/board/siemens/capricorn/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 Siemens AG
+#
+
+obj-y += board.o
+
+ifdef CONFIG_SPL_BUILD
+obj-y += spl.o
+else
+obj-y += ../common/factoryset.o
+endif
diff --git a/board/siemens/capricorn/board.c b/board/siemens/capricorn/board.c
new file mode 100644
index 0000000..00fd4b9
--- /dev/null
+++ b/board/siemens/capricorn/board.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2017-2019 NXP
+ *
+ * Copyright 2019 Siemens AG
+ *
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <netdev.h>
+#include <env_internal.h>
+#include <fsl_esdhc_imx.h>
+#include <i2c.h>
+#include <led.h>
+#include <pca953x.h>
+#include <power-domain.h>
+#include <asm/gpio.h>
+#include <asm/arch/imx8-pins.h>
+#include <asm/arch/iomux.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/sys_proto.h>
+#ifndef CONFIG_SPL
+#include <asm/arch-imx8/clock.h>
+#endif
+#include "../common/factoryset.h"
+
+#define GPIO_PAD_CTRL \
+		((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
+		 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+		 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
+		 (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+#define ENET_NORMAL_PAD_CTRL \
+		((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \
+		 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+		 (SC_PAD_28FDSOI_DSE_18V_10MA << PADRING_DSE_SHIFT) | \
+		 (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+#define UART_PAD_CTRL \
+		((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
+		 (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+		 (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \
+		 (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT))
+
+static iomux_cfg_t uart2_pads[] = {
+	SC_P_UART2_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
+	SC_P_UART2_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
+};
+
+static void setup_iomux_uart(void)
+{
+	imx8_iomux_setup_multiple_pads(uart2_pads, ARRAY_SIZE(uart2_pads));
+}
+
+int board_early_init_f(void)
+{
+	/* Set UART clock root to 80 MHz */
+	sc_pm_clock_rate_t rate = SC_80MHZ;
+	int ret;
+
+	ret = sc_pm_setup_uart(SC_R_UART_0, rate);
+	ret |= sc_pm_setup_uart(SC_R_UART_2, rate);
+	if (ret)
+		return ret;
+
+	setup_iomux_uart();
+
+	return 0;
+}
+
+#define ENET_PHY_RESET	IMX_GPIO_NR(0, 3)
+#define ENET_TEST_1	IMX_GPIO_NR(0, 8)
+#define ENET_TEST_2	IMX_GPIO_NR(0, 9)
+
+/*#define ETH_IO_TEST*/
+static iomux_cfg_t enet_reset[] = {
+	SC_P_ESAI0_SCKT | MUX_MODE_ALT(4) | MUX_PAD_CTRL(GPIO_PAD_CTRL),
+#ifdef ETH_IO_TEST
+	/* GPIO0.IO08 MODE3: TXD0 */
+	SC_P_ESAI0_TX4_RX1 | MUX_MODE_ALT(4) |
+	MUX_PAD_CTRL(ENET_NORMAL_PAD_CTRL),
+	/* GPIO0.IO09 MODE3: TXD1 */
+	SC_P_ESAI0_TX5_RX0 | MUX_MODE_ALT(4) |
+	MUX_PAD_CTRL(ENET_NORMAL_PAD_CTRL),
+#endif
+};
+
+static void enet_device_phy_reset(void)
+{
+	int ret = 0;
+
+	imx8_iomux_setup_multiple_pads(enet_reset, ARRAY_SIZE(enet_reset));
+
+	ret = gpio_request(ENET_PHY_RESET, "enet_phy_reset");
+	if (!ret) {
+		gpio_direction_output(ENET_PHY_RESET, 1);
+		gpio_set_value(ENET_PHY_RESET, 0);
+		/* SMSC9303 TRM chapter 14.5.2 */
+		udelay(200);
+		gpio_set_value(ENET_PHY_RESET, 1);
+	} else {
+		printf("ENET RESET failed!\n");
+	}
+
+#ifdef ETH_IO_TEST
+	ret =  gpio_request(ENET_TEST_1, "enet_test1");
+	if (!ret) {
+		int i;
+
+		printf("ENET TEST 1!\n");
+		for (i = 0; i < 20; i++) {
+			gpio_direction_output(ENET_TEST_1, 1);
+			gpio_set_value(ENET_TEST_1, 0);
+			udelay(50);
+			gpio_set_value(ENET_TEST_1, 1);
+			udelay(50);
+		}
+		gpio_free(ENET_TEST_1);
+	} else {
+		printf("GPIO for ENET TEST 1 failed!\n");
+	}
+	ret =  gpio_request(ENET_TEST_2, "enet_test2");
+	if (!ret) {
+		int i;
+
+		printf("ENET TEST 2!\n");
+		for (i = 0; i < 20; i++) {
+			gpio_direction_output(ENET_TEST_2, 1);
+			gpio_set_value(ENET_TEST_2, 0);
+			udelay(50);
+			gpio_set_value(ENET_TEST_2, 1);
+			udelay(50);
+		}
+		gpio_free(ENET_TEST_2);
+	} else {
+		printf("GPIO for ENET TEST 2 failed!\n");
+	}
+#endif
+}
+
+int setup_gpr_fec(void)
+{
+	sc_ipc_t ipc_handle = -1;
+	sc_err_t err = 0;
+	unsigned int test;
+
+	/*
+	 * TX_CLK_SEL: it controls a mux between clock coming from the pad 50M
+	 * input pin and clock generated internally to connectivity subsystem
+	 *	0: internal clock
+	 *	1: external clock --->  your choice for RMII
+	 *
+	 * CLKDIV_SEL: it controls a div by 2 on the internal clock path à
+	 *	it should be don’t care when using external clock
+	 *	0: non-divided clock
+	 *	1: clock divided by 2
+	 * 50_DISABLE or 125_DISABLE:
+	 *	it’s used to disable the clock tree going outside the chip
+	 *	when reference clock is generated internally.
+	 *	It should be don’t care when reference clock is provided
+	 *	externally.
+	 *	0: clock is enabled
+	 *	1: clock is disabled
+	 *
+	 * SC_C_TXCLK		= 24,
+	 * SC_C_CLKDIV		= 25,
+	 * SC_C_DISABLE_50	= 26,
+	 * SC_C_DISABLE_125	= 27,
+	 */
+
+	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, 1);
+	if (err != SC_ERR_NONE)
+		printf("Error in setting up SC_C %d\n\r", SC_C_TXCLK);
+
+	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test);
+	debug("TEST SC_C %d-->%d\n\r", SC_C_TXCLK, test);
+
+	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_CLKDIV, 0);
+	if (err != SC_ERR_NONE)
+		printf("Error in setting up SC_C %d\n\r", SC_C_CLKDIV);
+
+	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_CLKDIV, &test);
+	debug("TEST SC_C %d-->%d\n\r", SC_C_CLKDIV, test);
+
+	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_DISABLE_50, 0);
+	if (err != SC_ERR_NONE)
+		printf("Error in setting up SC_C %d\n\r", SC_C_DISABLE_50);
+
+	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test);
+	debug("TEST SC_C %d-->%d\n\r", SC_C_DISABLE_50, test);
+
+	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_DISABLE_125, 1);
+	if (err != SC_ERR_NONE)
+		printf("Error in setting up SC_C %d\n\r", SC_C_DISABLE_125);
+
+	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test);
+	debug("TEST SC_C %d-->%d\n\r", SC_C_DISABLE_125, test);
+
+	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_SEL_125, 1);
+	if (err != SC_ERR_NONE)
+		printf("Error in setting up SC_C %d\n\r", SC_C_SEL_125);
+
+	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_SEL_125, &test);
+	debug("TEST SC_C %d-->%d\n\r", SC_C_SEL_125, test);
+
+	return 0;
+}
+
+#if IS_ENABLED(CONFIG_FEC_MXC)
+#include <miiphy.h>
+int board_phy_config(struct phy_device *phydev)
+{
+	if (phydev->drv->config)
+		phydev->drv->config(phydev);
+
+	return 0;
+}
+
+#endif
+
+static int setup_fec(void)
+{
+	setup_gpr_fec();
+	/* Reset ENET PHY */
+	enet_device_phy_reset();
+	return 0;
+}
+
+void reset_cpu(ulong addr)
+{
+}
+
+#ifndef CONFIG_SPL_BUILD
+/* LED's */
+static int board_led_init(void)
+{
+	struct udevice *bus, *dev;
+	u8 pca_led[2] = { 0x00, 0x00 };
+	int ret;
+
+	/* init all GPIO LED's */
+	if (IS_ENABLED(CONFIG_LED))
+		led_default_state();
+
+	/* enable all leds on PCA9552 */
+	ret = uclass_get_device_by_seq(UCLASS_I2C, PCA9552_1_I2C_BUS, &bus);
+	if (ret) {
+		printf("ERROR: I2C get %d\n", ret);
+		return ret;
+	}
+
+	ret = dm_i2c_probe(bus, PCA9552_1_I2C_ADDR, 0, &dev);
+	if (ret) {
+		printf("ERROR: PCA9552 probe failed\n");
+		return ret;
+	}
+
+	ret = dm_i2c_write(dev, 0x16, pca_led, sizeof(pca_led));
+	if (ret) {
+		printf("ERROR: PCA9552 write failed\n");
+		return ret;
+	}
+
+	mdelay(1);
+	return ret;
+}
+#endif /* !CONFIG_SPL_BUILD */
+
+int checkboard(void)
+{
+	puts("Board: Capricorn\n");
+
+	/*
+	 * Running build_info() doesn't work with current SCFW blob.
+	 * Uncomment below call when new blob is available.
+	 */
+	/*build_info();*/
+
+	print_bootinfo();
+	return 0;
+}
+
+int board_init(void)
+{
+	setup_fec();
+	return 0;
+}
+
+#ifdef CONFIG_OF_BOARD_SETUP
+int ft_board_setup(void *blob, bd_t *bd)
+{
+	return 0;
+}
+#endif
+
+int board_mmc_get_env_dev(int devno)
+{
+	return devno;
+}
+
+static int check_mmc_autodetect(void)
+{
+	char *autodetect_str = env_get("mmcautodetect");
+
+	if (autodetect_str && (strcmp(autodetect_str, "yes") == 0))
+		return 1;
+
+	return 0;
+}
+
+/* This should be defined for each board */
+__weak int mmc_map_to_kernel_blk(int dev_no)
+{
+	return dev_no;
+}
+
+void board_late_mmc_env_init(void)
+{
+	char cmd[32];
+	char mmcblk[32];
+	u32 dev_no = mmc_get_env_dev();
+
+	if (!check_mmc_autodetect())
+		return;
+
+	env_set_ulong("mmcdev", dev_no);
+
+	/* Set mmcblk env */
+	sprintf(mmcblk, "/dev/mmcblk%dp2 rootwait rw",
+		mmc_map_to_kernel_blk(dev_no));
+	env_set("mmcroot", mmcblk);
+
+	sprintf(cmd, "mmc dev %d", dev_no);
+	run_command(cmd, 0);
+}
+
+#ifndef CONFIG_SPL_BUILD
+int factoryset_read_eeprom(int i2c_addr);
+
+static int load_parameters_from_factoryset(void)
+{
+	int ret;
+
+	ret = factoryset_read_eeprom(EEPROM_I2C_ADDR);
+	if (ret)
+		return ret;
+
+	return factoryset_env_set();
+}
+
+int board_late_init(void)
+{
+	env_set("sec_boot", "no");
+#ifdef CONFIG_AHAB_BOOT
+	env_set("sec_boot", "yes");
+#endif
+
+#ifdef CONFIG_ENV_IS_IN_MMC
+	board_late_mmc_env_init();
+#endif
+	/* Init LEDs */
+	if (board_led_init())
+		printf("I2C LED init failed\n");
+
+	/* Set environment from factoryset */
+	if (load_parameters_from_factoryset())
+		printf("Loading factoryset parameters failed!\n");
+
+	return 0;
+}
+
+/* Service button */
+#define MAX_PIN_NUMBER			128
+#define BOARD_DEFAULT_BUTTON_GPIO	IMX_GPIO_NR(1, 31)
+
+unsigned char get_button_state(char * const envname, unsigned char def)
+{
+	int button = 0;
+	int gpio;
+	char *ptr_env;
+
+	/* If button is not found we take default */
+	ptr_env = env_get(envname);
+	if (!ptr_env) {
+		printf("Using default: %u\n", def);
+		gpio = def;
+	} else {
+		gpio = (unsigned char)simple_strtoul(ptr_env, NULL, 0);
+		if (gpio > MAX_PIN_NUMBER)
+			gpio = def;
+	}
+
+	gpio_request(gpio, "");
+	gpio_direction_input(gpio);
+	if (gpio_get_value(gpio))
+		button = 1;
+	else
+		button = 0;
+
+	gpio_free(gpio);
+
+	return button;
+}
+
+/*
+ * This command returns the status of the user button on
+ * Input - none
+ * Returns -	1 if button is held down
+ *		0 if button is not held down
+ */
+static int
+do_userbutton(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int button = 0;
+
+	button = get_button_state("button_usr1", BOARD_DEFAULT_BUTTON_GPIO);
+
+	if (argc > 1)
+		printf("Button state: %u\n", button);
+
+	return button;
+}
+
+U_BOOT_CMD(
+	usrbutton, CONFIG_SYS_MAXARGS, 2, do_userbutton,
+	"Return the status of user button",
+	"[print]"
+);
+
+#define ERST	IMX_GPIO_NR(0, 3)
+
+static int
+do_eth_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	gpio_request(ERST, "ERST");
+	gpio_direction_output(ERST, 0);
+	udelay(200);
+	gpio_set_value(ERST, 1);
+	return 0;
+}
+
+U_BOOT_CMD(
+	switch_rst, CONFIG_SYS_MAXARGS, 2, do_eth_reset,
+	"Reset eth phy",
+	"[print]"
+);
+#endif /* ! CONFIG_SPL_BUILD */
diff --git a/board/siemens/capricorn/imximage.cfg b/board/siemens/capricorn/imximage.cfg
new file mode 100644
index 0000000..8660e50
--- /dev/null
+++ b/board/siemens/capricorn/imximage.cfg
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ *
+ * Refer doc/README.imx8image for more details about how-to configure
+ * and create imx8image boot image
+ */
+
+#define __ASSEMBLY__
+
+/* Boot from SD, sector size 0x400 */
+BOOT_FROM SD 0x400
+/* SoC type IMX8QX */
+SOC_TYPE IMX8QX
+/* Append seco container image */
+APPEND ahab-container.img
+/* Create the 2nd container */
+CONTAINER
+/* Add scfw image with exec attribute */
+IMAGE SCU capricorn-scfw-tcm.bin
+/* Add ATF image with exec attribute */
+IMAGE A35 spl/u-boot-spl.bin 0x00100000
diff --git a/board/siemens/capricorn/spl.c b/board/siemens/capricorn/spl.c
new file mode 100644
index 0000000..47fe86c
--- /dev/null
+++ b/board/siemens/capricorn/spl.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ *
+ * Copyright 2019 Siemens AG
+ *
+ */
+#include <common.h>
+#include <spl.h>
+#include <dm.h>
+#include <dm/uclass.h>
+#include <dm/device.h>
+#include <dm/uclass-internal.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void spl_board_init(void)
+{
+	struct udevice *dev;
+
+	uclass_find_first_device(UCLASS_MISC, &dev);
+
+	for (; dev; uclass_find_next_device(&dev)) {
+		if (device_probe(dev))
+			continue;
+	}
+
+	arch_cpu_init();
+
+	board_early_init_f();
+
+	timer_init();
+
+	preloader_console_init();
+}
+
+void board_init_f(ulong dummy)
+{
+	/* Clear global data */
+	memset((void *)gd, 0, sizeof(gd_t));
+
+	/* Clear the BSS. */
+	memset(__bss_start, 0, __bss_end - __bss_start);
+
+	board_init_r(NULL, 0);
+}
diff --git a/board/siemens/capricorn/uboot-container.cfg b/board/siemens/capricorn/uboot-container.cfg
new file mode 100644
index 0000000..8165811
--- /dev/null
+++ b/board/siemens/capricorn/uboot-container.cfg
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 NXP
+ */
+
+#define __ASSEMBLY__
+
+/* This file is to create a container image could be loaded by SPL */
+BOOT_FROM SD 0x400
+SOC_TYPE IMX8QX
+CONTAINER
+IMAGE A35 bl31.bin	0x80000000
+IMAGE A35 u-boot.bin	CONFIG_SYS_TEXT_BASE
diff --git a/board/siemens/common/factoryset.c b/board/siemens/common/factoryset.c
index 7715ddf..0d3701c 100644
--- a/board/siemens/common/factoryset.c
+++ b/board/siemens/common/factoryset.c
@@ -13,7 +13,9 @@
 #include <env_internal.h>
 #include <i2c.h>
 #include <asm/io.h>
+#if !CONFIG_IS_ENABLED(TARGET_GIEDI) && !CONFIG_IS_ENABLED(TARGET_DENEB)
 #include <asm/arch/cpu.h>
+#endif
 #include <asm/arch/sys_proto.h>
 #include <asm/unaligned.h>
 #include <net.h>