aboutsummaryrefslogtreecommitdiffstats
path: root/check-sort-order.py
blob: 5cbbd74c4548a19b5b58de42242e481d9821847d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/python

import pyparsing as pp, sys
from lib import devicetree

topmost_nodes = [
        'aliases', 'chosen', 'firmware', 'reserved-memory', 'memory'
    ]

def dump_node(node, indent = 0):
    prefix = ' ' * indent
    print('%snode: %s' % (prefix, node))

    for prop in node.properties:
        print('%s  property: %s' % (prefix, prop))

    for child in node.children:
        dump_node(child, indent + 2)

def check_duplicate(filename, node, indent = 0):
    for child in node.children:
        for sibling in node.children:
            if child == sibling:
                continue

            if child.name == sibling.name:
                if child.unit_address and sibling.unit_address and \
                   child.unit_address == sibling.unit_address:
                    print('ERROR: duplicate node: %s == %s' % (child, sibling))

                if child.unit_address is None and sibling.unit_address is None:
                    print('ERROR: duplicate node: %s == %s' % (child, sibling))

def check_node(filename, node, indent = 0):
    #prefix = ' ' * indent
    #print('%s%s' % (prefix, node))
    prev = None

    # thermal zones are ordered by zone ID
    if node.name == 'thermal-zones':
        return

    # PMIC regulators are ordered by importance
    if node.name == 'regulators':
        return

    # pinmux definitions are ordered (if at all) by pin offset
    if node.name == 'pinmux' and node.parent:
        if node.parent.name == 'pinmux' and node.parent.unit_address:
            return

    for child in node.children:
        # make sure aliases, chosen, firmware, reserved-memory and memory nodes are at the top
        if child.name in topmost_nodes:
            if prev and prev.name not in topmost_nodes:
                print('ERROR: %s: %s must appear before any other nodes (%s)' % (filename, child, prev))

            continue

        # pad controller pad and port definitions are sorted by type, not alphabetically
        if node.name == 'padctl':
            if child.name in [ 'pads', 'ports' ]:
                continue

        if node.name in [ 'pads', 'ports' ]:
            continue

        # regulator nodes are ordered by importance
        if child.name.startswith('regulator-'):
            continue

        # i2c-bus nodes are typically last
        if child.name == 'i2c-bus':
            continue

        # XXX operating-points are sorted numerically
        if child.name.startswith('opp-') or child.name.startswith('timing-'):
            continue

        if prev is not None:
            if child.unit_address is None:
                if prev.unit_address is None:
                    if child.name < prev.name:
                        print('ERROR: %s: %s < %s' % (filename, child, prev))
            else:
                if prev.unit_address is not None:
                    if child.unit_address < prev.unit_address:
                        if prev.name == 'memory' and prev.unit_address == 0x80000000:
                            if False:
                                print('WARNING: %s: %s < %s' % (filename, child, prev))
                        else:
                            print('ERROR: %s: %s < %s' % (filename, child, prev))
                else:
                    if prev.name not in [ 'aliases', 'chosen', 'firmware', 'reserved-memory' ]:
                        print('ERROR: %s: %s < %s' % (filename, child, prev))

        prev = child

    for child in node.children:
        check_node(filename, child, indent + 2)

#dts = devicetree.compile(sys.argv[1])
#with open(sys.argv[1] + '.tmp', 'w') as fobj:
#    fobj.write(dts)

#with open(sys.argv[1], 'r') as fobj:
#    dts = fobj.read()

#print('DTS:')
#for no, line in enumerate(dts.splitlines(), start = 1):
#    print('%3d: %s' % (no, line))

try:
    for filename in sys.argv[1:]:
        print('parsing %s...' % filename)
        #ast = devicetree.DeviceTree.parseString(dts, parseAll = True)
        #ast = devicetree.DeviceTree.parseFile(filename, parseAll = True)
        ast = devicetree.load(filename)
        #ast.pprint()

        if False:
            for node in ast:
                if isinstance(node, devicetree.Node):
                    dump_node(node)

        if True:
            #print('checking %s...' % filename)

            for node in ast:
                if isinstance(node, devicetree.Node):
                    check_duplicate(filename, node)
                    check_node(filename, node)

except pp.ParseException as e:
    print(e.line)
    print(' ' * (e.column - 1) + '^')
    print(e)