diff --git a/doc/device-tree-bindings/mailbox/mailbox.txt b/doc/device-tree-bindings/mailbox/mailbox.txt
new file mode 100644
index 0000000000000000000000000000000000000000..be05b9746c693c5cd595bfdd48411d143a18f1c5
--- /dev/null
+++ b/doc/device-tree-bindings/mailbox/mailbox.txt
@@ -0,0 +1,32 @@
+* Generic Mailbox Controller and client driver bindings
+
+Generic binding to provide a way for Mailbox controller drivers to
+assign appropriate mailbox channel to client drivers.
+
+* Mailbox Controller
+
+Required property:
+- #mbox-cells: Must be at least 1. Number of cells in a mailbox
+		specifier.
+
+Example:
+	mailbox: mailbox {
+		...
+		#mbox-cells = <1>;
+	};
+
+
+* Mailbox Client
+
+Required property:
+- mboxes: List of phandle and mailbox channel specifiers.
+
+Optional property:
+- mbox-names: List of identifier strings for each mailbox channel.
+
+Example:
+	pwr_cntrl: power {
+		...
+		mbox-names = "pwr-ctrl", "rpc";
+		mboxes = <&mailbox 0 &mailbox 1>;
+	};
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 118b66ed0e14c6828da5308abf01846c27b407e4..f2a137ad87fce76fc4fba6067324a22eed9a539e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -30,6 +30,8 @@ source "drivers/input/Kconfig"
 
 source "drivers/led/Kconfig"
 
+source "drivers/mailbox/Kconfig"
+
 source "drivers/memory/Kconfig"
 
 source "drivers/misc/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 99dd07fc7698f4f463840f0050ed3c138d4dbd42..f6295d285ece6a41cf4ae16a8945ade1d51a57a0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -64,6 +64,7 @@ obj-y += video/
 obj-y += watchdog/
 obj-$(CONFIG_QE) += qe/
 obj-$(CONFIG_U_QE) += qe/
+obj-y += mailbox/
 obj-y += memory/
 obj-y += pwm/
 obj-y += input/
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..295e6db0f28c79959d0c364aa4d6a833cf37804a
--- /dev/null
+++ b/drivers/mailbox/Kconfig
@@ -0,0 +1,13 @@
+menu "Mailbox Controller Support"
+
+config DM_MAILBOX
+	bool "Enable mailbox controllers using Driver Model"
+	depends on DM && OF_CONTROL
+	help
+	  Enable support for the mailbox driver class. Mailboxes provide the
+	  ability to transfer small messages and/or notifications from one
+	  CPU to another CPU, or sometimes to dedicated HW modules. They form
+	  the basis of a variety of inter-process/inter-CPU communication
+	  protocols.
+
+endmenu
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a2d96a4e3b9871ab46af947f2c52b3d5765a9759
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1,5 @@
+# Copyright (c) 2016, NVIDIA CORPORATION.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_DM_MAILBOX) += mailbox-uclass.o
diff --git a/drivers/mailbox/mailbox-uclass.c b/drivers/mailbox/mailbox-uclass.c
new file mode 100644
index 0000000000000000000000000000000000000000..73fa32874a5fa14401fcaf6e4ff4997752d8c492
--- /dev/null
+++ b/drivers/mailbox/mailbox-uclass.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <mailbox_client.h>
+#include <mailbox_uclass.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline struct mbox_ops *mbox_dev_ops(struct udevice *dev)
+{
+	return (struct mbox_ops *)dev->driver->ops;
+}
+
+static int mbox_of_xlate_default(struct mbox_chan *chan,
+				 struct fdtdec_phandle_args *args)
+{
+	debug("%s(chan=%p)\n", __func__, chan);
+
+	if (args->args_count != 1) {
+		debug("Invaild args_count: %d\n", args->args_count);
+		return -EINVAL;
+	}
+
+	chan->id = args->args[0];
+
+	return 0;
+}
+
+int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan)
+{
+	struct fdtdec_phandle_args args;
+	int ret;
+	struct udevice *dev_mbox;
+	struct mbox_ops *ops;
+
+	debug("%s(dev=%p, index=%d, chan=%p)\n", __func__, dev, index, chan);
+
+	ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
+					     "mboxes", "#mbox-cells", 0,
+					     index, &args);
+	if (ret) {
+		debug("%s: fdtdec_parse_phandle_with_args failed: %d\n",
+		      __func__, ret);
+		return ret;
+	}
+
+	ret = uclass_get_device_by_of_offset(UCLASS_MAILBOX, args.node,
+					     &dev_mbox);
+	if (ret) {
+		debug("%s: uclass_get_device_by_of_offset failed: %d\n",
+		      __func__, ret);
+		return ret;
+	}
+	ops = mbox_dev_ops(dev_mbox);
+
+	chan->dev = dev_mbox;
+	if (ops->of_xlate)
+		ret = ops->of_xlate(chan, &args);
+	else
+		ret = mbox_of_xlate_default(chan, &args);
+	if (ret) {
+		debug("of_xlate() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = ops->request(chan);
+	if (ret) {
+		debug("ops->request() failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int mbox_get_by_name(struct udevice *dev, const char *name,
+		     struct mbox_chan *chan)
+{
+	int index;
+
+	debug("%s(dev=%p, name=%s, chan=%p)\n", __func__, dev, name, chan);
+
+	index = fdt_find_string(gd->fdt_blob, dev->of_offset, "mbox-names",
+				name);
+	if (index < 0) {
+		debug("fdt_find_string() failed: %d\n", index);
+		return index;
+	}
+
+	return mbox_get_by_index(dev, index, chan);
+}
+
+int mbox_free(struct mbox_chan *chan)
+{
+	struct mbox_ops *ops = mbox_dev_ops(chan->dev);
+
+	debug("%s(chan=%p)\n", __func__, chan);
+
+	return ops->free(chan);
+}
+
+int mbox_send(struct mbox_chan *chan, const void *data)
+{
+	struct mbox_ops *ops = mbox_dev_ops(chan->dev);
+
+	debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
+
+	return ops->send(chan, data);
+}
+
+int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us)
+{
+	struct mbox_ops *ops = mbox_dev_ops(chan->dev);
+	ulong start_time;
+	int ret;
+
+	debug("%s(chan=%p, data=%p, timeout_us=%ld)\n", __func__, chan, data,
+	      timeout_us);
+
+	start_time = timer_get_us();
+	/*
+	 * Account for partial us ticks, but if timeout_us is 0, ensure we
+	 * still don't wait at all.
+	 */
+	if (timeout_us)
+		timeout_us++;
+
+	for (;;) {
+		ret = ops->recv(chan, data);
+		if (ret != -ENODATA)
+			return ret;
+		if ((timer_get_us() - start_time) >= timeout_us)
+			return -ETIMEDOUT;
+	}
+}
+
+UCLASS_DRIVER(mailbox) = {
+	.id		= UCLASS_MAILBOX,
+	.name		= "mailbox",
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index f9ff45e010f55805717adcd28e5327be4b1a6adf..0777cbe27ee53676e72b0d095086693438bcd860 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -44,6 +44,7 @@ enum uclass_id {
 	UCLASS_KEYBOARD,	/* Keyboard input device */
 	UCLASS_LED,		/* Light-emitting diode (LED) */
 	UCLASS_LPC,		/* x86 'low pin count' interface */
+	UCLASS_MAILBOX,		/* Mailbox controller */
 	UCLASS_MASS_STORAGE,	/* Mass storage device */
 	UCLASS_MISC,		/* Miscellaneous device */
 	UCLASS_MMC,		/* SD / MMC card or chip */
diff --git a/include/mailbox_client.h b/include/mailbox_client.h
new file mode 100644
index 0000000000000000000000000000000000000000..8345ea0bf1fbf2d6b1c25e44d8bf0ba8e393aca3
--- /dev/null
+++ b/include/mailbox_client.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _MAILBOX_CLIENT_H
+#define _MAILBOX_CLIENT_H
+
+/**
+ * A mailbox is a hardware mechanism for transferring small fixed-size messages
+ * and/or notifications between the CPU on which U-Boot runs and some other
+ * device such as an auxiliary CPU running firmware or a hardware module.
+ *
+ * Data transfer is optional; a mailbox may consist solely of a notification
+ * mechanism. When data transfer is implemented, it is via HW registers or
+ * FIFOs, rather than via RAM-based buffers. The mailbox API generally
+ * implements any communication protocol enforced solely by hardware, and
+ * leaves any higher-level protocols to other layers.
+ *
+ * A mailbox channel is a bi-directional mechanism that can send a message or
+ * notification to a single specific remote entity, and receive messages or
+ * notifications from that entity. The size, content, and format of such
+ * messages is defined by the mailbox implementation, or the remote entity with
+ * which it communicates; there is no general standard at this API level.
+ *
+ * A driver that implements UCLASS_MAILBOX is a mailbox provider. A provider
+ * will often implement multiple separate mailbox channels, since the hardware
+ * it manages often has this capability. mailbox_uclass.h describes the
+ * interface which mailbox providers must implement.
+ *
+ * Mailbox consumers/clients generate and send, or receive and process,
+ * messages. This header file describes the API used by clients.
+ */
+
+struct udevice;
+
+/**
+ * struct mbox_chan - A handle to a single mailbox channel.
+ *
+ * Clients provide storage for channels. The content of the channel structure
+ * is managed solely by the mailbox API and mailbox drivers. A mailbox channel
+ * is initialized by "get"ing the mailbox. The channel struct is passed to all
+ * other mailbox APIs to identify which mailbox to operate upon.
+ *
+ * @dev: The device which implements the mailbox.
+ * @id: The mailbox channel ID within the provider.
+ *
+ * Currently, the mailbox API assumes that a single integer ID is enough to
+ * identify and configure any mailbox channel for any mailbox provider. If this
+ * assumption becomes invalid in the future, the struct could be expanded to
+ * either (a) add more fields to allow mailbox providers to store additional
+ * information, or (b) replace the id field with an opaque pointer, which the
+ * provider would dynamically allocated during its .of_xlate op, and process
+ * during is .request op. This may require the addition of an extra op to clean
+ * up the allocation.
+ */
+struct mbox_chan {
+	struct udevice *dev;
+	/*
+	 * Written by of_xlate. We assume a single id is enough for now. In the
+	 * future, we might add more fields here.
+	 */
+	unsigned long id;
+};
+
+/**
+ * mbox_get_by_index - Get/request a mailbox by integer index
+ *
+ * This looks up and requests a mailbox channel. The index is relative to the
+ * client device; each device is assumed to have n mailbox channels associated
+ * with it somehow, and this function finds and requests one of them. The
+ * mapping of client device channel indices to provider channels may be via
+ * device-tree properties, board-provided mapping tables, or some other
+ * mechanism.
+ *
+ * @dev:	The client device.
+ * @index:	The index of the mailbox channel to request, within the
+ *		client's list of channels.
+ * @chan	A pointer to a channel object to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan);
+
+/**
+ * mbox_get_by_name - Get/request a mailbox by name
+ *
+ * This looks up and requests a mailbox channel. The name is relative to the
+ * client device; each device is assumed to have n mailbox channels associated
+ * with it somehow, and this function finds and requests one of them. The
+ * mapping of client device channel names to provider channels may be via
+ * device-tree properties, board-provided mapping tables, or some other
+ * mechanism.
+ *
+ * @dev:	The client device.
+ * @name:	The name of the mailbox channel to request, within the client's
+ *		list of channels.
+ * @chan	A pointer to a channel object to initialize.
+ * @return 0 if OK, or a negative error code.
+ */
+int mbox_get_by_name(struct udevice *dev, const char *name,
+		     struct mbox_chan *chan);
+
+/**
+ * mbox_free - Free a previously requested mailbox channel.
+ *
+ * @chan:	A channel object that was previously successfully requested by
+ *		calling mbox_get_by_*().
+ * @return 0 if OK, or a negative error code.
+ */
+int mbox_free(struct mbox_chan *chan);
+
+/**
+ * mbox_send - Send a message over a mailbox channel
+ *
+ * This function will send a message to the remote entity. It may return before
+ * the remote entity has received and/or processed the message.
+ *
+ * @chan:	A channel object that was previously successfully requested by
+ *		calling mbox_get_by_*().
+ * @data:	A pointer to the message to transfer. The format and size of
+ *		the memory region pointed at by @data is determined by the
+ *		mailbox provider. Providers that solely transfer notifications
+ *		will ignore this parameter.
+ * @return 0 if OK, or a negative error code.
+ */
+int mbox_send(struct mbox_chan *chan, const void *data);
+
+/**
+ * mbox_recv - Receive any available message from a mailbox channel
+ *
+ * This function will wait (up to the specified @timeout_us) for a message to
+ * be sent by the remote entity, and write the content of any such message
+ * into a caller-provided buffer.
+ *
+ * @chan:	A channel object that was previously successfully requested by
+ *		calling mbox_get_by_*().
+ * @data:	A pointer to the buffer to receive the message. The format and
+ *		size of the memory region pointed at by @data is determined by
+ *		the mailbox provider. Providers that solely transfer
+ *		notifications will ignore this parameter.
+ * @timeout_us:	The maximum time to wait for a message to be available, in
+ *		micro-seconds. A value of 0 does not wait at all.
+ * @return 0 if OK, -ENODATA if no message was available, or a negative error
+ * code.
+ */
+int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us);
+
+#endif
diff --git a/include/mailbox_uclass.h b/include/mailbox_uclass.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a2994c34cea0776a02d6a0003f1af71d00066bb
--- /dev/null
+++ b/include/mailbox_uclass.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _MAILBOX_UCLASS_H
+#define _MAILBOX_UCLASS_H
+
+/* See mailbox_client.h for background documentation. */
+
+#include <mailbox_client.h>
+
+struct udevice;
+
+/**
+ * struct mbox_ops - The functions that a mailbox driver must implement.
+ */
+struct mbox_ops {
+	/**
+	 * of_xlate - Translate a client's device-tree (OF) mailbox specifier.
+	 *
+	 * The mailbox core calls this function as the first step in
+	 * implementing a client's mbox_get_by_*() call.
+	 *
+	 * If this function pointer is set to NULL, the mailbox core will use
+	 * a default implementation, which assumes #mbox-cells = <1>, and that
+	 * the DT cell contains a simple integer channel ID.
+	 *
+	 * At present, the mailbox API solely supports device-tree. If this
+	 * changes, other xxx_xlate() functions may be added to support those
+	 * other mechanisms.
+	 *
+	 * @chan:	The channel to hold the translation result.
+	 * @args:	The mailbox specifier values from device tree.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*of_xlate)(struct mbox_chan *chan,
+			struct fdtdec_phandle_args *args);
+	/**
+	 * request - Request a translated channel.
+	 *
+	 * The mailbox core calls this function as the second step in
+	 * implementing a client's mbox_get_by_*() call, following a successful
+	 * xxx_xlate() call.
+	 *
+	 * @chan:	The channel to request; this has been filled in by a
+	 *		previoux xxx_xlate() function call.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*request)(struct mbox_chan *chan);
+	/**
+	 * free - Free a previously requested channel.
+	 *
+	 * This is the implementation of the client mbox_free() API.
+	 *
+	 * @chan:	The channel to free.
+	 * @return 0 if OK, or a negative error code.
+	 */
+	int (*free)(struct mbox_chan *chan);
+	/**
+	* send - Send a message over a mailbox channel
+	*
+	* @chan:	The channel to send to the message to.
+	* @data:	A pointer to the message to send.
+	* @return 0 if OK, or a negative error code.
+	*/
+	int (*send)(struct mbox_chan *chan, const void *data);
+	/**
+	* recv - Receive any available message from the channel.
+	*
+	* This function does not block. If not message is immediately
+	* available, the function should return an error.
+	*
+	* @chan:	The channel to receive to the message from.
+	* @data:	A pointer to the buffer to hold the received message.
+	* @return 0 if OK, -ENODATA if no message was available, or a negative
+	* error code.
+	*/
+	int (*recv)(struct mbox_chan *chan, void *data);
+};
+
+#endif