diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c04adfbe5034fdbd5793dca9a136f0b1a5fa16dc..b0b6f7885488f64b9f617a5c1a9e5ac8d6660c2b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1007,8 +1007,15 @@ config TARGET_THUNDERX_88XX
 	select OF_CONTROL
 	select SYS_CACHE_SHIFT_7
 
+config ARCH_ASPEED
+	bool "Support Aspeed SoCs"
+	select OF_CONTROL
+	select DM
+
 endchoice
 
+source "arch/arm/mach-aspeed/Kconfig"
+
 source "arch/arm/mach-at91/Kconfig"
 
 source "arch/arm/mach-bcm283x/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 4b8bf80c40394ed61e48d564943fba286f33474b..6fa950668c32d85fc8312da53f365b4cf6040696 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -50,6 +50,7 @@ PLATFORM_CPPFLAGS += $(arch-y) $(tune-y)
 
 # Machine directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
+machine-$(CONFIG_ARCH_ASPEED)		+= aspeed
 machine-$(CONFIG_ARCH_AT91)		+= at91
 machine-$(CONFIG_ARCH_BCM283X)		+= bcm283x
 machine-$(CONFIG_ARCH_DAVINCI)		+= davinci
diff --git a/arch/arm/include/asm/arch-aspeed/timer.h b/arch/arm/include/asm/arch-aspeed/timer.h
new file mode 100644
index 0000000000000000000000000000000000000000..87c5b354ecf6341f0246273a55cc47a3829e88b0
--- /dev/null
+++ b/arch/arm/include/asm/arch-aspeed/timer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef _ASM_ARCH_TIMER_H
+#define _ASM_ARCH_TIMER_H
+
+/* Each timer has 4 control bits in ctrl1 register.
+ * Timer1 uses bits 0:3, Timer2 uses bits 4:7 and so on,
+ * such that timer X uses bits (4 * X - 4):(4 * X - 1)
+ * If the timer does not support PWM, bit 4 is reserved.
+ */
+#define AST_TMC_EN			(1 << 0)
+#define AST_TMC_1MHZ			(1 << 1)
+#define AST_TMC_OVFINTR			(1 << 2)
+#define AST_TMC_PWM			(1 << 3)
+
+/* Timers are counted from 1 in the datasheet. */
+#define AST_TMC_CTRL1_SHIFT(n)			(4 * ((n) - 1))
+
+#define AST_TMC_RATE  (1000*1000)
+
+#ifndef __ASSEMBLY__
+
+/*
+ * All timers share control registers, which makes it harder to make them
+ * separate devices. Since only one timer is needed at the moment, making
+ * it this just one device.
+ */
+
+struct ast_timer_counter {
+	u32 status;
+	u32 reload_val;
+	u32 match1;
+	u32 match2;
+};
+
+struct ast_timer {
+	struct ast_timer_counter timers1[3];
+	u32 ctrl1;
+	u32 ctrl2;
+#ifdef CONFIG_ASPEED_AST2500
+	u32 ctrl3;
+	u32 ctrl1_clr;
+#else
+	u32 reserved[2];
+#endif
+	struct ast_timer_counter timers2[5];
+};
+
+#endif  /* __ASSEMBLY__ */
+
+#endif  /* _ASM_ARCH_TIMER_H */
diff --git a/arch/arm/include/asm/arch-aspeed/wdt.h b/arch/arm/include/asm/arch-aspeed/wdt.h
new file mode 100644
index 0000000000000000000000000000000000000000..b292a0e67b5591a27d8423a76f401119e5118084
--- /dev/null
+++ b/arch/arm/include/asm/arch-aspeed/wdt.h
@@ -0,0 +1,99 @@
+/*
+ * (C) Copyright 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_WDT_H
+#define _ASM_ARCH_WDT_H
+
+#define WDT_BASE			0x1e785000
+
+/*
+ * Special value that needs to be written to counter_restart register to
+ * (re)start the timer
+ */
+#define WDT_COUNTER_RESTART_VAL		0x4755
+
+/* Control register */
+#define WDT_CTRL_RESET_MODE_SHIFT	5
+#define WDT_CTRL_RESET_MODE_MASK	3
+
+#define WDT_CTRL_EN			(1 << 0)
+#define WDT_CTRL_RESET			(1 << 1)
+#define WDT_CTRL_CLK1MHZ		(1 << 4)
+#define WDT_CTRL_2ND_BOOT		(1 << 7)
+
+/* Values for Reset Mode */
+#define WDT_CTRL_RESET_SOC		0
+#define WDT_CTRL_RESET_CHIP		1
+#define WDT_CTRL_RESET_CPU		2
+#define WDT_CTRL_RESET_MASK		3
+
+/* Reset Mask register */
+#define WDT_RESET_ARM			(1 << 0)
+#define WDT_RESET_COPROC		(1 << 1)
+#define WDT_RESET_SDRAM			(1 << 2)
+#define WDT_RESET_AHB			(1 << 3)
+#define WDT_RESET_I2C			(1 << 4)
+#define WDT_RESET_MAC1			(1 << 5)
+#define WDT_RESET_MAC2			(1 << 6)
+#define WDT_RESET_GCRT			(1 << 7)
+#define WDT_RESET_USB20			(1 << 8)
+#define WDT_RESET_USB11_HOST		(1 << 9)
+#define WDT_RESET_USB11_EHCI2		(1 << 10)
+#define WDT_RESET_VIDEO			(1 << 11)
+#define WDT_RESET_HAC			(1 << 12)
+#define WDT_RESET_LPC			(1 << 13)
+#define WDT_RESET_SDSDIO		(1 << 14)
+#define WDT_RESET_MIC			(1 << 15)
+#define WDT_RESET_CRT2C			(1 << 16)
+#define WDT_RESET_PWM			(1 << 17)
+#define WDT_RESET_PECI			(1 << 18)
+#define WDT_RESET_JTAG			(1 << 19)
+#define WDT_RESET_ADC			(1 << 20)
+#define WDT_RESET_GPIO			(1 << 21)
+#define WDT_RESET_MCTP			(1 << 22)
+#define WDT_RESET_XDMA			(1 << 23)
+#define WDT_RESET_SPI			(1 << 24)
+#define WDT_RESET_MISC			(1 << 25)
+
+#ifndef __ASSEMBLY__
+struct ast_wdt {
+	u32 counter_status;
+	u32 counter_reload_val;
+	u32 counter_restart;
+	u32 ctrl;
+	u32 timeout_status;
+	u32 clr_timeout_status;
+	u32 reset_width;
+#ifdef CONFIG_ASPEED_AST2500
+	u32 reset_mask;
+#else
+	u32 reserved0;
+#endif
+};
+
+void wdt_stop(struct ast_wdt *wdt);
+void wdt_start(struct ast_wdt *wdt, u32 timeout);
+
+/**
+ * Reset peripherals specified by mask
+ *
+ * Note, that this is only supported by ast2500 SoC
+ *
+ * @wdt: watchdog to use for this reset
+ * @mask: reset mask.
+ */
+int ast_wdt_reset_masked(struct ast_wdt *wdt, u32 mask);
+
+/**
+ * ast_get_wdt() - get a pointer to watchdog registers
+ *
+ * @wdt_number: 0-based WDT peripheral number
+ * @return pointer to registers or -ve error on error
+ */
+struct ast_wdt *ast_get_wdt(u8 wdt_number);
+#endif  /* __ASSEMBLY__ */
+
+#endif /* _ASM_ARCH_WDT_H */
diff --git a/arch/arm/mach-aspeed/Kconfig b/arch/arm/mach-aspeed/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..b72ed89af74fb7ad4b7bd1ce1f94eaebbe43e7a4
--- /dev/null
+++ b/arch/arm/mach-aspeed/Kconfig
@@ -0,0 +1,27 @@
+if ARCH_ASPEED
+
+config SYS_ARCH
+	default "arm"
+
+config SYS_SOC
+	default "aspeed"
+
+config SYS_TEXT_BASE
+	default 0x00000000
+
+config ASPEED_AST2500
+	bool "Support Aspeed AST2500 SoC"
+	select CPU_ARM1176
+	help
+	  The Aspeed AST2500 is a ARM-based SoC with arm1176 CPU.
+	  It is used as Board Management Controller on many server boards,
+	  which is enabled by support of LPC and eSPI peripherals.
+
+config WDT_NUM
+	int "Number of Watchdog Timers"
+	default 3 if ASPEED_AST2500
+	help
+	  The number of Watchdot Timers on a SoC.
+	  AST2500 has three WDTsk earlier versions have two or fewer.
+
+endif
diff --git a/arch/arm/mach-aspeed/Makefile b/arch/arm/mach-aspeed/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a14b8f751d28b7183ba72b3ce472e038b4c2c0d1
--- /dev/null
+++ b/arch/arm/mach-aspeed/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2016 Google, Inc
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_ARCH_ASPEED) += ast_wdt.o
diff --git a/arch/arm/mach-aspeed/ast_wdt.c b/arch/arm/mach-aspeed/ast_wdt.c
new file mode 100644
index 0000000000000000000000000000000000000000..22481ab7ea1ac4b8c7ae5c688dffe5c02aae504c
--- /dev/null
+++ b/arch/arm/mach-aspeed/ast_wdt.c
@@ -0,0 +1,59 @@
+/*
+ * (C) Copyright 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/wdt.h>
+#include <linux/err.h>
+
+void wdt_stop(struct ast_wdt *wdt)
+{
+	clrbits_le32(&wdt->ctrl, WDT_CTRL_EN);
+}
+
+void wdt_start(struct ast_wdt *wdt, u32 timeout)
+{
+	writel(timeout, &wdt->counter_reload_val);
+	writel(WDT_COUNTER_RESTART_VAL, &wdt->counter_restart);
+	/*
+	 * Setting CLK1MHZ bit is just for compatibility with ast2400 part.
+	 * On ast2500 watchdog timer clock is fixed at 1MHz and the bit is
+	 * read-only
+	 */
+	setbits_le32(&wdt->ctrl,
+		     WDT_CTRL_EN | WDT_CTRL_RESET | WDT_CTRL_CLK1MHZ);
+}
+
+struct ast_wdt *ast_get_wdt(u8 wdt_number)
+{
+	if (wdt_number > CONFIG_WDT_NUM - 1)
+		return ERR_PTR(-EINVAL);
+
+	return (struct ast_wdt *)(WDT_BASE +
+				  sizeof(struct ast_wdt) * wdt_number);
+}
+
+int ast_wdt_reset_masked(struct ast_wdt *wdt, u32 mask)
+{
+#ifdef CONFIG_ASPEED_AST2500
+	if (!mask)
+		return -EINVAL;
+
+	writel(mask, &wdt->reset_mask);
+	clrbits_le32(&wdt->ctrl,
+		     WDT_CTRL_RESET_MASK << WDT_CTRL_RESET_MODE_SHIFT);
+	wdt_start(wdt, 1);
+
+	/* Wait for WDT to reset */
+	while (readl(&wdt->ctrl) & WDT_CTRL_EN)
+		;
+	wdt_stop(wdt);
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index fa75cc52de76c7c14a0b13e81e46c11f0082837e..37638a8eea46d2d8161339893aa5d8fafc1a2fdb 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_ROCKCHIP_RK3399) += sysreset_rk3399.o
 obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
 obj-$(CONFIG_ARCH_SNAPDRAGON) += sysreset_snapdragon.o
 obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o
+obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
diff --git a/drivers/sysreset/sysreset_ast.c b/drivers/sysreset/sysreset_ast.c
new file mode 100644
index 0000000000000000000000000000000000000000..a0ab12851d4c5d1942c363afcb73f660547d3d6a
--- /dev/null
+++ b/drivers/sysreset/sysreset_ast.c
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <sysreset.h>
+#include <asm/io.h>
+#include <asm/arch/wdt.h>
+#include <linux/err.h>
+
+/* Number of Watchdog Timer ticks before reset */
+#define AST_WDT_RESET_TIMEOUT	10
+#define AST_WDT_FOR_RESET	0
+
+static int ast_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+	struct ast_wdt *wdt = ast_get_wdt(AST_WDT_FOR_RESET);
+	u32 reset_mode = 0;
+
+	if (IS_ERR(wdt))
+		return PTR_ERR(wdt);
+
+	switch (type) {
+	case SYSRESET_WARM:
+		reset_mode = WDT_CTRL_RESET_CPU;
+		break;
+	case SYSRESET_COLD:
+		reset_mode = WDT_CTRL_RESET_CHIP;
+		break;
+	default:
+		return -EPROTONOSUPPORT;
+	}
+
+	/* Clear reset mode bits */
+	clrsetbits_le32(&wdt->ctrl,
+			(WDT_CTRL_RESET_MODE_MASK << WDT_CTRL_RESET_MODE_SHIFT),
+			(reset_mode << WDT_CTRL_RESET_MODE_SHIFT));
+	wdt_start(wdt, AST_WDT_RESET_TIMEOUT);
+
+	return -EINPROGRESS;
+}
+
+static struct sysreset_ops ast_sysreset = {
+	.request	= ast_sysreset_request,
+};
+
+U_BOOT_DRIVER(sysreset_ast) = {
+	.name	= "ast_sysreset",
+	.id	= UCLASS_SYSRESET,
+	.ops	= &ast_sysreset,
+};
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index cb18f12fc99b90ee779e09c5dc37a1cfb9e0b6e4..cd38a6d4bd956d278c81cc9ceb71b9a494fd477e 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -46,4 +46,16 @@ config OMAP_TIMER
 	help
 	  Select this to enable an timer for Omap devices.
 
+config AST_TIMER
+	bool "Aspeed ast2400/ast2500 timer support"
+	depends on TIMER
+	default y if ARCH_ASPEED
+	help
+	  Select this to enable timer for Aspeed ast2400/ast2500 devices.
+	  This is a simple sys timer driver, it is compatible with lib/time.c,
+	  but does not support any interrupts. Even though SoC has 8 hardware
+	  counters, they are all treated as a single device by this driver.
+	  This is mostly because they all share several registers which
+	  makes it difficult to completely separate them.
+
 endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index f351fbb4e0ca10c594df39e6c527892e9cd164d7..a4b1a486b0f16d428756618d3326b909220167d4 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_ALTERA_TIMER)	+= altera_timer.o
 obj-$(CONFIG_SANDBOX_TIMER)	+= sandbox_timer.o
 obj-$(CONFIG_X86_TSC_TIMER)	+= tsc_timer.o
 obj-$(CONFIG_OMAP_TIMER)	+= omap-timer.o
+obj-$(CONFIG_AST_TIMER)	+= ast_timer.o
diff --git a/drivers/timer/ast_timer.c b/drivers/timer/ast_timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..d7c5460cd3c4813c91de96cc953e958e387a7d26
--- /dev/null
+++ b/drivers/timer/ast_timer.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <asm/arch/timer.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define AST_TICK_TIMER  1
+#define AST_TMC_RELOAD_VAL  0xffffffff
+
+struct ast_timer_priv {
+	struct ast_timer *regs;
+	struct ast_timer_counter *tmc;
+};
+
+static struct ast_timer_counter *ast_get_timer_counter(struct ast_timer *timer,
+						       int n)
+{
+	if (n > 3)
+		return &timer->timers2[n - 4];
+	else
+		return &timer->timers1[n - 1];
+}
+
+static int ast_timer_probe(struct udevice *dev)
+{
+	struct ast_timer_priv *priv = dev_get_priv(dev);
+	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	writel(AST_TMC_RELOAD_VAL, &priv->tmc->reload_val);
+
+	/*
+	 * Stop the timer. This will also load reload_val into
+	 * the status register.
+	 */
+	clrbits_le32(&priv->regs->ctrl1,
+		     AST_TMC_EN << AST_TMC_CTRL1_SHIFT(AST_TICK_TIMER));
+	/* Start the timer from the fixed 1MHz clock. */
+	setbits_le32(&priv->regs->ctrl1,
+		     (AST_TMC_EN | AST_TMC_1MHZ) <<
+		     AST_TMC_CTRL1_SHIFT(AST_TICK_TIMER));
+
+	uc_priv->clock_rate = AST_TMC_RATE;
+
+	return 0;
+}
+
+static int ast_timer_get_count(struct udevice *dev, u64 *count)
+{
+	struct ast_timer_priv *priv = dev_get_priv(dev);
+
+	*count = AST_TMC_RELOAD_VAL - readl(&priv->tmc->status);
+
+	return 0;
+}
+
+static int ast_timer_ofdata_to_platdata(struct udevice *dev)
+{
+	struct ast_timer_priv *priv = dev_get_priv(dev);
+
+	priv->regs = dev_get_addr_ptr(dev);
+	if (IS_ERR(priv->regs))
+		return PTR_ERR(priv->regs);
+
+	priv->tmc = ast_get_timer_counter(priv->regs, AST_TICK_TIMER);
+
+	return 0;
+}
+
+static const struct timer_ops ast_timer_ops = {
+	.get_count = ast_timer_get_count,
+};
+
+static const struct udevice_id ast_timer_ids[] = {
+	{ .compatible = "aspeed,ast2500-timer" },
+	{ .compatible = "aspeed,ast2400-timer" },
+	{ }
+};
+
+U_BOOT_DRIVER(ast_timer) = {
+	.name = "ast_timer",
+	.id = UCLASS_TIMER,
+	.of_match = ast_timer_ids,
+	.probe = ast_timer_probe,
+	.priv_auto_alloc_size = sizeof(struct ast_timer_priv),
+	.ofdata_to_platdata = ast_timer_ofdata_to_platdata,
+	.ops = &ast_timer_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};