@@ -489,6 +489,23 @@ def build_prop(path, name, v, t=None):
489489
490490 return t .build (v )
491491
492+ PHANDLE_PROPS = {
493+ 'AAPL,phandle' ,
494+ 'interrupt-parent' ,
495+ 'iommu-parent' ,
496+ 'dma-parent' ,
497+ 'hdcp-parent' ,
498+ 'external-power-provider' ,
499+
500+ 'atc-phy-parent' ,
501+ 'atc-phy' ,
502+ 'acio-parent' ,
503+
504+ 'dp2hdmi-gpio-parent' ,
505+ 'dock' ,
506+ 'audio' ,
507+ }
508+
492509class ADTNode :
493510 def __init__ (self , val = None , path = "/" , parent = None ):
494511 self ._children = []
@@ -642,13 +659,15 @@ def interrupt_cells(self):
642659 except KeyError :
643660 raise AttributeError ("#interrupt-cells" )
644661
645- def _fmt_prop (self , k , v ):
662+ def _fmt_prop (self , k , v , fmt_phandle = None ):
646663 t , is_template = self ._types .get (k , (None , False ))
647664 if is_template :
648665 return f"<< { v } >>"
649666 elif k == 'reg' and isinstance (v , ListContainer ) and all (isinstance (x , Container ) for x in v ):
650667 fmt_value = lambda n : f'{ n :#018x} ' if isinstance (n , int ) else ' ' .join (f'{ x :#010x} ' for x in n )
651668 return "\n " .join (["[" , * (f" (addr = { fmt_value (x .addr )} , size = { fmt_value (x .size )} )," for x in v ), "]" ])
669+ elif k in PHANDLE_PROPS :
670+ return fmt_phandle (v , self ) if fmt_phandle else f'@{ v !r} '
652671 elif isinstance (v , ListContainer ):
653672 vs = [self ._fmt_prop ((k , i ), x ) for i , x in enumerate (v )]
654673 if any (('\n ' in v ) for v in vs ) or (len (vs ) > 1 and max (map (len , vs )) > 20 ):
@@ -670,14 +689,15 @@ def _fmt_prop(self, k, v):
670689 b = arg .to_bytes (4 , "big" )
671690 is_ascii = all (0x20 <= c <= 0x7e for c in b )
672691 args .append (f"{ arg :#x} " if not is_ascii else f"'{ b .decode ('ascii' )} '" )
673- return f"{ v .phandle } :{ v .name } ({ ', ' .join (args )} )"
692+ phandle = fmt_phandle (v .phandle , self ) if fmt_phandle else f'@{ v !r} '
693+ return f"{ phandle } :{ repr (v .name )[1 :- 1 ]} ({ ', ' .join (args )} )"
674694 name .startswith ("function-" )
675695 elif isinstance (v , str ):
676696 return repr (v )
677697 else :
678698 return str (v )
679699
680- def __str__ (self , t = "" , sort_keys = False , sort_nodes = False ):
700+ def __str__ (self , t = "" , sort_keys = False , sort_nodes = False , fmt_phandle = None ):
681701 props = self ._properties .items ()
682702 if sort_keys :
683703 props = sorted (props )
@@ -686,9 +706,9 @@ def __str__(self, t="", sort_keys=False, sort_nodes=False):
686706 children = sorted (children , key = lambda n : n .name )
687707 return "\n " .join ([
688708 t + f"{ self .name } {{" ,
689- * (t + f" { repr (k )[1 :- 1 ]} = { self ._fmt_prop (k , v ).replace ('\n ' , '\n ' + t + ' ' )} " for k , v in props if k != "name" ),
709+ * (t + f" { repr (k )[1 :- 1 ]} = { self ._fmt_prop (k , v , fmt_phandle ).replace ('\n ' , '\n ' + t + ' ' )} " for k , v in props if k != "name" ),
690710 * (["" ] if self ._children else []),
691- * (i .__str__ (t + " " , sort_keys , sort_nodes ) for i in children ),
711+ * (i .__str__ (t + " " , sort_keys , sort_nodes , fmt_phandle ) for i in children ),
692712 t + "}"
693713 ])
694714
@@ -775,6 +795,22 @@ def walk_tree(self):
775795 for child in self :
776796 yield from child .walk_tree ()
777797
798+ def build_phandle_lookup (self , verify_continuity = False , last_phandle = 0 ):
799+ phandles = {}
800+ for node in self .walk_tree ():
801+ if 'AAPL,phandle' not in node ._properties :
802+ continue
803+ ph = node ._properties ['AAPL,phandle' ]
804+
805+ assert isinstance (ph , int ) and (ph not in phandles )
806+ phandles [ph ] = node
807+
808+ if verify_continuity :
809+ assert ph == last_phandle + 1
810+ last_phandle = ph
811+
812+ return phandles
813+
778814 def build_addr_lookup (self ):
779815 lookup = AddrLookup ()
780816 for node in self .walk_tree ():
@@ -833,7 +869,17 @@ def load_adt(data):
833869 adt_data = args .input .read_bytes ()
834870
835871 adt = load_adt (adt_data )
836- print (adt .__str__ (sort_keys = args .sort_keys , sort_nodes = args .sort_nodes ))
872+ phandles = adt .build_phandle_lookup (verify_continuity = True )
873+ # since we'll refer to nodes by their path, make sure paths are unique
874+ for node in adt .walk_tree ():
875+ assert '/' not in node .name
876+ assert len (set (n .name for n in node )) == len (node ._children )
877+ def fmt_phandle (ph , context ):
878+ if isinstance (ph , int ) and ph in phandles :
879+ ph = phandles [ph ]._path
880+ return f"@{ ph !r} "
881+
882+ print (adt .__str__ (sort_keys = args .sort_keys , sort_nodes = args .sort_nodes , fmt_phandle = fmt_phandle ))
837883 new_data = adt .build ()
838884 if args .output is not None :
839885 args .output .write_bytes (new_data )
0 commit comments