Merge tag 'u-boot-amlogic-20191018' of https://gitlab.denx.de/u-boot/custodians/u-boot-amlogic

- document alternative libretech-cc installation methods, including upstream TF-A and opensource tools
- add HDMI/CVBS display support for Amlogic G12A SoCs and SEI510 board
- add support for Amlogic A311D based Khadas VIM3
- add support for Amlogic S905X3 based SEI610 board, targeting Android support like SEI510
diff --git a/arch/riscv/include/asm/arch-generic/gpio.h b/arch/riscv/include/asm/arch-generic/gpio.h
new file mode 100644
index 0000000..dfcb753
--- /dev/null
+++ b/arch/riscv/include/asm/arch-generic/gpio.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019 SiFive, Inc.
+ */
+
+#ifndef _GPIO_SIFIVE_H
+#define _GPIO_SIFIVE_H
+
+#define GPIO_INPUT_VAL	0x00
+#define GPIO_INPUT_EN	0x04
+#define GPIO_OUTPUT_EN	0x08
+#define GPIO_OUTPUT_VAL	0x0C
+#define GPIO_RISE_IE	0x18
+#define GPIO_RISE_IP	0x1C
+#define GPIO_FALL_IE	0x20
+#define GPIO_FALL_IP	0x24
+#define GPIO_HIGH_IE	0x28
+#define GPIO_HIGH_IP	0x2C
+#define GPIO_LOW_IE	0x30
+#define GPIO_LOW_IP	0x34
+#define GPIO_OUTPUT_XOR	0x40
+
+#define NR_GPIOS	16
+
+enum gpio_state {
+	LOW,
+	HIGH
+};
+
+/* Details about a GPIO bank */
+struct sifive_gpio_platdata {
+	void *base;     /* address of registers in physical memory */
+};
+
+#endif /* _GPIO_SIFIVE_H */
diff --git a/arch/riscv/include/asm/gpio.h b/arch/riscv/include/asm/gpio.h
new file mode 100644
index 0000000..008d756
--- /dev/null
+++ b/arch/riscv/include/asm/gpio.h
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 SiFive, Inc.
+ */
+
+#include <asm-generic/gpio.h>
diff --git a/arch/riscv/lib/image.c b/arch/riscv/lib/image.c
index d063beb..7357d3b 100644
--- a/arch/riscv/lib/image.c
+++ b/arch/riscv/lib/image.c
@@ -14,20 +14,21 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* ASCII version of "RISCV" defined in Linux kernel */
-#define LINUX_RISCV_IMAGE_MAGIC 0x5643534952
+/* ASCII version of "RSC\0x5" defined in Linux kernel */
+#define LINUX_RISCV_IMAGE_MAGIC 0x05435352
 
 struct linux_image_h {
 	uint32_t	code0;		/* Executable code */
 	uint32_t	code1;		/* Executable code */
 	uint64_t	text_offset;	/* Image load offset */
 	uint64_t	image_size;	/* Effective Image size */
-	uint64_t	res1;		/* reserved */
+	uint64_t	flags;		/* kernel flags (little endian) */
+	uint32_t	version;	/* version of the header */
+	uint32_t	res1;		/* reserved */
 	uint64_t	res2;		/* reserved */
 	uint64_t	res3;		/* reserved */
-	uint64_t	magic;		/* Magic number */
+	uint32_t	magic;		/* Magic number */
 	uint32_t	res4;		/* reserved */
-	uint32_t	res5;		/* reserved */
 };
 
 int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
diff --git a/board/sifive/fu540/Kconfig b/board/sifive/fu540/Kconfig
index 5d65080..5ca2147 100644
--- a/board/sifive/fu540/Kconfig
+++ b/board/sifive/fu540/Kconfig
@@ -44,6 +44,9 @@
 	imply MMC_SPI
 	imply MMC_BROKEN_CD
 	imply CMD_MMC
+	imply DM_GPIO
+	imply SIFIVE_GPIO
+	imply CMD_GPIO
 	imply SMP
 
 endif
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f2dabb5..39f2c7e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -285,6 +285,13 @@
 	  usable on many stm32 families like stm32f4/f7/h7 and stm32mp1.
 	  Tested on STM32F7.
 
+config SIFIVE_GPIO
+	bool "SiFive GPIO driver"
+	depends on DM_GPIO
+	help
+	  Device model driver for GPIO controller present in SiFive FU540 SoC. This
+	  driver enables GPIO interface on HiFive Unleashed A00 board.
+
 config MVEBU_GPIO
 	bool "Marvell MVEBU GPIO driver"
 	depends on DM_GPIO && ARCH_MVEBU
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4a8aa0f..ccc49e2 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -61,3 +61,4 @@
 obj-$(CONFIG_PM8916_GPIO)	+= pm8916_gpio.o
 obj-$(CONFIG_MT7621_GPIO)	+= mt7621_gpio.o
 obj-$(CONFIG_MSCC_SGPIO)	+= mscc_sgpio.o
+obj-$(CONFIG_SIFIVE_GPIO)	+= sifive-gpio.o
diff --git a/drivers/gpio/sifive-gpio.c b/drivers/gpio/sifive-gpio.c
new file mode 100644
index 0000000..76d5a1d3
--- /dev/null
+++ b/drivers/gpio/sifive-gpio.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SiFive GPIO driver
+ *
+ * Copyright (C) 2019 SiFive, Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/arch/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <asm/gpio.h>
+
+static int sifive_gpio_probe(struct udevice *dev)
+{
+	struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	char name[18], *str;
+
+	sprintf(name, "gpio@%4lx_", (uintptr_t)plat->base);
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	uc_priv->bank_name = str;
+
+	/*
+	 * Use the gpio count mentioned in device tree,
+	 * if not specified in dt, set NR_GPIOS as default
+	 */
+	uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", NR_GPIOS);
+
+	return 0;
+}
+
+static void sifive_update_gpio_reg(void *bptr, u32 offset, bool value)
+{
+	void __iomem *ptr = (void __iomem *)bptr;
+
+	u32 bit = BIT(offset);
+	u32 old = readl(ptr);
+
+	if (value)
+		writel(old | bit, ptr);
+	else
+		writel(old & ~bit, ptr);
+}
+
+static int sifive_gpio_direction_input(struct udevice *dev, u32 offset)
+{
+	struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	if (offset > uc_priv->gpio_count)
+		return -EINVAL;
+
+	/* Configure gpio direction as input */
+	sifive_update_gpio_reg(plat->base + GPIO_INPUT_EN,  offset, true);
+	sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, false);
+
+	return 0;
+}
+
+static int sifive_gpio_direction_output(struct udevice *dev, u32 offset,
+					int value)
+{
+	struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	if (offset > uc_priv->gpio_count)
+		return -EINVAL;
+
+	/* Configure gpio direction as output */
+	sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, true);
+	sifive_update_gpio_reg(plat->base + GPIO_INPUT_EN,  offset, false);
+
+	/* Set the output state of the pin */
+	sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value);
+
+	return 0;
+}
+
+static int sifive_gpio_get_value(struct udevice *dev, u32 offset)
+{
+	struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	int val;
+	int dir;
+
+	if (offset > uc_priv->gpio_count)
+		return -EINVAL;
+
+	/* Get direction of the pin */
+	dir = !(readl(plat->base + GPIO_OUTPUT_EN) & BIT(offset));
+
+	if (dir)
+		val = readl(plat->base + GPIO_INPUT_VAL) & BIT(offset);
+	else
+		val = readl(plat->base + GPIO_OUTPUT_VAL) & BIT(offset);
+
+	return val ? HIGH : LOW;
+}
+
+static int sifive_gpio_set_value(struct udevice *dev, u32 offset, int value)
+{
+	struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	if (offset > uc_priv->gpio_count)
+		return -EINVAL;
+
+	sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value);
+
+	return 0;
+}
+
+static int sifive_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+	struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
+	u32	outdir, indir, val;
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	if (offset > uc_priv->gpio_count)
+		return -1;
+
+	/* Get direction of the pin */
+	outdir = readl(plat->base + GPIO_OUTPUT_EN) & BIT(offset);
+	indir  = readl(plat->base + GPIO_INPUT_EN) & BIT(offset);
+
+	if (outdir)
+		/* Pin at specified offset is configured as output */
+		val = GPIOF_OUTPUT;
+	else if (indir)
+		/* Pin at specified offset is configured as input */
+		val = GPIOF_INPUT;
+	else
+		/*The requested GPIO is not set as input or output */
+		val = GPIOF_UNUSED;
+
+	return val;
+}
+
+static const struct udevice_id sifive_gpio_match[] = {
+	{ .compatible = "sifive,gpio0" },
+	{ }
+};
+
+static const struct dm_gpio_ops sifive_gpio_ops = {
+	.direction_input        = sifive_gpio_direction_input,
+	.direction_output       = sifive_gpio_direction_output,
+	.get_value              = sifive_gpio_get_value,
+	.set_value              = sifive_gpio_set_value,
+	.get_function		= sifive_gpio_get_function,
+};
+
+static int sifive_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+	struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
+	fdt_addr_t addr;
+
+	addr = devfdt_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	plat->base = (void *)addr;
+	return 0;
+}
+
+U_BOOT_DRIVER(gpio_sifive) = {
+	.name	= "gpio_sifive",
+	.id	= UCLASS_GPIO,
+	.of_match = sifive_gpio_match,
+	.ofdata_to_platdata = of_match_ptr(sifive_gpio_ofdata_to_platdata),
+	.platdata_auto_alloc_size = sizeof(struct sifive_gpio_platdata),
+	.ops	= &sifive_gpio_ops,
+	.probe	= sifive_gpio_probe,
+};