diff --git a/Documentation/devicetree/bindings/quirks/am33xx-bone-quirk.txt b/Documentation/devicetree/bindings/quirks/am33xx-bone-quirk.txt
new file mode 100644
index 0000000..239dd8d
--- /dev/null
+++ b/Documentation/devicetree/bindings/quirks/am33xx-bone-quirk.txt
@@ -0,0 +1,82 @@
+am33xx Beaglebone White/Black Device Tree Bindings
+--------------------------------------------------
+
+Beaglebone boards that boot with a common device tree blob contain
+a DT quirk entry with the following properties:
+
+Required properties:
+
+- compatible : should be "ti,am33xx-bone-quirk"
+
+Required child node:
+
+- revs : Contains children nodes that identify boards
+
+  Each child node of revs must be of the following form:
+
+  Required properties:
+
+  - board-id : Contain the board ID as it appears in the EEPROM
+  - board-apply : Should contain the phandle of the quirk to apply
+
+  Optional child node:
+
+  - options : Contain a number of properties that identify options
+  that can be enabled or disabled by external means. For Linux the
+  options are selected by parsing the boot command line.
+  The properties contain a tupple of quirk phandles, the first containing
+  the enable quirk and the second the disable quirk. If the phandle is zero
+  then no quirk is applied.
+
+Any other nodes (like the quirk definitions are ignored).
+
+The following example defines two revisions (white/black) with
+board-id A335BONE for the white and A335BNLT for the black.
+For the beaglebone black we also define two options
+no-emmc and no-hdmi which when are present in the boot command line
+the emmc and hdmi are disabled.
+
+	beaglebone-quirks {
+		compatible = "ti,am33xx-bone-quirk";
+		status = "okay";
+
+		revs {
+			white {
+				board-id = "A335BONE";
+				board-apply = <&bonewhite>;
+			};
+			black {
+				board-id = "A335BNLT";
+				board-apply = <&boneblack>;
+				options {
+					no-emmc = <0 &black_enable_emmc>;
+					no-hdmi = <0 &black_enable_hdmi>;
+				};
+			};
+		};
+
+		overlays {
+			bonewhite: bonewhite {
+				/* quirk for white */
+				...
+			};
+
+			boneblack: boneblack {
+				/* quirk for black */
+				...
+			};
+
+			black_enable_hdmi: black_hdmi {
+				/* quirk to enable hdmi */
+				...
+			};
+
+			black_enable_emmc: black_emmc {
+				/* quirk to enable emmc */
+				...
+			};
+		};
+	};
+
+
+
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 5d27dfd..02129e7 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -259,6 +259,11 @@ obj-$(CONFIG_MACH_CRANEBOARD)		+= board-am3517crane.o
 
 obj-$(CONFIG_MACH_SBC3530)		+= board-omap3stalker.o
 
+# DT quirks
+ifneq ($(CONFIG_OF_DYNAMIC),)
+obj-$(CONFIG_SOC_AM33XX)		+= am33xx-dt-quirks.o
+endif
+
 # Platform specific device init code
 
 omap-flash-$(CONFIG_MTD_NAND_OMAP2)	:= board-flash.o
diff --git a/arch/arm/mach-omap2/am33xx-dt-quirks.c b/arch/arm/mach-omap2/am33xx-dt-quirks.c
new file mode 100644
index 0000000..668235c
--- /dev/null
+++ b/arch/arm/mach-omap2/am33xx-dt-quirks.c
@@ -0,0 +1,498 @@
+/*
+ * arch/arm/mach-omap2/am33xx-dt-quirks.c
+ *
+ * AM33xx variant DT quirks
+ *
+ * Copyright (C) 2015 Konsulko Group
+ *
+ * Author:
+ *	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "am33xx-dt-quirks.h"
+
+/*
+ * The board IDs for am33xx board are in an I2C EEPROM
+ * We are very early in the boot process so we have to
+ * read the EEPROM directly without using the I2C layer.
+ *
+ * Note that we rely on the bootloader setting up the muxes
+ * (which is the case for u-boot).
+ */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_XDR	(1 << 14)	/* TX Buffer draining */
+#define OMAP_I2C_STAT_RDR	(1 << 13)	/* RX Buffer draining */
+#define OMAP_I2C_STAT_BB	(1 << 12)	/* Bus busy */
+#define OMAP_I2C_STAT_ROVR	(1 << 11)	/* Receive overrun */
+#define OMAP_I2C_STAT_XUDF	(1 << 10)	/* Transmit underflow */
+#define OMAP_I2C_STAT_AAS	(1 << 9)	/* Address as slave */
+#define OMAP_I2C_STAT_BF	(1 << 8)	/* Bus Free */
+#define OMAP_I2C_STAT_XRDY	(1 << 4)	/* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY	(1 << 3)	/* Receive data ready */
+#define OMAP_I2C_STAT_ARDY	(1 << 2)	/* Register access ready */
+#define OMAP_I2C_STAT_NACK	(1 << 1)	/* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL	(1 << 0)	/* Arbitration lost int ena */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN		(1 << 15)	/* I2C module enable */
+#define OMAP_I2C_CON_BE		(1 << 14)	/* Big endian mode */
+#define OMAP_I2C_CON_OPMODE_HS	(1 << 12)	/* High Speed support */
+#define OMAP_I2C_CON_STB	(1 << 11)	/* Start byte mode (master) */
+#define OMAP_I2C_CON_MST	(1 << 10)	/* Master/slave mode */
+#define OMAP_I2C_CON_TRX	(1 << 9)	/* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA		(1 << 8)	/* Expand address */
+#define OMAP_I2C_CON_RM		(1 << 2)	/* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP	(1 << 1)	/* Stop cond (master only) */
+#define OMAP_I2C_CON_STT	(1 << 0)	/* Start condition (master) */
+
+/* register definitions */
+#define I2C_REVNB_LO		0x00
+#define I2C_REVNB_HI		0x04
+#define I2C_SYSC		0x10
+#define I2C_IRQSTATUS_RAW	0x24
+#define I2C_IRQSTATUS		0x28
+#define I2C_IRQENABLE_SET	0x2C
+#define I2C_IRQENABLE_CLR	0x30
+#define I2C_WE			0x34
+#define I2C_DMARXENABLE_SET	0x38
+#define I2C_DMATXENABLE_SET	0x3C
+#define I2C_DMARXENABLE_CLR	0x40
+#define I2C_DMATXENABLE_CLR	0x44
+#define I2C_DMARXWAKE_EN	0x48
+#define I2C_DMATXWAKE_EN	0x4C
+#define I2C_SYSS		0x90
+#define I2C_BUF			0x94
+#define I2C_CNT			0x98
+#define I2C_DATA		0x9C
+#define I2C_CON			0xA4
+#define I2C_OA			0xA8
+#define I2C_SA			0xAC
+#define I2C_PSC			0xB0
+#define I2C_SCLL		0xB4
+#define I2C_SCLH		0xB8
+#define I2C_SYSTEST		0xBC
+#define I2C_BUFSTAT		0xC0
+#define I2C_OA1			0xC4
+#define I2C_OA2			0xC8
+#define I2C_OA3			0xCC
+#define I2C_ACTOA		0xD0
+#define I2C_SBLOCK		0xD4
+
+static inline void i2c_reg_write(void __iomem *base, unsigned int reg, u16 val)
+{
+	writew_relaxed(val, base + reg);
+}
+
+static inline u16 i2c_reg_read(void __iomem *base, unsigned int reg)
+{
+	return readw_relaxed(base + reg);
+}
+
+static void flush_fifo(void __iomem *base)
+{
+	u16 stat;
+
+	while ((stat = i2c_reg_read(base, I2C_IRQSTATUS_RAW))
+			& OMAP_I2C_STAT_RRDY) {
+		(void)i2c_reg_read(base, I2C_DATA);
+		i2c_reg_write(base, I2C_IRQSTATUS, OMAP_I2C_STAT_RRDY);
+		udelay(1000);
+	};
+}
+
+static void wait_delay(void __iomem *base)
+{
+	udelay((10000000 / 100000) * 2);
+}
+
+static int wait_for_bb(void __iomem *base)
+{
+	int timeout;
+	u16 stat;
+
+	timeout = 1000;
+	while (((stat = i2c_reg_read(base, I2C_IRQSTATUS_RAW)) &
+				OMAP_I2C_STAT_BB) && timeout--) {
+		i2c_reg_write(base, I2C_IRQSTATUS, stat);
+		wait_delay(base);
+	}
+
+	if (timeout <= 0) {
+		pr_err("%s: Timeout while waiting for bus\n", __func__);
+		return -1;
+	}
+	i2c_reg_write(base, I2C_IRQSTATUS, 0xffff);
+	return 0;
+}
+
+static u16 wait_for_event(void __iomem *base)
+{
+	u16 status;
+	int timeout = 10000;
+
+	do {
+		wait_delay(base);
+		status = i2c_reg_read(base, I2C_IRQSTATUS_RAW);
+	} while (!(status & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF |
+		    OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_RRDY |
+		    OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+		    OMAP_I2C_STAT_AL)) &&
+			timeout--);
+
+	if (timeout <= 0) {
+		pr_err("%s: Timeout status=%04x\n", __func__, status);
+		i2c_reg_write(base, I2C_IRQSTATUS, 0xffff);
+		status = 0;
+	}
+
+	return status;
+}
+
+static int i2c_init(void __iomem *base, u16 psc, u16 scll, u16 sclh)
+{
+	int timeout;
+
+	/* init */
+	if (i2c_reg_read(base, I2C_CON) & OMAP_I2C_CON_EN) {
+		i2c_reg_write(base, I2C_CON, 0);
+		for (timeout = 0; timeout <= 50000; timeout += 1000)
+			udelay(1000);
+	}
+
+	/* soft reset */
+	i2c_reg_write(base, I2C_SYSC, 0x02);
+	udelay(1000);
+	i2c_reg_write(base, I2C_CON, OMAP_I2C_CON_EN);
+
+	timeout = 1000;
+	while (!(i2c_reg_read(base, I2C_SYSS) & 0x0001) && timeout--) {
+		if (timeout <= 0) {
+			pr_err("%s: Timeout in soft reset\n", __func__);
+			return -ENODEV;
+		}
+		udelay(1000);
+	}
+
+	i2c_reg_write(base, I2C_CON, 0x0000);
+	i2c_reg_write(base, I2C_PSC, psc);
+	i2c_reg_write(base, I2C_SCLL, scll);
+	i2c_reg_write(base, I2C_SCLH, sclh);
+	i2c_reg_write(base, I2C_CON, 0x8000);
+	udelay(1000);
+
+	i2c_reg_write(base, I2C_OA, 1);
+
+	/* flush fifo */
+	flush_fifo(base);
+	i2c_reg_write(base, I2C_IRQSTATUS, 0xffff);
+
+	return 0;
+}
+
+static int i2c_read(void __iomem *base, u8 chip, u16 addr,
+		unsigned int alen,
+		void *buffer, int len)
+{
+	u8 *s = buffer;
+	unsigned int i;
+	u16 status;
+	int timeout, ret;
+
+	if (alen < 0 || len < 0 || !buffer || alen > 2 ||
+			(addr + len > 0x10000))
+		return -EINVAL;
+
+	if (wait_for_bb(base) != 0) {
+		pr_err("%s: wait for bb fail\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = -EINVAL;
+	i2c_reg_write(base, I2C_SA, chip);
+
+	if (alen) {
+		i2c_reg_write(base, I2C_CNT, alen);
+
+		/* Stop - Start (P-S) */
+		i2c_reg_write(base, I2C_CON, OMAP_I2C_CON_EN |
+			OMAP_I2C_CON_MST | OMAP_I2C_CON_STT |
+			OMAP_I2C_CON_STP | OMAP_I2C_CON_TRX);
+		while (alen > 0) {
+			status = wait_for_event(base);
+			if (status == 0 || (status & OMAP_I2C_STAT_NACK)) {
+				ret = -ENODEV;
+				pr_err("%s: error waiting for addr ACK\n",
+						__func__);
+				goto out;
+			}
+			if (status & OMAP_I2C_STAT_XRDY) {
+				alen--;
+				i2c_reg_write(base, I2C_DATA,
+					(addr >> (8 * alen)) & 0xff);
+				i2c_reg_write(base, I2C_IRQSTATUS,
+						OMAP_I2C_STAT_XRDY);
+			}
+		}
+
+		/* poll ARDY for last byte going out */
+		timeout = 1000;
+		do {
+			status = wait_for_event(base);
+			if (status & OMAP_I2C_STAT_ARDY)
+				break;
+			udelay(1000);
+		} while (timeout--);
+
+		if (timeout <= 0) {
+			ret = -ENODEV;
+			pr_err("%s: timeout waiting for ARDY\n",
+					__func__);
+			goto out;
+		}
+
+		i2c_reg_write(base, I2C_IRQSTATUS, OMAP_I2C_STAT_ARDY);
+
+		wait_delay(base);
+	}
+
+	i2c_reg_write(base, I2C_CNT, len);
+
+	i2c_reg_write(base, I2C_CON, OMAP_I2C_CON_EN | OMAP_I2C_CON_MST |
+		OMAP_I2C_CON_STT | OMAP_I2C_CON_STP);
+
+	i = 0;
+	while (i < len) {
+		status = wait_for_event(base);
+		if (status == 0 || (status & OMAP_I2C_STAT_NACK)) {
+			ret = -ENODEV;
+			pr_err("%s: error waiting for data ACK\n",
+					__func__);
+			goto out;
+		}
+		if (status & OMAP_I2C_STAT_RRDY) {
+			*s++ = (u8)i2c_reg_read(base, I2C_DATA);
+			i2c_reg_write(base, I2C_IRQSTATUS,
+					OMAP_I2C_STAT_RRDY);
+			i++;
+		}
+		if (status & OMAP_I2C_STAT_ARDY) {
+			i2c_reg_write(base, I2C_IRQSTATUS,
+					OMAP_I2C_STAT_ARDY);
+			break;
+		}
+	}
+
+	if (i < len)
+		pr_err("%s: short read (%u < %u)\n", __func__, i, len);
+	ret = i;
+
+out:
+	flush_fifo(base);
+	i2c_reg_write(base, I2C_IRQSTATUS, 0xffff);
+	return ret;
+}
+
+struct am335x_baseboard_id {
+	u8 magic[4];
+	u8 name[8];
+	u8 version[4];
+	u8 serial[12];
+	u8 config[32];
+	u8 mac_addr[3][6];
+};
+
+static int beaglebone_read_header(struct am335x_baseboard_id *hdr)
+{
+	void __iomem *base;
+	u32 magic;
+	int ret;
+
+	/* map I2C0 */
+	base = ioremap((phys_addr_t)0x44E0B000, 0x1000);
+	if (base == NULL) {
+		pr_err("%s: failed to ioremap\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = i2c_init(base, 0x0000, 0x00ea, 0x00ea);
+	if (ret != 0) {
+		pr_err("%s: i2c_init failed\n", __func__);
+		return ret;
+	}
+
+	/* the EEPROM is at 0x50 */
+	ret = i2c_read(base, 0x50, 0, 2, hdr, sizeof(*hdr));
+	if (ret != sizeof(*hdr)) {
+		pr_err("%s: Failed to read EEPROM\n", __func__);
+		ret = ret >= 0 ? -EINVAL : ret;
+		goto out;
+	}
+
+	print_hex_dump(KERN_DEBUG, "EEPROM: ", DUMP_PREFIX_OFFSET,
+			16, 1, hdr, sizeof(*hdr), true);
+
+	/* magic value is LE */
+	magic = ((u32)hdr->magic[3] << 24) | ((u32)hdr->magic[2] << 16) |
+		((u32)hdr->magic[1] << 8) | hdr->magic[0];
+	if (magic != 0xEE3355AA) {
+		pr_err("%s: Bad EEPROM (0x%08x) %02x %02x %02x %02x\n",
+				__func__, magic,
+				hdr->magic[0], hdr->magic[1],
+				hdr->magic[2], hdr->magic[3]);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = 0;
+
+out:
+	iounmap(base);
+	return ret;
+}
+
+/* find whether a command line argument exists */
+static const char *command_line_arg(const char *bootargs, const char *what)
+{
+	const char *s, *e, *p;
+	int len;
+
+	len = strlen(what);
+	s = bootargs;
+	e = bootargs + strlen(bootargs);
+	for (; s < e && (p = strstr(s, what)) != NULL; s += len) {
+
+		/* if not the first arguments a space must precede */
+		if (p > bootargs && p[-1] != ' ')
+			continue;
+
+		/* skip over what */
+		p += len;
+
+		/* if not the last argument a space must follow */
+		if (p < e && *p != ' ')
+			continue;
+
+		return p;
+	}
+
+	return NULL;
+}
+
+static void __init beaglebone_dt_quirk(void)
+{
+	struct am335x_baseboard_id header;
+	struct device_node *np, *revnp, *child, *optnp, *chosen;
+	struct property *prop;
+	char name[8 + 1];
+	const char *detected_board_id, *board_id, *bootargs;
+	int i, ret;
+	phandle ph;
+
+	np = NULL;
+	revnp = NULL;
+	optnp = NULL;
+	chosen = NULL;
+
+	/* beaglebone quirks */
+	np = of_find_compatible_node(NULL, NULL, "ti,am33xx-bone-quirk");
+	if (!np || !of_device_is_available(np))
+		goto out;
+
+	revnp = of_get_child_by_name(np, "revs");
+	if (!revnp) {
+		pr_err("%s: no revs node at %pO\n", __func__, np);
+		goto out;
+	}
+	child = NULL;
+	optnp = NULL;
+	chosen = NULL;
+
+	ret = beaglebone_read_header(&header);
+	if (ret != 0) {
+		pr_err("%s: Failed to read EEPROM\n", __func__);
+		goto out;
+	}
+	memcpy(name, header.name, sizeof(header.name));
+	name[sizeof(header.name)] = '\0';
+
+	detected_board_id = name;
+
+	pr_debug("%s: Finding quirks for board_id=%s\n", __func__,
+			detected_board_id);
+	for_each_child_of_node(revnp, child) {
+		if (!of_property_read_string(child, "board-id", &board_id) &&
+			!strcmp(board_id, detected_board_id))
+			goto found;
+	}
+	pr_warn("%s: No quirks for board_id=%s\n", __func__, detected_board_id);
+	goto out;
+found:
+	pr_debug("%s: Applying quirks for board_id=%s\n", __func__,
+			board_id);
+	ret = 0;
+	for (i = 0; of_property_read_u32_index(child,
+				"board-apply", i, &ph) == 0; i++) {
+
+		ret = of_quirk_apply_by_phandle(ph);
+		if (ret != 0)
+			break;
+	}
+	if (ret != 0) {
+		pr_err("%s: Failed to apply quirk at %pO\n", __func__, child);
+		goto out;
+	}
+
+	optnp = of_get_child_by_name(child, "options");
+	chosen = of_find_node_by_path("/chosen");
+	bootargs = NULL;
+	if (chosen) {
+		if (of_property_read_string(chosen, "bootargs", &bootargs))
+			bootargs = NULL;
+		of_node_put(chosen);
+	}
+	if (optnp && bootargs) {
+		/* iterate on properties */
+		for_each_property_of_node(optnp, prop) {
+			if (!strcmp(prop->name, "name"))
+				continue;
+
+			if (command_line_arg(bootargs, prop->name))
+				i = 0;
+			else
+				i = 1;
+			if (of_property_read_u32_index(optnp,
+						prop->name, i, &ph) != 0) {
+				pr_err("%s: Failed to get phandle at %pO/%s\n",
+						__func__, optnp, prop->name);
+				continue;
+			}
+			ret = of_quirk_apply_by_phandle(ph);
+			if (ret != 0)
+				break;
+		}
+	}
+
+out:
+	of_node_put(optnp);
+	of_node_put(child);
+	of_node_put(revnp);
+	of_node_put(np);
+}
+
+void __init am33xx_dt_quirk(void)
+{
+	/* Manually issue calls for each supported board variant */
+
+	/* the beaglebone is the one supported board for now */
+	beaglebone_dt_quirk();
+}
diff --git a/arch/arm/mach-omap2/am33xx-dt-quirks.h b/arch/arm/mach-omap2/am33xx-dt-quirks.h
new file mode 100644
index 0000000..8c7dbec
--- /dev/null
+++ b/arch/arm/mach-omap2/am33xx-dt-quirks.h
@@ -0,0 +1,10 @@
+#ifndef AM33XX_DT_QUIRKS_H
+#define AM33XX_DT_QUIRKS_H
+
+#if IS_ENABLED(OF_DYNAMIC)
+extern void __init am33xx_dt_quirk(void);
+#else
+#define am33xx_dt_quirk	NULL
+#endif
+
+#endif
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index b61c049..9922c61 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -177,6 +177,7 @@ DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
 	.init_time	= omap3_gptimer_timer_init,
 	.dt_compat	= am33xx_boards_compat,
 	.restart	= am33xx_restart,
+	.dt_quirk	= am33xx_dt_quirk,
 MACHINE_END
 #endif
 
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 64e44d6..6b4d6e0 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -155,6 +155,14 @@ static inline void am33xx_restart(enum reboot_mode mode, const char *cmd)
 }
 #endif
 
+#ifdef CONFIG_SOC_AM33XX
+void am33xx_dt_quirk(void);
+#else
+static inline void am33xx_dt_quirk(void)
+{
+}
+#endif
+
 #ifdef CONFIG_ARCH_OMAP3
 void omap3xxx_restart(enum reboot_mode mode, const char *cmd);
 #else
