arm: imx: add i.MX53 Beckhoff CX9020 Embedded PC

Add CX9020 board based on mx53loco.
Add simplified imx53 base device tree from kernel v4.8-rc8, to reuse
serial_mxc with DTE and prepare for device tree migration of other
functions and imx53 devices.

The CX9020 differs from i.MX53 Quick Start Board by:
- use uart2 instead of uart1
- DVI-D connector instead of VGA
- no audio
- CCAT FPGA connected to emi
- enable rtc

Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>
diff --git a/board/beckhoff/mx53cx9020/Kconfig b/board/beckhoff/mx53cx9020/Kconfig
new file mode 100644
index 0000000..dcdafb6
--- /dev/null
+++ b/board/beckhoff/mx53cx9020/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_MX53CX9020
+
+config SYS_BOARD
+	default "mx53cx9020"
+
+config SYS_VENDOR
+	default "beckhoff"
+
+config SYS_CONFIG_NAME
+	default "mx53cx9020"
+
+endif
diff --git a/board/beckhoff/mx53cx9020/MAINTAINERS b/board/beckhoff/mx53cx9020/MAINTAINERS
new file mode 100644
index 0000000..f84413e
--- /dev/null
+++ b/board/beckhoff/mx53cx9020/MAINTAINERS
@@ -0,0 +1,6 @@
+MX53 CX9020
+M:	Patrick Bruenn <p.bruenn@beckhoff.com>
+S:	Maintained
+F:	board/beckhoff/mx53cx9020/
+F:	include/configs/mx53cx9020.h
+F:	configs/mx53cx9020_defconfig
diff --git a/board/beckhoff/mx53cx9020/Makefile b/board/beckhoff/mx53cx9020/Makefile
new file mode 100644
index 0000000..a01c0f1
--- /dev/null
+++ b/board/beckhoff/mx53cx9020/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (C) 2015  Beckhoff Automation GmbH & Co. KG
+# Patrick Bruenn <p.bruenn@beckhoff.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y               += mx53cx9020.o
+obj-$(CONFIG_VIDEO) += mx53cx9020_video.o
diff --git a/board/beckhoff/mx53cx9020/imximage.cfg b/board/beckhoff/mx53cx9020/imximage.cfg
new file mode 100644
index 0000000..a11d04c
--- /dev/null
+++ b/board/beckhoff/mx53cx9020/imximage.cfg
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015  Beckhoff Automation GmbH
+ * Patrick Bruenn <p.bruenn@beckhoff.com>
+ *
+ * Based on <u-boot>/board/freescale/mx53loco/imximage.cfg
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* image version */
+IMAGE_VERSION 2
+
+/*
+ * Boot Device : one of
+ * spi, sd (the board has no nand neither onenand)
+ */
+BOOT_FROM	sd
+
+/*
+ * Device Configuration Data (DCD)
+ *
+ * Each entry must have the format:
+ * Addr-type           Address        Value
+ *
+ * where:
+ *	Addr-type register length (1,2 or 4 bytes)
+ *	Address	  absolute address of the register
+ *	value	  value to be stored in the register
+ */
+DATA 4 0x53fa8554 0x00300000
+DATA 4 0x53fa8558 0x00300040
+DATA 4 0x53fa8560 0x00300000
+DATA 4 0x53fa8564 0x00300040
+DATA 4 0x53fa8568 0x00300040
+DATA 4 0x53fa8570 0x00300000
+DATA 4 0x53fa8574 0x00300000
+DATA 4 0x53fa8578 0x00300000
+DATA 4 0x53fa857c 0x00300040
+DATA 4 0x53fa8580 0x00300040
+DATA 4 0x53fa8584 0x00300000
+DATA 4 0x53fa8588 0x00300000
+DATA 4 0x53fa8590 0x00300040
+DATA 4 0x53fa8594 0x00300000
+DATA 4 0x53fa86f0 0x00300000
+DATA 4 0x53fa86f4 0x00000000
+DATA 4 0x53fa86fc 0x00000000
+DATA 4 0x53fa8714 0x00000000
+DATA 4 0x53fa8718 0x00300000
+DATA 4 0x53fa871c 0x00300000
+DATA 4 0x53fa8720 0x00300000
+DATA 4 0x53fa8724 0x00000000
+DATA 4 0x53fa8728 0x00300000
+DATA 4 0x53fa872c 0x00300000
+DATA 4 0x63fd9088 0x35343535
+DATA 4 0x63fd9090 0x4d444c44
+DATA 4 0x63fd907c 0x01370138
+DATA 4 0x63fd9080 0x013b013c
+DATA 4 0x63fd9018 0x00011740
+DATA 4 0x63fd9000 0x83190000
+DATA 4 0x63fd900c 0x40425333
+DATA 4 0x63fd9010 0xb68e8a63
+DATA 4 0x63fd9014 0x01ff00db
+DATA 4 0x63fd902c 0x000026d2
+DATA 4 0x63fd9030 0x009f0e21
+DATA 4 0x63fd9008 0x12273030
+DATA 4 0x63fd9004 0x0002002d
+DATA 4 0x63fd901c 0x00008032
+DATA 4 0x63fd901c 0x00008033
+DATA 4 0x63fd901c 0x00028031
+DATA 4 0x63fd901c 0x052080b0
+DATA 4 0x63fd901c 0x04008040
+DATA 4 0x63fd9000 0xc3190000
+DATA 4 0x63fd901c 0x0000803a
+DATA 4 0x63fd901c 0x0000803b
+DATA 4 0x63fd901c 0x00028039
+DATA 4 0x63fd901c 0x05208138
+DATA 4 0x63fd901c 0x04008048
+DATA 4 0x63fd9020 0x00005800
+DATA 4 0x63fd9040 0x05380003
+DATA 4 0x63fd9058 0x00022227
+DATA 4 0x63fd901c 0x00000000
diff --git a/board/beckhoff/mx53cx9020/mx53cx9020.c b/board/beckhoff/mx53cx9020/mx53cx9020.c
new file mode 100644
index 0000000..9b3ac22
--- /dev/null
+++ b/board/beckhoff/mx53cx9020/mx53cx9020.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2015  Beckhoff Automation GmbH & Co. KG
+ * Patrick Bruenn <p.bruenn@beckhoff.com>
+ *
+ * Based on <u-boot>/board/freescale/mx53loco/mx53loco.c
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/iomux-mx53.h>
+#include <asm/arch/clock.h>
+#include <asm/imx-common/mx5_video.h>
+#include <ACEX1K.h>
+#include <netdev.h>
+#include <i2c.h>
+#include <mmc.h>
+#include <fsl_esdhc.h>
+#include <asm/gpio.h>
+#include <linux/fb.h>
+#include <ipu_pixfmt.h>
+#include <fs.h>
+#include <dm/platdata.h>
+#include <dm/platform_data/serial_mxc.h>
+
+enum LED_GPIOS {
+	GPIO_SD1_CD = IMX_GPIO_NR(1, 1),
+	GPIO_SD2_CD = IMX_GPIO_NR(1, 4),
+	GPIO_LED_SD2_R = IMX_GPIO_NR(3, 16),
+	GPIO_LED_SD2_B = IMX_GPIO_NR(3, 17),
+	GPIO_LED_SD2_G = IMX_GPIO_NR(3, 18),
+	GPIO_LED_SD1_R = IMX_GPIO_NR(3, 19),
+	GPIO_LED_SD1_B = IMX_GPIO_NR(3, 20),
+	GPIO_LED_SD1_G = IMX_GPIO_NR(3, 21),
+	GPIO_LED_PWR_R = IMX_GPIO_NR(3, 22),
+	GPIO_LED_PWR_B = IMX_GPIO_NR(3, 23),
+	GPIO_LED_PWR_G = IMX_GPIO_NR(3, 24),
+	GPIO_SUPS_INT = IMX_GPIO_NR(3, 31),
+	GPIO_C3_CONFIG = IMX_GPIO_NR(6, 8),
+	GPIO_C3_STATUS = IMX_GPIO_NR(6, 7),
+	GPIO_C3_DONE = IMX_GPIO_NR(6, 9),
+};
+
+#define CCAT_BASE_ADDR ((void *)0xf0000000)
+#define CCAT_END_ADDR (CCAT_BASE_ADDR + (1024 * 1024 * 32))
+#define CCAT_SIZE 1191788
+#define CCAT_SIGN_ADDR (CCAT_BASE_ADDR + 12)
+static const char CCAT_SIGNATURE[] = "CCAT";
+
+static const u32 CCAT_MODE_CONFIG = 0x0024DC81;
+static const u32 CCAT_MODE_RUN = 0x0033DC8F;
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static uint32_t mx53_dram_size[2];
+
+phys_size_t get_effective_memsize(void)
+{
+	/*
+	 * WARNING: We must override get_effective_memsize() function here
+	 * to report only the size of the first DRAM bank. This is to make
+	 * U-Boot relocator place U-Boot into valid memory, that is, at the
+	 * end of the first DRAM bank. If we did not override this function
+	 * like so, U-Boot would be placed at the address of the first DRAM
+	 * bank + total DRAM size - sizeof(uboot), which in the setup where
+	 * each DRAM bank contains 512MiB of DRAM would result in placing
+	 * U-Boot into invalid memory area close to the end of the first
+	 * DRAM bank.
+	 */
+	return mx53_dram_size[0];
+}
+
+int dram_init(void)
+{
+	mx53_dram_size[0] = get_ram_size((void *)PHYS_SDRAM_1, 1 << 30);
+	mx53_dram_size[1] = get_ram_size((void *)PHYS_SDRAM_2, 1 << 30);
+
+	gd->ram_size = mx53_dram_size[0] + mx53_dram_size[1];
+
+	return 0;
+}
+
+void dram_init_banksize(void)
+{
+	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+	gd->bd->bi_dram[0].size = mx53_dram_size[0];
+
+	gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
+	gd->bd->bi_dram[1].size = mx53_dram_size[1];
+}
+
+u32 get_board_rev(void)
+{
+	struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
+	struct fuse_bank *bank = &iim->bank[0];
+	struct fuse_bank0_regs *fuse =
+	    (struct fuse_bank0_regs *)bank->fuse_regs;
+
+	int rev = readl(&fuse->gp[6]);
+
+	return (get_cpu_rev() & ~(0xF << 8)) | (rev & 0xF) << 8;
+}
+
+/*
+ * Set CCAT mode
+ * @mode: use CCAT_MODE_CONFIG or CCAT_MODE_RUN
+ */
+void weim_cs0_settings(u32 mode)
+{
+	struct weim *weim_regs = (struct weim *)WEIM_BASE_ADDR;
+
+	writel(0x0, &weim_regs->cs0gcr1);
+	writel(mode, &weim_regs->cs0gcr1);
+	writel(0x00001002, &weim_regs->cs0gcr2);
+
+	writel(0x04000000, &weim_regs->cs0rcr1);
+	writel(0x00000000, &weim_regs->cs0rcr2);
+
+	writel(0x04000000, &weim_regs->cs0wcr1);
+	writel(0x00000000, &weim_regs->cs0wcr2);
+}
+
+static void setup_gpio_eim(void)
+{
+	gpio_direction_input(GPIO_C3_STATUS);
+	gpio_direction_input(GPIO_C3_DONE);
+	gpio_direction_output(GPIO_C3_CONFIG, 1);
+
+	weim_cs0_settings(CCAT_MODE_RUN);
+}
+
+static void setup_gpio_sups(void)
+{
+	gpio_direction_input(GPIO_SUPS_INT);
+
+	static const int BLINK_INTERVALL = 50000;
+	int status = 1;
+	while (gpio_get_value(GPIO_SUPS_INT)) {
+		/* signal "CX SUPS power fail" */
+		gpio_set_value(GPIO_LED_PWR_R,
+			       (++status / BLINK_INTERVALL) % 2);
+	}
+
+	/* signal "CX power up" */
+	gpio_set_value(GPIO_LED_PWR_R, 1);
+}
+
+static void setup_gpio_leds(void)
+{
+	gpio_direction_output(GPIO_LED_SD2_R, 0);
+	gpio_direction_output(GPIO_LED_SD2_B, 0);
+	gpio_direction_output(GPIO_LED_SD2_G, 0);
+	gpio_direction_output(GPIO_LED_SD1_R, 0);
+	gpio_direction_output(GPIO_LED_SD1_B, 0);
+	gpio_direction_output(GPIO_LED_SD1_G, 0);
+	gpio_direction_output(GPIO_LED_PWR_R, 0);
+	gpio_direction_output(GPIO_LED_PWR_B, 0);
+	gpio_direction_output(GPIO_LED_PWR_G, 0);
+}
+
+#ifdef CONFIG_USB_EHCI_MX5
+int board_ehci_hcd_init(int port)
+{
+	/* request VBUS power enable pin, GPIO7_8 */
+	gpio_direction_output(IMX_GPIO_NR(7, 8), 1);
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_FSL_ESDHC
+struct fsl_esdhc_cfg esdhc_cfg[2] = {
+	{MMC_SDHC1_BASE_ADDR},
+	{MMC_SDHC2_BASE_ADDR},
+};
+
+int board_mmc_getcd(struct mmc *mmc)
+{
+	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+	int ret;
+
+	gpio_direction_input(GPIO_SD1_CD);
+	gpio_direction_input(GPIO_SD2_CD);
+
+	if (cfg->esdhc_base == MMC_SDHC1_BASE_ADDR)
+		ret = !gpio_get_value(GPIO_SD1_CD);
+	else
+		ret = !gpio_get_value(GPIO_SD2_CD);
+
+	return ret;
+}
+
+int board_mmc_init(bd_t *bis)
+{
+	u32 index;
+	int ret;
+
+	esdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
+	esdhc_cfg[1].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
+
+	for (index = 0; index < CONFIG_SYS_FSL_ESDHC_NUM; index++) {
+		switch (index) {
+		case 0:
+			break;
+		case 1:
+			break;
+		default:
+			printf("Warning: you configured more ESDHC controller(%d) as supported by the board(2)\n",
+			       CONFIG_SYS_FSL_ESDHC_NUM);
+			return -EINVAL;
+		}
+		ret = fsl_esdhc_initialize(bis, &esdhc_cfg[index]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+#endif
+
+static int power_init(void)
+{
+	/* nothing to do on CX9020 */
+	return 0;
+}
+
+static void clock_1GHz(void)
+{
+	int ret;
+	u32 ref_clk = MXC_HCLK;
+	/*
+	 * After increasing voltage to 1.25V, we can switch
+	 * CPU clock to 1GHz and DDR to 400MHz safely
+	 */
+	ret = mxc_set_clock(ref_clk, 1000, MXC_ARM_CLK);
+	if (ret)
+		printf("CPU:   Switch CPU clock to 1GHZ failed\n");
+
+	ret = mxc_set_clock(ref_clk, 400, MXC_PERIPH_CLK);
+	ret |= mxc_set_clock(ref_clk, 400, MXC_DDR_CLK);
+	if (ret)
+		printf("CPU:   Switch DDR clock to 400MHz failed\n");
+}
+
+int board_early_init_f(void)
+{
+	setup_gpio_leds();
+	setup_gpio_sups();
+	setup_gpio_eim();
+	setup_iomux_lcd();
+
+	return 0;
+}
+
+/*
+ * Do not overwrite the console
+ * Use always serial for U-Boot console
+ */
+int overwrite_console(void)
+{
+	return 1;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
+
+	mxc_set_sata_internal_clock();
+
+	return 0;
+}
+
+int checkboard(void)
+{
+	puts("Board: Beckhoff CX9020\n");
+
+	return 0;
+}
+
+static int ccat_config_fn(int assert_config, int flush, int cookie)
+{
+	/* prepare FPGA for programming */
+	weim_cs0_settings(CCAT_MODE_CONFIG);
+	gpio_set_value(GPIO_C3_CONFIG, 0);
+	udelay(1);
+	gpio_set_value(GPIO_C3_CONFIG, 1);
+	udelay(230);
+
+	return FPGA_SUCCESS;
+}
+
+static int ccat_status_fn(int cookie)
+{
+	return FPGA_FAIL;
+}
+
+static int ccat_write_fn(const void *buf, size_t buf_len, int flush, int cookie)
+{
+	const uint8_t *const buffer = buf;
+
+	/* program CCAT */
+	int i;
+	for (i = 0; i < buf_len; ++i)
+		writeb(buffer[i], CCAT_BASE_ADDR);
+
+	writeb(0xff, CCAT_BASE_ADDR);
+	writeb(0xff, CCAT_BASE_ADDR);
+
+	return FPGA_SUCCESS;
+}
+
+static int ccat_done_fn(int cookie)
+{
+	/* programming complete? */
+	return gpio_get_value(GPIO_C3_DONE);
+}
+
+static int ccat_post_fn(int cookie)
+{
+	/* switch to FPGA run mode */
+	weim_cs0_settings(CCAT_MODE_RUN);
+	invalidate_dcache_range((ulong) CCAT_BASE_ADDR, (ulong) CCAT_END_ADDR);
+
+	if (memcmp(CCAT_SIGN_ADDR, CCAT_SIGNATURE, sizeof(CCAT_SIGNATURE))) {
+		printf("Verifing CCAT firmware failed, signature not found\n");
+		return FPGA_FAIL;
+	}
+
+	/* signal "CX booting OS" */
+	gpio_set_value(GPIO_LED_PWR_R, 1);
+	gpio_set_value(GPIO_LED_PWR_G, 1);
+	gpio_set_value(GPIO_LED_PWR_B, 0);
+	return FPGA_SUCCESS;
+}
+
+static Altera_CYC2_Passive_Serial_fns ccat_fns = {
+	.config = ccat_config_fn,
+	.status = ccat_status_fn,
+	.done = ccat_done_fn,
+	.write = ccat_write_fn,
+	.abort = ccat_post_fn,
+	.post = ccat_post_fn,
+};
+
+static Altera_desc ccat_fpga = {
+	.family = Altera_CYC2,
+	.iface = passive_serial,
+	.size = CCAT_SIZE,
+	.iface_fns = &ccat_fns,
+	.base = CCAT_BASE_ADDR,
+};
+
+int board_late_init(void)
+{
+	if (!power_init())
+		clock_1GHz();
+
+	fpga_init();
+	fpga_add(fpga_altera, &ccat_fpga);
+
+	return 0;
+}
diff --git a/board/beckhoff/mx53cx9020/mx53cx9020_video.c b/board/beckhoff/mx53cx9020/mx53cx9020_video.c
new file mode 100644
index 0000000..4da83da
--- /dev/null
+++ b/board/beckhoff/mx53cx9020/mx53cx9020_video.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015  Beckhoff Automation GmbH & Co. KG
+ * Patrick Bruenn <p.bruenn@beckhoff.com>
+ *
+ * Based on <u-boot>/board/freescale/mx53loco/mx53loco_video.c
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/list.h>
+#include <asm/gpio.h>
+#include <asm/arch/iomux-mx53.h>
+#include <linux/fb.h>
+#include <ipu_pixfmt.h>
+
+#define CX9020_DVI_PWD	IMX_GPIO_NR(6, 1)
+
+static struct fb_videomode const vga_640x480 = {
+	.name = "VESA_VGA_640x480",
+	.refresh = 60,
+	.xres = 640,
+	.yres = 480,
+	.pixclock = 39721,	/* picosecond (25.175 MHz) */
+	.left_margin = 40,
+	.right_margin = 60,
+	.upper_margin = 10,
+	.lower_margin = 10,
+	.hsync_len = 20,
+	.vsync_len = 10,
+	.sync = 0,
+	.vmode = FB_VMODE_NONINTERLACED
+};
+
+void setup_iomux_lcd(void)
+{
+	/* Turn on DVI_PWD */
+	imx_iomux_v3_setup_pad(MX53_PAD_CSI0_DAT15__GPIO6_1);
+	gpio_direction_output(CX9020_DVI_PWD, 1);
+}
+
+int board_video_skip(void)
+{
+	const int ret = ipuv3_fb_init(&vga_640x480, 0, IPU_PIX_FMT_RGB24);
+	if (ret)
+		printf("VESA VG 640x480 cannot be configured: %d\n", ret);
+	return ret;
+}