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/arch/arc/Kconfig b/arch/arc/Kconfig
index d59aa3a..b24593e 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -157,6 +157,10 @@
 config TARGET_HSDK
 	bool "Support Synpsys HS DevelopmentKit board"
 
+config TARGET_IOT_DEVKIT
+	bool "Synopsys Brite IoT Development kit"
+	select CPU_ARCEM6
+
 endchoice
 
 source "board/abilis/tb100/Kconfig"
@@ -164,5 +168,6 @@
 source "board/synopsys/axs10x/Kconfig"
 source "board/synopsys/emdk/Kconfig"
 source "board/synopsys/hsdk/Kconfig"
+source "board/synopsys/iot_devkit/Kconfig"
 
 endmenu
diff --git a/arch/arc/dts/Makefile b/arch/arc/dts/Makefile
index 491a4f4..17e1405 100644
--- a/arch/arc/dts/Makefile
+++ b/arch/arc/dts/Makefile
@@ -6,6 +6,7 @@
 dtb-$(CONFIG_TARGET_TB100) +=  abilis_tb100.dtb
 dtb-$(CONFIG_TARGET_EMDK) +=  emdk.dtb
 dtb-$(CONFIG_TARGET_HSDK) +=  hsdk.dtb
+dtb-$(CONFIG_TARGET_IOT_DEVKIT) +=  iot_devkit.dtb
 
 targets += $(dtb-y)
 
diff --git a/arch/arc/dts/iot_devkit.dts b/arch/arc/dts/iot_devkit.dts
new file mode 100644
index 0000000..ebf5a95
--- /dev/null
+++ b/arch/arc/dts/iot_devkit.dts
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
+ */
+/dts-v1/;
+
+#include "skeleton.dtsi"
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		console = &uart0;
+	};
+
+	cpu_card {
+		core_clk: core_clk {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <144000000>;
+			u-boot,dm-pre-reloc;
+		};
+	};
+
+	uart0: serial0@80014000 {
+		compatible = "snps,dw-apb-uart";
+		clock-frequency = <16000000>;
+		reg = <0x80014000 0x1000>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+	};
+
+	usb: usb@f0040000 {
+		compatible = "snps,dwc2";
+		reg = <0xf0040000 0x10000>;
+		phys = <&usbphy>;
+		phy-names = "usb2-phy";
+	};
+
+	usbphy: phy {
+		compatible = "nop-phy";
+		#phy-cells = <0>;
+	};
+};
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 = .;
+}
diff --git a/configs/iot_devkit_defconfig b/configs/iot_devkit_defconfig
new file mode 100644
index 0000000..1f0f9c3
--- /dev/null
+++ b/configs/iot_devkit_defconfig
@@ -0,0 +1,38 @@
+CONFIG_ARC=y
+CONFIG_ISA_ARCV2=y
+CONFIG_CPU_ARCEM6=y
+CONFIG_SYS_ICACHE_OFF=y
+CONFIG_SYS_DCACHE_OFF=y
+CONFIG_TARGET_IOT_DEVKIT=y
+CONFIG_SYS_TEXT_BASE=0x20000000
+CONFIG_SYS_CLK_FREQ=16000000
+# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
+CONFIG_SYS_PROMPT="IoTDK# "
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_BOOTM is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
+# CONFIG_CMD_NET is not set
+CONFIG_CMD_FAT=y
+CONFIG_OF_CONTROL=y
+CONFIG_OF_EMBED=y
+CONFIG_DEFAULT_DEVICE_TREE="iot_devkit"
+CONFIG_ENV_IS_IN_FAT=y
+CONFIG_ENV_FAT_INTERFACE="mmc"
+CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
+CONFIG_DM=y
+CONFIG_MMC=y
+CONFIG_MMC_DW=y
+CONFIG_DM_SERIAL=y
+CONFIG_SYS_NS16550=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_DWC2=y
+CONFIG_USB_DWC2_BUFFER_SIZE=16
+CONFIG_USB_STORAGE=y
+CONFIG_FS_FAT_MAX_CLUSTSIZE=4096
diff --git a/include/configs/iot_devkit.h b/include/configs/iot_devkit.h
new file mode 100644
index 0000000..4ffe114
--- /dev/null
+++ b/include/configs/iot_devkit.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
+ */
+
+#ifndef _CONFIG_IOT_DEVKIT_H_
+#define _CONFIG_IOT_DEVKIT_H_
+
+#include <linux/sizes.h>
+
+/*
+ *                         MEMORY MAP
+ *
+ * eFlash: 0x0000_0000 - 0x0008_0000 (512K)
+ *   ICCM: 0x2000_0000 - 0x2004_0000 (256K)
+ *   SRAM: 0x3000_0000 - 0x3002_0000 (128K)
+ *   DCCM: 0x8000_0000 - 0x8002_0000 (128K)
+ *     Note: only data goes here, as IFQ cannot fetch instructions from DCCM
+ *
+ *
+ *                         RAM PARTITIONING
+ *
+ *   +-----------+----------+---------------------+-------------+
+ *   | <-- Stack |  .data   | Malloc              | Environment |
+ *   +-----------+----------+---------------------+-------------+
+ *   :           :          :                     :\___________/
+ *   :           :          :                     :      |
+ *   :           :          :                     :     CONFIG_ENV_SIZE
+ *   :           :           \____________________/
+ *   :           :                     |
+ *   :           :                    CONFIG_SYS_MALLOC_LEN
+ *   :           :
+ *   :          Specified explicitly by CONFIG_SYS_INIT_SP_ADDR
+ *   :
+ *  Specified explicitly by CONFIG_SYS_SDRAM_BASE
+ *
+ *  NOTES:
+ *    - Stack starts from CONFIG_SYS_INIT_SP_ADDR and grows down,
+ *      i.e. towards CONFIG_SYS_SDRAM_BASE but nothing stops it from crossing
+ *      that CONFIG_SYS_SDRAM_BASE in which case data won't be really saved on
+ *      stack any longer and values popped from stack will contain garbage
+ *      leading to unexpected behavior, typically but not limited to:
+ *        - "Returning" back to bogus caller function
+ *        - Reading data from weird addresses
+ */
+
+#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
+
+#define SRAM_BASE			0x30000000
+#define SRAM_SIZE			SZ_128K
+
+#define DCCM_BASE			0x80000000
+#define DCCM_SIZE			SZ_128K
+
+#define CONFIG_SYS_SDRAM_BASE		DCCM_BASE
+#define CONFIG_SYS_SDRAM_SIZE		DCCM_SIZE
+
+#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_32K)
+
+#define CONFIG_SYS_MALLOC_LEN		SZ_64K
+#define CONFIG_SYS_BOOTM_LEN		SZ_128K
+#define CONFIG_SYS_LOAD_ADDR		SRAM_BASE
+
+#define ROM_BASE			CONFIG_SYS_MONITOR_BASE
+#define ROM_SIZE			SZ_256K
+
+#define RAM_DATA_BASE			CONFIG_SYS_INIT_SP_ADDR
+#define RAM_DATA_SIZE			CONFIG_SYS_SDRAM_SIZE - \
+					(CONFIG_SYS_INIT_SP_ADDR - \
+					CONFIG_SYS_SDRAM_BASE) - \
+					CONFIG_SYS_MALLOC_LEN - \
+					CONFIG_ENV_SIZE
+
+/* Required by DW MMC driver */
+#define CONFIG_BOUNCE_BUFFER
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_SIZE			SZ_4K
+#define CONFIG_BOOTFILE			"app.bin"
+#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
+
+#endif /* _CONFIG_IOT_DEVKIT_H_ */