diff --git a/MAINTAINERS b/MAINTAINERS
index db8cecd5e0..e689d1ebeb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -216,6 +216,13 @@ F:	arch/arm/cpu/armv8/hisilicon
 F:	arch/arm/include/asm/arch-hi6220/
 F:	arch/arm/include/asm/arch-hi3660/
 
+ARM IPQ40XX
+M:	Robert Marko <robert.marko at sartura.hr>
+M:	Luka Kovacic <luka.kovacic at sartura.hr>
+M:	Luka Perkov <luka.perkov at sartura.hr>
+S:	Maintained
+F:	arch/arm/mach-ipq40xx/
+
 ARM MARVELL KIRKWOOD ARMADA-XP ARMADA-38X ARMADA-37XX ARMADA-7K/8K
 M:	Stefan Roese <sr at denx.de>
 S:	Maintained
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 54d65f8488..3868c5c674 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -763,6 +763,17 @@ config ARCH_INTEGRATOR
 	select PL01X_SERIAL
 	imply CMD_DM
 
+config ARCH_IPQ40XX
+	bool "Qualcomm IPQ40xx SoCs"
+	select CPU_V7A
+	select DM
+	select DM_GPIO
+	select DM_SERIAL
+	select PINCTRL
+	select CLK
+	select OF_CONTROL
+	imply CMD_DM
+
 config ARCH_KEYSTONE
 	bool "TI Keystone"
 	select CMD_POWEROFF
@@ -1772,6 +1783,8 @@ source "arch/arm/mach-highbank/Kconfig"
 
 source "arch/arm/mach-integrator/Kconfig"
 
+source "arch/arm/mach-ipq40xx/Kconfig"
+
 source "arch/arm/mach-k3/Kconfig"
 
 source "arch/arm/mach-keystone/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 94eb50bf72..a20b82bc8d 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -58,6 +58,7 @@ machine-$(CONFIG_ARCH_BCMSTB)		+= bcmstb
 machine-$(CONFIG_ARCH_DAVINCI)		+= davinci
 machine-$(CONFIG_ARCH_EXYNOS)		+= exynos
 machine-$(CONFIG_ARCH_HIGHBANK)		+= highbank
+machine-$(CONFIG_ARCH_IPQ40XX)		+= ipq40xx
 machine-$(CONFIG_ARCH_K3)		+= k3
 machine-$(CONFIG_ARCH_KEYSTONE)		+= keystone
 machine-$(CONFIG_ARCH_KIRKWOOD)		+= kirkwood
diff --git a/arch/arm/dts/qcom-ipq4019.dtsi b/arch/arm/dts/qcom-ipq4019.dtsi
new file mode 100644
index 0000000000..5f78bc5ab9
--- /dev/null
+++ b/arch/arm/dts/qcom-ipq4019.dtsi
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko at sartura.hr>
+ */
+
+ /dts-v1/;
+
+#include "skeleton.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/pinctrl-snapdragon.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	model = "Qualcomm Technologies, Inc. IPQ4019";
+	compatible = "qcom,ipq4019";
+
+	aliases {
+		serial0 = &blsp1_uart1;
+	};
+
+	reserved-memory {
+		#address-cells = <0x1>;
+		#size-cells = <0x1>;
+		ranges;
+
+		smem_mem: smem_region: smem at 87e00000 {
+			reg = <0x87e00000 0x080000>;
+			no-map;
+		};
+
+		tz at 87e80000 {
+			reg = <0x87e80000 0x180000>;
+			no-map;
+		};
+	};
+
+	soc: soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "simple-bus";
+
+		gcc: clock-controller at 1800000 {
+			compatible = "qcom,gcc-ipq4019";
+			reg = <0x1800000 0x60000>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			u-boot,dm-pre-reloc;
+		};
+
+		pinctrl: qcom,tlmm at 1000000 {
+			compatible = "qcom,tlmm-ipq4019";
+			reg = <0x1000000 0x300000>;
+			u-boot,dm-pre-reloc;
+		};
+
+		blsp1_uart1: serial at 78af000 {
+			compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+			reg = <0x78af000 0x200>;
+			clock = <&gcc 26>;
+			bit-rate = <0xFF>;
+			status = "disabled";
+			u-boot,dm-pre-reloc;
+		};
+
+		soc_gpios: pinctrl at 1000000 {
+			compatible = "qcom,ipq4019-pinctrl";
+			reg = <0x1000000 0x300000>;
+			gpio-controller;
+			gpio-count = <100>;
+			gpio-bank-name="soc";
+			#gpio-cells = <2>;
+		};
+	};
+};
diff --git a/arch/arm/mach-ipq40xx/Kconfig b/arch/arm/mach-ipq40xx/Kconfig
new file mode 100644
index 0000000000..4eef80e935
--- /dev/null
+++ b/arch/arm/mach-ipq40xx/Kconfig
@@ -0,0 +1,15 @@
+if ARCH_IPQ40XX
+
+config SYS_SOC
+	default "ipq40xx"
+
+config SYS_MALLOC_F_LEN
+	default 0x2000
+
+config SYS_TEXT_BASE
+	default 0x87300000
+
+config NR_DRAM_BANKS
+	default 1
+
+endif
diff --git a/arch/arm/mach-ipq40xx/Makefile b/arch/arm/mach-ipq40xx/Makefile
new file mode 100644
index 0000000000..08a65b8854
--- /dev/null
+++ b/arch/arm/mach-ipq40xx/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2019 Sartura Ltd.
+#
+# Author: Robert Marko <robert.marko at sartura.hr>
+
+obj-y += clock-ipq4019.o
+obj-y += pinctrl-snapdragon.o
+obj-y += pinctrl-ipq4019.o
diff --git a/arch/arm/mach-ipq40xx/clock-ipq4019.c b/arch/arm/mach-ipq40xx/clock-ipq4019.c
new file mode 100644
index 0000000000..7cf98a203c
--- /dev/null
+++ b/arch/arm/mach-ipq40xx/clock-ipq4019.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Clock drivers for Qualcomm IPQ40xx
+ *
+ * Copyright (c) 2019 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko at sartura.hr>
+ *
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+
+struct msm_clk_priv {
+	phys_addr_t base;
+};
+
+ulong msm_set_rate(struct clk *clk, ulong rate)
+{
+	switch (clk->id) {
+	case 26: /*UART1*/
+		/* This clock is already initialized by SBL1 */
+		return 0; 
+		break;
+	default:
+		return 0;
+	}
+}
+
+static int msm_clk_probe(struct udevice *dev)
+{
+	struct msm_clk_priv *priv = dev_get_priv(dev);
+
+	priv->base = devfdt_get_addr(dev);
+	if (priv->base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	return 0;
+}
+
+static ulong msm_clk_set_rate(struct clk *clk, ulong rate)
+{
+	return msm_set_rate(clk, rate);
+}
+
+static struct clk_ops msm_clk_ops = {
+	.set_rate = msm_clk_set_rate,
+};
+
+static const struct udevice_id msm_clk_ids[] = {
+	{ .compatible = "qcom,gcc-ipq4019" },
+	{ }
+};
+
+U_BOOT_DRIVER(clk_msm) = {
+	.name		= "clk_msm",
+	.id		= UCLASS_CLK,
+	.of_match	= msm_clk_ids,
+	.ops		= &msm_clk_ops,
+	.priv_auto_alloc_size = sizeof(struct msm_clk_priv),
+	.probe		= msm_clk_probe,
+};
diff --git a/arch/arm/mach-ipq40xx/include/mach/gpio.h b/arch/arm/mach-ipq40xx/include/mach/gpio.h
new file mode 100644
index 0000000000..a45747c0fe
--- /dev/null
+++ b/arch/arm/mach-ipq40xx/include/mach/gpio.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Empty gpio.h
+ *
+ * This file must stay as arch/arm/include/asm/gpio.h requires it.
+ *
+ * Copyright (c) 2019 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko at sartura.hr>
+ */
diff --git a/arch/arm/mach-ipq40xx/pinctrl-ipq4019.c b/arch/arm/mach-ipq40xx/pinctrl-ipq4019.c
new file mode 100644
index 0000000000..06a57f2e5e
--- /dev/null
+++ b/arch/arm/mach-ipq40xx/pinctrl-ipq4019.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm IPQ40xx pinctrl
+ *
+ * Copyright (c) 2019 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko at sartura.hr>
+ */
+
+#include "pinctrl-snapdragon.h"
+#include <common.h>
+
+#define MAX_PIN_NAME_LEN 32
+static char pin_name[MAX_PIN_NAME_LEN];
+
+static const struct pinctrl_function msm_pinctrl_functions[] = {
+	{"gpio", 0},
+	{"blsp_uart0_0", 1}, /* Only for GPIO:16,17 */
+	{"blsp_uart0_1", 2}, /* Only for GPIO:60,61 */
+	{"blsp_uart1", 1},
+};
+
+static const char *ipq4019_get_function_name(struct udevice *dev,
+					     unsigned int selector)
+{
+	return msm_pinctrl_functions[selector].name;
+}
+
+static const char *ipq4019_get_pin_name(struct udevice *dev,
+					unsigned int selector)
+{
+	snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+	return pin_name;
+}
+
+static unsigned int ipq4019_get_function_mux(unsigned int selector)
+{
+	return msm_pinctrl_functions[selector].val;
+}
+
+struct msm_pinctrl_data ipq4019_data = {
+	.pin_count = 100,
+	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
+	.get_function_name = ipq4019_get_function_name,
+	.get_function_mux = ipq4019_get_function_mux,
+	.get_pin_name = ipq4019_get_pin_name,
+};
diff --git a/arch/arm/mach-ipq40xx/pinctrl-snapdragon.c b/arch/arm/mach-ipq40xx/pinctrl-snapdragon.c
new file mode 100644
index 0000000000..64b8b049fa
--- /dev/null
+++ b/arch/arm/mach-ipq40xx/pinctrl-snapdragon.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TLMM driver for Qualcomm IPQ40xx
+ *
+ * (C) Copyright 2018 Ramon Fried <ramon.fried at gmail.com>
+ *
+ * Copyright (c) 2020 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko at sartura.hr>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include "pinctrl-snapdragon.h"
+
+struct msm_pinctrl_priv {
+	phys_addr_t base;
+	struct msm_pinctrl_data *data;
+};
+
+#define GPIO_CONFIG_OFFSET(x)         ((x) * 0x1000)
+#define TLMM_GPIO_PULL_MASK GENMASK(1, 0)
+#define TLMM_FUNC_SEL_MASK GENMASK(5, 2)
+#define TLMM_DRV_STRENGTH_MASK GENMASK(8, 6)
+#define TLMM_GPIO_DISABLE BIT(9)
+
+static const struct pinconf_param msm_conf_params[] = {
+	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 2 },
+	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+	{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 2 },
+};
+
+static int msm_get_functions_count(struct udevice *dev)
+{
+	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return priv->data->functions_count;
+}
+
+static int msm_get_pins_count(struct udevice *dev)
+{
+	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return priv->data->pin_count;
+}
+
+static const char *msm_get_function_name(struct udevice *dev,
+					 unsigned int selector)
+{
+	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return priv->data->get_function_name(dev, selector);
+}
+
+static int msm_pinctrl_probe(struct udevice *dev)
+{
+	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+	priv->base = devfdt_get_addr(dev);
+	priv->data = (struct msm_pinctrl_data *)dev->driver_data;
+
+	return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
+}
+
+static const char *msm_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return priv->data->get_pin_name(dev, selector);
+}
+
+static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
+			  unsigned int func_selector)
+{
+	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+	clrsetbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector),
+			TLMM_FUNC_SEL_MASK | TLMM_GPIO_DISABLE,
+			priv->data->get_function_mux(func_selector) << 2);
+	return 0;
+}
+
+static int msm_pinconf_set(struct udevice *dev, unsigned int pin_selector,
+			   unsigned int param, unsigned int argument)
+{
+	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+
+	switch (param) {
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		clrsetbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector),
+				TLMM_DRV_STRENGTH_MASK, argument << 6);
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		clrbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector),
+			     TLMM_GPIO_PULL_MASK);
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		clrsetbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector),
+			     TLMM_GPIO_PULL_MASK, argument);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static struct pinctrl_ops msm_pinctrl_ops = {
+	.get_pins_count = msm_get_pins_count,
+	.get_pin_name = msm_get_pin_name,
+	.set_state = pinctrl_generic_set_state,
+	.pinmux_set = msm_pinmux_set,
+	.pinconf_num_params = ARRAY_SIZE(msm_conf_params),
+	.pinconf_params = msm_conf_params,
+	.pinconf_set = msm_pinconf_set,
+	.get_functions_count = msm_get_functions_count,
+	.get_function_name = msm_get_function_name,
+};
+
+static const struct udevice_id msm_pinctrl_ids[] = {
+	{ .compatible = "qcom,tlmm-ipq4019", .data = (ulong)&ipq4019_data },
+	{ }
+};
+
+U_BOOT_DRIVER(pinctrl_snapdraon) = {
+	.name		= "pinctrl_msm",
+	.id		= UCLASS_PINCTRL,
+	.of_match	= msm_pinctrl_ids,
+	.priv_auto_alloc_size = sizeof(struct msm_pinctrl_priv),
+	.ops		= &msm_pinctrl_ops,
+	.probe		= msm_pinctrl_probe,
+};
diff --git a/arch/arm/mach-ipq40xx/pinctrl-snapdragon.h b/arch/arm/mach-ipq40xx/pinctrl-snapdragon.h
new file mode 100644
index 0000000000..2341a71349
--- /dev/null
+++ b/arch/arm/mach-ipq40xx/pinctrl-snapdragon.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Qualcomm Pin control
+ *
+ * (C) Copyright 2018 Ramon Fried <ramon.fried at gmail.com>
+ *
+ */
+#ifndef _PINCTRL_SNAPDRAGON_H
+#define _PINCTRL_SNAPDRAGON_H
+
+#include <common.h>
+
+struct msm_pinctrl_data {
+	int pin_count;
+	int functions_count;
+	const char *(*get_function_name)(struct udevice *dev,
+					 unsigned int selector);
+	unsigned int (*get_function_mux)(unsigned int selector);
+	const char *(*get_pin_name)(struct udevice *dev,
+				    unsigned int selector);
+};
+
+struct pinctrl_function {
+	const char *name;
+	int val;
+};
+
+extern struct msm_pinctrl_data ipq4019_data;
+
+#endif
