diff --git a/tools/binman/README.entries b/tools/binman/README.entries
index 3afc560052a..4dd67d64fa7 100644
--- a/tools/binman/README.entries
+++ b/tools/binman/README.entries
@@ -462,6 +462,8 @@ both SPL and the device tree).
 Entry: u-boot-spl-with-ucode-ptr: U-Boot SPL with embedded microcode pointer
 ----------------------------------------------------------------------------
 
+This is used when SPL must set up the microcode for U-Boot.
+
 See Entry_u_boot_ucode for full details of the entries involved in this
 process.
 
@@ -503,6 +505,24 @@ to activate.
 
 
 
+Entry: u-boot-tpl-dtb-with-ucode: U-Boot TPL with embedded microcode pointer
+----------------------------------------------------------------------------
+
+This is used when TPL must set up the microcode for U-Boot.
+
+See Entry_u_boot_ucode for full details of the entries involved in this
+process.
+
+
+
+Entry: u-boot-tpl-with-ucode-ptr: U-Boot TPL with embedded microcode pointer
+----------------------------------------------------------------------------
+
+See Entry_u_boot_ucode for full details of the entries involved in this
+process.
+
+
+
 Entry: u-boot-ucode: U-Boot microcode block
 -------------------------------------------
 
diff --git a/tools/binman/etype/u_boot_dtb_with_ucode.py b/tools/binman/etype/u_boot_dtb_with_ucode.py
index 73f5fbf9033..444c51b8b72 100644
--- a/tools/binman/etype/u_boot_dtb_with_ucode.py
+++ b/tools/binman/etype/u_boot_dtb_with_ucode.py
@@ -43,6 +43,9 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob_dtb):
         # If the section does not need microcode, there is nothing to do
         ucode_dest_entry = self.section.FindEntryType(
             'u-boot-spl-with-ucode-ptr')
+        if not ucode_dest_entry or not ucode_dest_entry.target_offset:
+            ucode_dest_entry = self.section.FindEntryType(
+                'u-boot-tpl-with-ucode-ptr')
         if not ucode_dest_entry or not ucode_dest_entry.target_offset:
             ucode_dest_entry = self.section.FindEntryType(
                 'u-boot-with-ucode-ptr')
@@ -70,14 +73,14 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob_dtb):
     def ObtainContents(self):
         # Call the base class just in case it does something important.
         Entry_blob_dtb.ObtainContents(self)
-        self._pathname = state.GetFdtPath(self._filename)
-        self.ReadBlobContents()
-        if self.ucode:
+        if self.ucode and not self.collate:
             for node in self.ucode.subnodes:
                 data_prop = node.props.get('data')
-                if data_prop and not self.collate:
+                if data_prop:
                     # Find the offset in the device tree of the ucode data
                     self.ucode_offset = data_prop.GetOffset() + 12
                     self.ucode_size = len(data_prop.bytes)
-        self.ready = True
-        return True
+                    self.ready = True
+        else:
+            self.ready = True
+        return self.ready
diff --git a/tools/binman/etype/u_boot_spl_with_ucode_ptr.py b/tools/binman/etype/u_boot_spl_with_ucode_ptr.py
index 0dfe268a568..b650cf0146c 100644
--- a/tools/binman/etype/u_boot_spl_with_ucode_ptr.py
+++ b/tools/binman/etype/u_boot_spl_with_ucode_ptr.py
@@ -16,6 +16,8 @@ import tools
 class Entry_u_boot_spl_with_ucode_ptr(Entry_u_boot_with_ucode_ptr):
     """U-Boot SPL with embedded microcode pointer
 
+    This is used when SPL must set up the microcode for U-Boot.
+
     See Entry_u_boot_ucode for full details of the entries involved in this
     process.
     """
diff --git a/tools/binman/etype/u_boot_tpl_dtb_with_ucode.py b/tools/binman/etype/u_boot_tpl_dtb_with_ucode.py
new file mode 100644
index 00000000000..71e04fcd44f
--- /dev/null
+++ b/tools/binman/etype/u_boot_tpl_dtb_with_ucode.py
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for U-Boot device tree with the microcode removed
+#
+
+import control
+from entry import Entry
+from u_boot_dtb_with_ucode import Entry_u_boot_dtb_with_ucode
+import tools
+
+class Entry_u_boot_tpl_dtb_with_ucode(Entry_u_boot_dtb_with_ucode):
+    """U-Boot TPL with embedded microcode pointer
+
+    This is used when TPL must set up the microcode for U-Boot.
+
+    See Entry_u_boot_ucode for full details of the entries involved in this
+    process.
+    """
+    def __init__(self, section, etype, node):
+        Entry_u_boot_dtb_with_ucode.__init__(self, section, etype, node)
+
+    def GetDefaultFilename(self):
+        return 'tpl/u-boot-tpl.dtb'
diff --git a/tools/binman/etype/u_boot_tpl_with_ucode_ptr.py b/tools/binman/etype/u_boot_tpl_with_ucode_ptr.py
new file mode 100644
index 00000000000..8d94dded694
--- /dev/null
+++ b/tools/binman/etype/u_boot_tpl_with_ucode_ptr.py
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# Entry-type module for an TPL binary with an embedded microcode pointer
+#
+
+import struct
+
+import command
+from entry import Entry
+from blob import Entry_blob
+from u_boot_with_ucode_ptr import Entry_u_boot_with_ucode_ptr
+import tools
+
+class Entry_u_boot_tpl_with_ucode_ptr(Entry_u_boot_with_ucode_ptr):
+    """U-Boot TPL with embedded microcode pointer
+
+    See Entry_u_boot_ucode for full details of the entries involved in this
+    process.
+    """
+    def __init__(self, section, etype, node):
+        Entry_u_boot_with_ucode_ptr.__init__(self, section, etype, node)
+        self.elf_fname = 'tpl/u-boot-tpl'
+
+    def GetDefaultFilename(self):
+        return 'tpl/u-boot-tpl-nodtb.bin'
diff --git a/tools/binman/etype/u_boot_ucode.py b/tools/binman/etype/u_boot_ucode.py
index 6acf94d8cbc..a00e530295b 100644
--- a/tools/binman/etype/u_boot_ucode.py
+++ b/tools/binman/etype/u_boot_ucode.py
@@ -62,19 +62,24 @@ class Entry_u_boot_ucode(Entry_blob):
 
     def ObtainContents(self):
         # If the section does not need microcode, there is nothing to do
-        ucode_dest_entry = self.section.FindEntryType('u-boot-with-ucode-ptr')
-        ucode_dest_entry_spl = self.section.FindEntryType(
-            'u-boot-spl-with-ucode-ptr')
-        if ((not ucode_dest_entry or not ucode_dest_entry.target_offset) and
-            (not ucode_dest_entry_spl or not ucode_dest_entry_spl.target_offset)):
+        found = False
+        for suffix in ['', '-spl', '-tpl']:
+            name = 'u-boot%s-with-ucode-ptr' % suffix
+            entry = self.section.FindEntryType(name)
+            if entry and entry.target_offset:
+                found = True
+        if not found:
             self.data = ''
             return True
-
         # Get the microcode from the device tree entry. If it is not available
         # yet, return False so we will be called later. If the section simply
         # doesn't exist, then we may as well return True, since we are going to
         # get an error anyway.
-        fdt_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
+        for suffix in ['', '-spl', '-tpl']:
+            name = 'u-boot%s-dtb-with-ucode' % suffix
+            fdt_entry = self.section.FindEntryType(name)
+            if fdt_entry:
+                break
         if not fdt_entry:
             return True
         if not fdt_entry.ready:
@@ -86,12 +91,9 @@ class Entry_u_boot_ucode(Entry_blob):
             return True
 
         # Write it out to a file
-        dtb_name = 'u-boot-ucode.bin'
-        fname = tools.GetOutputFilename(dtb_name)
-        with open(fname, 'wb') as fd:
-            fd.write(fdt_entry.ucode_data)
+        self._pathname = tools.GetOutputFilename('u-boot-ucode.bin')
+        tools.WriteFile(self._pathname, fdt_entry.ucode_data)
 
-        self._pathname = fname
         self.ReadBlobContents()
 
         return True
diff --git a/tools/binman/etype/u_boot_with_ucode_ptr.py b/tools/binman/etype/u_boot_with_ucode_ptr.py
index c850b59a1e1..01f3513e7d3 100644
--- a/tools/binman/etype/u_boot_with_ucode_ptr.py
+++ b/tools/binman/etype/u_boot_with_ucode_ptr.py
@@ -74,13 +74,16 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
 
         # Get the microcode, either from u-boot-ucode or u-boot-dtb-with-ucode.
         # If we have left the microcode in the device tree, then it will be
-        # in the former. If we extracted the microcode from the device tree
-        # and collated it in one place, it will be in the latter.
+        # in the latter. If we extracted the microcode from the device tree
+        # and collated it in one place, it will be in the former.
         if ucode_entry.size:
             offset, size = ucode_entry.offset, ucode_entry.size
         else:
             dtb_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
-            if not dtb_entry or not dtb_entry.ready:
+            if not dtb_entry:
+                dtb_entry = self.section.FindEntryType(
+                        'u-boot-tpl-dtb-with-ucode')
+            if not dtb_entry:
                 self.Raise('Cannot find microcode region u-boot-dtb-with-ucode')
             offset = dtb_entry.offset + dtb_entry.ucode_offset
             size = dtb_entry.ucode_size
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 6c86f4a742c..2a9eea2a499 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -45,6 +45,7 @@ X86_START16_SPL_DATA  = 'start16spl'
 X86_START16_TPL_DATA  = 'start16tpl'
 U_BOOT_NODTB_DATA     = 'nodtb with microcode pointer somewhere in here'
 U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
+U_BOOT_TPL_NODTB_DATA = 'tplnodtb with microcode pointer somewhere in here'
 FSP_DATA              = 'fsp'
 CMC_DATA              = 'cmc'
 VBT_DATA              = 'vbt'
@@ -104,6 +105,8 @@ class TestFunctional(unittest.TestCase):
         TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
         TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
                                       U_BOOT_SPL_NODTB_DATA)
+        TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
+                                      U_BOOT_TPL_NODTB_DATA)
         TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
         TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
         TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
@@ -1645,6 +1648,22 @@ class TestFunctional(unittest.TestCase):
         m.update(16 * 'a')
         self.assertEqual(m.digest(), ''.join(hash_node.value))
 
+    def testPackUBootTplMicrocode(self):
+        """Test that x86 microcode can be handled correctly in TPL
+
+        We expect to see the following in the image, in order:
+            u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
+                place
+            u-boot-tpl.dtb with the microcode removed
+            the microcode
+        """
+        with open(self.TestFile('u_boot_ucode_ptr')) as fd:
+            TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
+        first, pos_and_size = self._RunMicrocodeTest('93_x86_tpl_ucode.dts',
+                                                     U_BOOT_TPL_NODTB_DATA)
+        self.assertEqual('tplnodtb with microc' + pos_and_size +
+                         'ter somewhere in here', first)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/93_x86_tpl_ucode.dts b/tools/binman/test/93_x86_tpl_ucode.dts
new file mode 100644
index 00000000000..d7ed9fc66b8
--- /dev/null
+++ b/tools/binman/test/93_x86_tpl_ucode.dts
@@ -0,0 +1,29 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		sort-by-offset;
+		end-at-4gb;
+		size = <0x200>;
+		u-boot-tpl-with-ucode-ptr {
+		};
+
+		u-boot-tpl-dtb-with-ucode {
+		};
+
+		u-boot-ucode {
+		};
+	};
+
+	microcode {
+		update@0 {
+			data = <0x12345678 0x12345679>;
+		};
+		update@1 {
+			data = <0xabcd0000 0x78235609>;
+		};
+	};
+};
