1# SPDX-License-Identifier: GPL-2.0+
2# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
5# Entry-type module for U-Boot device tree with the microcode removed
6#
7
8from binman.entry import Entry
9from binman.etype.blob_dtb import Entry_blob_dtb
10from patman import tools
11
12class Entry_u_boot_dtb_with_ucode(Entry_blob_dtb):
13    """A U-Boot device tree file, with the microcode removed
14
15    Properties / Entry arguments:
16        - filename: Filename of u-boot.dtb (default 'u-boot.dtb')
17
18    See Entry_u_boot_ucode for full details of the three entries involved in
19    this process. This entry provides the U-Boot device-tree file, which
20    contains the microcode. If the microcode is not being collated into one
21    place then the offset and size of the microcode is recorded by this entry,
22    for use by u-boot-with-ucode_ptr. If it is being collated, then this
23    entry deletes the microcode from the device tree (to save space) and makes
24    it available to u-boot-ucode.
25    """
26    def __init__(self, section, etype, node):
27        # Put this here to allow entry-docs and help to work without libfdt
28        global state
29        from binman import state
30
31        super().__init__(section, etype, node)
32        self.ucode_data = b''
33        self.collate = False
34        self.ucode_offset = None
35        self.ucode_size = None
36        self.ucode = None
37        self.ready = False
38
39    def GetDefaultFilename(self):
40        return 'u-boot.dtb'
41
42    def GetFdtEtype(self):
43        return 'u-boot-dtb'
44
45    def ProcessFdt(self, fdt):
46        # So the module can be loaded without it
47        from dtoc import fdt
48
49        # If the section does not need microcode, there is nothing to do
50        ucode_dest_entry = self.section.FindEntryType(
51            'u-boot-spl-with-ucode-ptr')
52        if not ucode_dest_entry or not ucode_dest_entry.target_offset:
53            ucode_dest_entry = self.section.FindEntryType(
54                'u-boot-tpl-with-ucode-ptr')
55        if not ucode_dest_entry or not ucode_dest_entry.target_offset:
56            ucode_dest_entry = self.section.FindEntryType(
57                'u-boot-with-ucode-ptr')
58        if not ucode_dest_entry or not ucode_dest_entry.target_offset:
59            return True
60
61        # Remove the microcode
62        etype = self.GetFdtEtype()
63        fdt = state.GetFdtForEtype(etype)
64        self.ucode = fdt.GetNode('/microcode')
65        if not self.ucode:
66            raise self.Raise("No /microcode node found in '%s'" % etype)
67
68        # There's no need to collate it (move all microcode into one place)
69        # if we only have one chunk of microcode.
70        self.collate = len(self.ucode.subnodes) > 1
71        for node in self.ucode.subnodes:
72            data_prop = node.props.get('data')
73            if data_prop:
74                self.ucode_data += data_prop.bytes
75                if self.collate:
76                    node.DeleteProp('data')
77        return True
78
79    def ObtainContents(self):
80        # Call the base class just in case it does something important.
81        super().ObtainContents()
82        if self.ucode and not self.collate:
83            for node in self.ucode.subnodes:
84                data_prop = node.props.get('data')
85                if data_prop:
86                    # Find the offset in the device tree of the ucode data
87                    self.ucode_offset = data_prop.GetOffset() + 12
88                    self.ucode_size = len(data_prop.bytes)
89                    self.ready = True
90        else:
91            self.ready = True
92        return self.ready
93