arc: Add support for IoT development kit

The DesignWare ARC IoT Development Kit is a versatile platform
that includes the necessary hardware and software to accelerate
software development and debugging of sensor fusion,
voice recognition and face detection designs.

More information is avaialble here [1] and here [2].

The board is based on real silicon with
ARC EM9D-based Data Fusion IP Subsystem.

It sports a rich set of I/O including
 * DW USB OTG
 * DW MobileStorage (used for micro SD-card)
 * GPIO
 * multiple serial interface including DW APB UART
 * ADC, PWM and eFlash, SRAM and SPI Flash memory
 * Real-Time Clock (RTC)
 * Bluetooth module with worldwide regulatory compliance
   (FCC, IC, CE, ETSI, TELEC)
 * On-board 9-axis sensor (gyro, accelerometer and compass)

Extensible with Arduino, Pmod, mikroBUS connectors and a 2x18
extension header.

One of the most interesting features for developers is built-in
Digilent USB JTAG probe so only micro-USB cable is needed!

[1] https://www.synopsys.com/dw/ipdir.php?ds=arc_iot_development_kit
[2] https://www.synopsys.com/dw/doc.php/ds/cc/iot_dev_kit.pdf

Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
diff --git a/board/synopsys/iot_devkit/Kconfig b/board/synopsys/iot_devkit/Kconfig
new file mode 100644
index 0000000..ad956b2
--- /dev/null
+++ b/board/synopsys/iot_devkit/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_IOT_DEVKIT
+
+config SYS_BOARD
+	default "iot_devkit"
+
+config SYS_VENDOR
+	default "synopsys"
+
+config SYS_CONFIG_NAME
+	default "iot_devkit"
+
+endif
diff --git a/board/synopsys/iot_devkit/MAINTAINERS b/board/synopsys/iot_devkit/MAINTAINERS
new file mode 100644
index 0000000..06457cf
--- /dev/null
+++ b/board/synopsys/iot_devkit/MAINTAINERS
@@ -0,0 +1,5 @@
+IOT DEVKIT BOARD
+M:	Alexey Brodkin <abrodkin@synopsys.com>
+S:	Maintained
+F:	board/synopsys/iot_devkit/
+F:	configs/iot_devkit_defconfig
diff --git a/board/synopsys/iot_devkit/Makefile b/board/synopsys/iot_devkit/Makefile
new file mode 100644
index 0000000..1616024
--- /dev/null
+++ b/board/synopsys/iot_devkit/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (C) 2018 Synopsys, Inc. All rights reserved.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	+= iot_devkit.o
diff --git a/board/synopsys/iot_devkit/config.mk b/board/synopsys/iot_devkit/config.mk
new file mode 100644
index 0000000..1207335
--- /dev/null
+++ b/board/synopsys/iot_devkit/config.mk
@@ -0,0 +1,2 @@
+PLATFORM_CPPFLAGS += -mlittle-endian -mcode-density -mdiv-rem -mswap -mnorm -mmpy-option=6 -mbarrel-shifter
+LDSCRIPT = $(srctree)/board/synopsys/iot_devkit/u-boot.lds
diff --git a/board/synopsys/iot_devkit/iot_devkit.c b/board/synopsys/iot_devkit/iot_devkit.c
new file mode 100644
index 0000000..c185d5c
--- /dev/null
+++ b/board/synopsys/iot_devkit/iot_devkit.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <dwmmc.h>
+#include <linux/libfdt.h>
+#include <fdtdec.h>
+
+#include <asm/arcregs.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define SYSCON_BASE	0xf000a000
+#define AHBCKDIV	(void *)(SYSCON_BASE + 0x04)
+#define APBCKDIV	(void *)(SYSCON_BASE + 0x08)
+#define APBCKEN		(void *)(SYSCON_BASE + 0x0C)
+#define CLKSEL		(void *)(SYSCON_BASE + 0x24)
+#define CLKSTAT		(void *)(SYSCON_BASE + 0x28)
+#define PLLCON		(void *)(SYSCON_BASE + 0x2C)
+#define APBCKSEL	(void *)(SYSCON_BASE + 0x30)
+#define AHBCKEN		(void *)(SYSCON_BASE + 0x34)
+#define USBPHY_PLL	(void *)(SYSCON_BASE + 0x78)
+#define USBCFG		(void *)(SYSCON_BASE + 0x7c)
+
+#define PLL_MASK_0	0xffcfffff
+#define PLL_MASK_1	0xffcfff00
+#define PLL_MASK_2	0xfbcfff00
+
+#define CLKSEL_DEFAULT	0x5a690000
+
+static int set_cpu_freq(unsigned int clk)
+{
+	clk /= 1000000;
+
+	/* Set clk to ext Xtal (LSN value 0) */
+	writel(CLKSEL_DEFAULT, CLKSEL);
+
+	switch (clk) {
+	case 16:
+		/* Bypass mode */
+		return 0;
+
+	case 50:
+		writel(readl(PLLCON) & PLL_MASK_0, PLLCON);
+		/* pll_off=1, M=25, N=1, OD=3, PLL_OUT_CLK=50M */
+		writel((readl(PLLCON) & PLL_MASK_1) | 0x300191, PLLCON);
+		/* pll_off=0, M=25, N=1, OD=3, PLL_OUT_CLK=50M */
+		writel((readl(PLLCON) & PLL_MASK_2) | 0x300191, PLLCON);
+		break;
+
+	case 72:
+		writel(readl(PLLCON) & PLL_MASK_0, PLLCON);
+		/* pll_off=1, M=18, N=1, OD=2, PLL_OUT_CLK=72M */
+		writel((readl(PLLCON) & PLL_MASK_1) | 0x200121, PLLCON);
+		/* pll_off=0, M=18, N=1, OD=2, PLL_OUT_CLK=72M */
+		writel((readl(PLLCON) & PLL_MASK_2) | 0x200121, PLLCON);
+		break;
+
+	case 100:
+		writel(readl(PLLCON) & PLL_MASK_0, PLLCON);
+		/* pll_off=1,M=25, N=1, OD=2, PLL_OUT_CLK=100M */
+		writel((readl(PLLCON) & PLL_MASK_1) | 0x200191, PLLCON);
+		/* pll_off=0,M=25, N=1, OD=2, PLL_OUT_CLK=100M */
+		writel((readl(PLLCON) & PLL_MASK_2) | 0x200191, PLLCON);
+		break;
+
+	case 144:
+		writel(readl(PLLCON) & PLL_MASK_0, PLLCON);
+		/* pll_off=1, M=18, N=1, OD=1, PLL_OUT_CLK=144M */
+		writel((readl(PLLCON) & PLL_MASK_1) | 0x100121, PLLCON);
+		/* pll_off=0, M=18, N=1, OD=1, PLL_OUT_CLK=144M */
+		writel((readl(PLLCON) & PLL_MASK_2) | 0x100121, PLLCON);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	while (!(readl(CLKSTAT) & 0x4))
+		;
+
+	/* Set clk from PLL on bus (LSN = 1) */
+	writel(CLKSEL_DEFAULT | BIT(0), CLKSEL);
+
+	return 0;
+}
+
+extern u8 __rom_end[];
+extern u8 __ram_start[];
+extern u8 __ram_end[];
+
+/*
+ * Use mach_cpu_init() for .data section copy as board_early_init_f() will be
+ * too late: initf_dm() will use a value of "av_" variable from not yet
+ * initialized (by copy) area.
+ */
+int mach_cpu_init(void)
+{
+	int offset, freq;
+
+	/* Don't relocate U-Boot */
+	gd->flags |= GD_FLG_SKIP_RELOC;
+
+	/* Copy data from ROM to RAM */
+	u8 *src = __rom_end;
+	u8 *dst = __ram_start;
+
+	while (dst < __ram_end)
+		*dst++ = *src++;
+
+	/* Enable debug uart */
+#define DEBUG_UART_BASE		0x80014000
+#define DEBUG_UART_DLF_OFFSET	0xc0
+	write_aux_reg(DEBUG_UART_BASE + DEBUG_UART_DLF_OFFSET, 1);
+
+	offset = fdt_path_offset(gd->fdt_blob, "/cpu_card/core_clk");
+	if (offset < 0)
+		return offset;
+
+	freq = fdtdec_get_int(gd->fdt_blob, offset, "clock-frequency", 0);
+	if (!freq)
+		return -EINVAL;
+
+	/* If CPU freq > 100 MHz, divide eFLASH clock by 2 */
+	if (freq > 100000000) {
+		u32 reg = readl(AHBCKDIV);
+
+		reg &= ~(0xF << 8);
+		reg |= 2 << 8;
+		writel(reg, AHBCKDIV);
+	}
+
+	return set_cpu_freq(freq);
+}
+
+#define ARC_PERIPHERAL_BASE	0xF0000000
+#define SDIO_BASE		(ARC_PERIPHERAL_BASE + 0xB000)
+
+int board_mmc_init(bd_t *bis)
+{
+	struct dwmci_host *host = NULL;
+
+	host = malloc(sizeof(struct dwmci_host));
+	if (!host) {
+		printf("dwmci_host malloc fail!\n");
+		return -ENOMEM;
+	}
+
+	memset(host, 0, sizeof(struct dwmci_host));
+	host->name = "Synopsys Mobile storage";
+	host->ioaddr = (void *)SDIO_BASE;
+	host->buswidth = 4;
+	host->dev_index = 0;
+	host->bus_hz = 50000000;
+
+	add_dwmci(host, host->bus_hz / 2, 400000);
+
+	return 0;
+}
+
+int checkboard(void)
+{
+	puts("Board: Synopsys IoT Development Kit\n");
+	return 0;
+};
diff --git a/board/synopsys/iot_devkit/u-boot.lds b/board/synopsys/iot_devkit/u-boot.lds
new file mode 100644
index 0000000..d083168
--- /dev/null
+++ b/board/synopsys/iot_devkit/u-boot.lds
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+
+MEMORY {
+	ROM : ORIGIN = ROM_BASE, LENGTH = ROM_SIZE
+	RAM : ORIGIN = RAM_DATA_BASE, LENGTH = RAM_DATA_SIZE
+}
+
+OUTPUT_FORMAT("elf32-littlearc", "elf32-littlearc", "elf32-littlearc")
+OUTPUT_ARCH(arc)
+ENTRY(_start)
+SECTIONS
+{
+	. = CONFIG_SYS_MONITOR_BASE;
+	__image_copy_start = .;
+	.ivt :
+	{
+		__ivt_start = .;
+		KEEP(*(.ivt));
+		__ivt_end = .;
+	} > ROM
+
+	. = ALIGN(1024);
+	.text :	{
+		__text_start = .;
+		arch/arc/lib/start.o (.text*)
+		*(.text*)
+		__text_end = .;
+	} > ROM
+
+	. = ALIGN(4);
+	.rodata : {
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+	} > ROM
+
+	. = ALIGN(4);
+	.u_boot_list : {
+		KEEP(*(SORT(.u_boot_list*)));
+
+		/* Mark RAM's LMA */
+		. = ALIGN(4);
+		__rom_end = .;
+	} > ROM
+
+	.data : {
+		/* Mark RAM's VMA */
+		. = ALIGN(4);
+
+		/*
+		 * Everything between __ram_start and __ram_start will be
+		 * copied from ROM to RAM in board_early_init_f().
+		 */
+		__ram_start = .;
+
+		*(.data*)
+
+		__ram_end = .;
+	} > RAM AT > ROM
+
+	.bss : {
+		. = ALIGN(1024);
+		__bss_start = .;
+		*(.bss*)
+		__bss_end = .;
+	} > RAM
+
+	/* Keep relocation-related symbols to make linker happy */
+	__rel_dyn_start = .;
+	__rel_dyn_end = .;
+	__image_copy_end = .;
+	__init_end = .;
+}