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