/
common_proc.tcl
2629 lines (2435 loc) · 84.7 KB
/
common_proc.tcl
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#
# (C) Copyright 2014-2015 Xilinx, Inc.
# Based on original code:
# (C) Copyright 2007-2014 Michal Simek
# (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd
#
# Michal SIMEK <monstr@monstr.eu>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# common procedures
#
# global variables
global def_string zynq_soc_dt_tree bus_clk_list pl_ps_irq1 pl_ps_irq0
set pl_ps_irq1 0
set pl_ps_irq0 0
set def_string "__def_none"
set zynq_soc_dt_tree "dummy.dtsi"
set bus_clk_list ""
global or_id
global or_cnt
set or_id 0
set or_cnt 0
proc get_clock_frequency {ip_handle portname} {
set clk ""
set clkhandle [get_pins -of_objects $ip_handle $portname]
if {[string compare -nocase $clkhandle ""] != 0} {
set clk [get_property CLK_FREQ $clkhandle ]
}
return $clk
}
proc set_drv_property args {
set drv_handle [lindex $args 0]
set conf_prop [lindex $args 1]
set value [lindex $args 2]
if {[llength $value] !=0} {
if {$value != "-1" && [llength $value] !=0} {
set type "hexint"
if {[llength $args] >= 4} {
set type [lindex $args 3]
if {[string equal -nocase $type "boolean"]} {
if {[expr $value < 1]} {
return 0
}
set value ""
}
}
# remove CONFIG. as add_new_property does not work with CONFIG.
regsub -all {^CONFIG.} $conf_prop {} conf_prop
hsi::utils::add_new_property $drv_handle $conf_prop $type $value
}
}
}
# set driver property based on IP property
proc set_drv_conf_prop args {
set drv_handle [lindex $args 0]
set pram [lindex $args 1]
set conf_prop [lindex $args 2]
set ip [get_cells -hier $drv_handle]
set value [get_property CONFIG.${pram} $ip]
if {[llength $value] !=0} {
regsub -all "MIO( |)" $value "" value
if {$value != "-1" && [llength $value] !=0} {
set type "hexint"
if {[llength $args] >= 4} {
set type [lindex $args 3]
if {[string equal -nocase $type "boolean"]} {
if {[expr $value < 1]} {
return 0
}
set value ""
}
}
regsub -all {^CONFIG.} $conf_prop {} conf_prop
hsi::utils::add_new_property $drv_handle $conf_prop $type $value
}
}
}
# set driver property based on other IP's property
proc add_cross_property args {
set src_handle [lindex $args 0]
set src_prams [lindex $args 1]
set dest_handle [lindex $args 2]
set dest_prop [lindex $args 3]
set ip [get_cells -hier $src_handle]
set ipname [get_property IP_NAME $ip]
foreach conf_prop $src_prams {
set value [get_property ${conf_prop} $ip]
if {$conf_prop == "CONFIG.processor_mode"} {
set value "true"
}
if {$ipname == "axi_ethernet"} {
set value [is_property_set $value]
}
if {[llength $value]} {
if {$value != "-1" && [llength $value] !=0} {
set type "hexint"
if {[llength $args] >= 5} {
set type [lindex $args 4]
}
if {[string equal -nocase $type "boolean"]} {
if {[expr $value < 1]} {
return 0
}
set value ""
}
if {[regexp "(int|hex).*" $type match]} {
regsub -all {"} $value "" value
}
set ipname [get_property IP_NAME [get_cells -hier $ip]]
if {[string match -nocase $ipname "axi_mcdma"] && [string match -nocase $dest_prop "xlnx,include-sg"] } {
set type "boolean"
set value ""
}
hsi::utils::add_new_property $dest_handle $dest_prop $type $value
return 0
}
}
}
}
# TODO: merge to add_cross_property by detecting if dest_node is dt node or driver
proc add_cross_property_to_dtnode args {
set src_handle [lindex $args 0]
set src_prams [lindex $args 1]
set dest_node [lindex $args 2]
set dest_prop [lindex $args 3]
set ip [get_cells -hier $src_handle]
foreach conf_prop $src_prams {
set value [get_property ${conf_prop} $ip]
if {[llength $value]} {
if {$value != "-1" && [llength $value] !=0} {
set type "hexint"
if {[llength $args] >= 5} {
set type [lindex $args 4]
}
if {[string equal -nocase $type "boolean"]} {
if {[expr $value < 1]} {
return 0
}
set value ""
}
if {[regexp "(int|hex).*" $type match]} {
regsub -all {"} $value "" value
}
hsi::utils::add_new_dts_param $dest_node $dest_prop $value $type
return 0
}
}
}
}
proc get_ip_property {drv_handle parameter} {
set ip [get_cells -hier $drv_handle]
return [get_property ${parameter} $ip]
}
proc is_it_in_pl {ip} {
# FIXME: This is a workaround to check if IP that's in PL however,
# this is not entirely correct, it is a hack and only works for
# IP_NAME that does not matches ps7_*
# better detection is required
# handles interrupt that coming from get_drivers only
if {[llength [get_drivers $ip]] < 1} {
return -1
}
set ip_type [get_property IP_NAME $ip]
if {![regexp "ps*" "$ip_type" match]} {
return 1
}
return -1
}
proc get_intr_id {drv_handle intr_port_name} {
set slave [get_cells -hier $drv_handle]
set intr_info ""
set proctype [get_property IP_NAME [get_cells -hier [get_sw_processor]]]
foreach pin ${intr_port_name} {
set intc [::hsi::utils::get_interrupt_parent $drv_handle $pin]
if {[string_is_empty $intc] == 1} {continue}
if {[string match -nocase $proctype "psu_cortexa53"] } {
set intc [get_property IP_NAME $intc]
if {[llength $intc] > 1} {
foreach intr_cntr $intc {
if { [::hsi::utils::is_ip_interrupting_current_proc $intr_cntr] } {
set intc $intr_cntr
}
}
}
}
if {[string match -nocase $proctype "psu_cortexa53"] } {
set intr_id [get_psu_interrupt_id $drv_handle $pin]
} else {
set intr_id [::hsi::utils::get_interrupt_id $drv_handle $pin]
}
if {[string match -nocase $intr_id "-1"]} {continue}
set intr_type [get_intr_type $intc $slave $pin]
if {[string match -nocase $intr_type "-1"]} {
continue
}
set cur_intr_info ""
if { [string match -nocase $proctype "ps7_cortexa9"] } {
if {[string match "[get_property IP_NAME $intc]" "ps7_scugic"] } {
if {$intr_id > 32} {
set intr_id [expr $intr_id - 32]
}
set cur_intr_info "0 $intr_id $intr_type"
}
} elseif {[string match -nocase $intc "psu_acpu_gic"]} {
set cur_intr_info "0 $intr_id $intr_type"
} else {
set cur_intr_info "$intr_id $intr_type"
}
if {[string_is_empty $intr_info]} {
set intr_info "$cur_intr_info"
} else {
append intr_info " " $cur_intr_info
}
}
if {[string_is_empty $intr_info]} {
set intr_info -1
}
return $intr_info
}
proc dtg_debug msg {
return
puts "# [lindex [info level -1] 0] #>> $msg"
}
proc dtg_warning msg {
puts "WARNING: $msg"
}
proc proc_called_by {} {
return
puts "# [lindex [info level -1] 0] #>> called by [lindex [info level -2] 0]"
}
proc Pop {varname {nth 0}} {
upvar $varname args
set r [lindex $args $nth]
set args [lreplace $args $nth $nth]
return $r
}
proc string_is_empty {input} {
if {[string compare -nocase $input ""] != 0} {
return 0
}
return 1
}
proc gen_dt_node_search_pattern args {
proc_called_by
# generates device tree node search pattern and return it
global def_string
foreach var {node_name node_label node_unit_addr} {
set ${var} ${def_string}
}
while {[string match -* [lindex $args 0]]} {
switch -glob -- [lindex $args 0] {
-n* {set node_name [Pop args 1]}
-l* {set node_label [Pop args 1]}
-u* {set node_unit_addr [Pop args 1]}
-- {Pop args ; break}
default {
error "gen_dt_node_search_pattern bad option - [lindex $args 0]"
}
}
Pop args
}
set pattern ""
# TODO: is these search patterns correct
# TODO: check if pattern in the list or not
if {![string equal -nocase ${node_label} ${def_string}] && \
![string equal -nocase ${node_name} ${def_string}] && \
![string equal -nocase ${node_unit_addr} ${def_string}]} {
lappend pattern "^${node_label}:${node_name}@${node_unit_addr}$"
lappend pattern "^${node_name}@${node_unit_addr}$"
}
if {![string equal -nocase ${node_label} ${def_string}] && \
![string equal -nocase ${node_name} ${def_string}]} {
lappend pattern "^${node_label}:${node_name}"
}
if {![string equal -nocase ${node_name} ${def_string}] && \
![string equal -nocase ${node_unit_addr} ${def_string}]} {
lappend pattern "^${node_name}@${node_unit_addr}$"
}
if {![string equal -nocase ${node_label} ${def_string}]} {
lappend pattern "^&${node_label}$"
lappend pattern "^${node_label}:"
}
return $pattern
}
proc set_cur_working_dts {{dts_file ""}} {
# set current working device tree
# return the tree object
proc_called_by
if {[string_is_empty ${dts_file}] == 1} {
return [current_dt_tree]
}
set dt_idx [lsearch [get_dt_trees] ${dts_file}]
if {$dt_idx >= 0} {
set dt_tree_obj [current_dt_tree [lindex [get_dt_trees] $dt_idx]]
} else {
set dt_tree_obj [create_dt_tree -dts_file $dts_file]
}
return $dt_tree_obj
}
proc get_baseaddr {slave_ip {no_prefix ""}} {
# only returns the first addr
set ip_mem_handle [lindex [hsi::utils::get_ip_mem_ranges [get_cells -hier $slave_ip]] 0]
if { [string_is_empty $ip_mem_handle] } {
return -1
}
set addr [string tolower [get_property BASE_VALUE $ip_mem_handle]]
if {![string_is_empty $no_prefix]} {
regsub -all {^0x} $addr {} addr
}
return $addr
}
proc get_highaddr {slave_ip {no_prefix ""}} {
set ip_mem_handle [lindex [hsi::utils::get_ip_mem_ranges [get_cells -hier $slave_ip]] 0]
set addr [string tolower [get_property HIGH_VALUE $ip_mem_handle]]
if {![string_is_empty $no_prefix]} {
regsub -all {^0x} $addr {} addr
}
return $addr
}
proc get_all_tree_nodes {dts_file} {
# Workaround for -hier not working with -of_objects
# get all the nodes presented in a dt_tree and return node list
proc_called_by
set cur_dts [current_dt_tree]
current_dt_tree $dts_file
set all_nodes [get_dt_nodes -hier]
current_dt_tree $cur_dts
return $all_nodes
}
proc check_node_in_dts {node_name dts_file_list} {
# check if the node is in the device-tree file
# return 1 if found
# return 0 if not found
proc_called_by
foreach tmp_dts_file ${dts_file_list} {
set dts_nodes [get_all_tree_nodes $tmp_dts_file]
# TODO: better detection here
foreach pattern ${node_name} {
foreach node ${dts_nodes} {
if {[regexp $pattern $node match]} {
dtg_debug "Node $node ($pattern) found in $tmp_dts_file"
return 1
}
}
}
}
return 0
}
proc get_node_object {lu_node {dts_files ""} {error_out "yes"}} {
# get the node object based on the args
# returns the dt node object
proc_called_by
if [string_is_empty $dts_files] {
set dts_files [get_dt_trees]
}
set cur_dts [current_dt_tree]
foreach dts_file ${dts_files} {
set dts_nodes [get_all_tree_nodes $dts_file]
foreach node ${dts_nodes} {
if {[regexp $lu_node $node match]} {
# workaround for -hier not working with -of_objects
current_dt_tree $dts_file
set node_obj [get_dt_nodes -hier $node]
current_dt_tree $cur_dts
return $node_obj
}
}
}
if {[string_is_empty $error_out]} {
return ""
} else {
error "Failed to find $lu_node node !!!"
}
}
proc update_dt_parent args {
# update device tree node's parent
# return the node name
proc_called_by
global def_string
set node [lindex $args 0]
set new_parent [lindex $args 1]
if {[llength $args] >= 3} {
set dts_file [lindex $args 2]
} else {
set dts_file [current_dt_tree]
}
set node [get_node_object $node $dts_file]
# Skip if node is a reference node (start with &) or amba
if {[regexp "^&.*" "$node" match] || [regexp "amba_apu" "$node" match] || [regexp "amba" "$node" match]} {
return $node
}
if {[string_is_empty $new_parent] || \
[string equal ${def_string} "$new_parent"]} {
return $node
}
# Currently the PARENT node must within the same dt tree
if {![check_node_in_dts $new_parent $dts_file]} {
error "Node '$node' is not in $dts_file tree"
}
set cur_parent [get_property PARENT $node]
# set new parent if required
if {![string equal -nocase ${cur_parent} ${new_parent}] && [string_is_empty ${new_parent}] == 0} {
dtg_debug "Update parent to $new_parent"
set_property PARENT "${new_parent}" $node
}
return $node
}
proc get_all_dt_labels {{dts_files ""}} {
# get all dt node labels
set cur_dts [current_dt_tree]
set labels ""
if [string_is_empty $dts_files] {
set dts_files [get_dt_trees]
}
foreach dts_file ${dts_files} {
set dts_nodes [get_all_tree_nodes $dts_file]
foreach node ${dts_nodes} {
set node_label [get_property "NODE_LABEL" $node]
if {[string_is_empty $node_label]} {
continue
}
lappend labels $node_label
}
}
current_dt_tree $cur_dts
return $labels
}
proc list_remove_element {cur_list elements} {
foreach e ${elements} {
set rm_idx [lsearch $cur_list $e]
set cur_list [lreplace $cur_list $rm_idx $rm_idx]
}
return $cur_list
}
proc update_system_dts_include {include_file} {
# where should we get master_dts data
set master_dts [get_property CONFIG.master_dts [get_os]]
set cur_dts [current_dt_tree]
set master_dts_obj [get_dt_trees ${master_dts}]
if {[string_is_empty $master_dts_obj] == 1} {
set master_dts_obj [set_cur_working_dts ${master_dts}]
}
if {[string equal ${include_file} ${master_dts_obj}]} {
return 0
}
set cur_inc_list [get_property INCLUDE_FILES $master_dts_obj]
set tmp_list [split $cur_inc_list ","]
if { [lsearch $tmp_list $include_file] < 0} {
if {[string_is_empty $cur_inc_list]} {
set cur_inc_list $include_file
} else {
append cur_inc_list "," $include_file
set field [split $cur_inc_list ","]
set cur_inc_list [lsort -decreasing $field]
set cur_inc_list [join $cur_inc_list ","]
}
set_property INCLUDE_FILES ${cur_inc_list} $master_dts_obj
}
# set dts version
set dts_ver [get_property DTS_VERSION $master_dts_obj]
if {[string_is_empty $dts_ver]} {
set_property DTS_VERSION "/dts-v1/" $master_dts_obj
}
set_cur_working_dts $cur_dts
}
proc set_drv_def_dts {drv_handle} {
# optional dts control by adding the following line in mdd file
# PARAMETER name = def_dts, default = ps.dtsi, type = string;
set default_dts [get_property CONFIG.def_dts $drv_handle]
set dt_overlay [get_property CONFIG.dt_overlay [get_os]]
if {[string_is_empty $default_dts]} {
if {[is_pl_ip $drv_handle]} {
set default_dts "pl.dtsi"
} else {
# PS IP, read pcw_dts property
set default_dts [get_property CONFIG.pcw_dts [get_os]]
}
}
set default_dts [set_cur_working_dts $default_dts]
if {[is_pl_ip $drv_handle] && $dt_overlay} {
set master_dts_obj [get_dt_trees ${default_dts}]
set_property DTS_VERSION "/dts-v1/;\n/plugin/" $master_dts_obj
set root_node [add_or_get_dt_node -n / -d ${default_dts}]
set fpga_node [add_or_get_dt_node -n "fragment@0" -d ${default_dts} -p ${root_node}]
set pl_file $default_dts
set targets "fpga_full"
hsi::utils::add_new_dts_param $fpga_node target "$targets" reference
set child_name "__overlay__"
set child_node [add_or_get_dt_node -l "overlay0" -n $child_name -p $fpga_node]
set proctype [get_property IP_NAME [get_cells -hier [get_sw_processor]]]
if {[string match -nocase $proctype "psu_cortexa53"]} {
hsi::utils::add_new_dts_param "${child_node}" "#address-cells" 2 int
hsi::utils::add_new_dts_param "${child_node}" "#size-cells" 2 int
} else {
hsi::utils::add_new_dts_param "${child_node}" "#address-cells" 1 int
hsi::utils::add_new_dts_param "${child_node}" "#size-cells" 1 int
}
hsi::utils::add_new_dts_param "${child_node}" "firmware-name" "design_1_wrapper.bit.bin" string
} else {
update_system_dts_include $default_dts
}
return $default_dts
}
proc dt_node_def_checking {node_label node_name node_ua node_obj} {
# check if the node_object has matching label, name and unit_address properties
global def_string
if {[string equal -nocase $node_label $def_string]} {
set node_label ""
}
if {[string equal -nocase $node_ua $def_string]} {
set node_ua ""
}
# ignore reference node as it does not have label and unit_addr
if {![regexp "^&.*" "$node_obj" match]} {
set old_label [get_property "NODE_LABEL" $node_obj]
set old_name [get_property "NODE_NAME" $node_obj]
set old_ua [get_property "UNIT_ADDRESS" $node_obj]
set config_prop [list_property -regexp $node_obj "CONFIG.*"]
if {[string_is_empty $old_ua]} {
return 1
}
if {![string equal -nocase -length [string length $node_label] $node_label $old_label] || \
![string equal -nocase $node_ua $old_ua] || \
![string equal -nocase -length [string length $node_name] $node_name $old_name]} {
if {[string compare -nocase $config_prop ""]} {
dtg_debug "dt_node_def_checking($node_obj): label: ${node_label} - ${old_label}, name: ${node_name} - ${old_name}, unit addr: ${node_ua} - ${old_ua}"
return 0
}
}
}
return 1
}
proc add_or_get_dt_node args {
# Creates the dt node or the parent node if required
# return dt node
proc_called_by
global def_string
foreach var {node_name node_label node_unit_addr parent_obj dts_file} {
set ${var} ${def_string}
}
set auto_ref 1
set auto_ref_parent 0
set force_create 0
while {[string match -* [lindex $args 0]]} {
switch -glob -- [lindex $args 0] {
-force {set force_create 1}
-disable_auto_ref {set auto_ref 0}
-auto_ref_parent {set auto_ref_parent 1}
-n* {set node_name [Pop args 1]}
-l* {set node_label [Pop args 1]}
-u* {set node_unit_addr [Pop args 1]}
-p* {set parent_obj [Pop args 1]}
-d* {set dts_file [Pop args 1]}
-- {Pop args ; break}
default {
error "add_or_get_dt_node bad option - [lindex $args 0]"
}
}
Pop args
}
# if no dts_file provided
if {[string equal -nocase ${dts_file} ${def_string}]} {
set dts_file [current_dt_tree]
}
# node_name sanity checking
if {[string equal -nocase ${node_name} ${def_string}]} {
error "Node name must be provided..."
}
# Generate unique label name to prevent issue caused by static dtsi
# better way of handling this issue is required
set label_list [get_all_dt_labels]
# TODO: This only handle label duplication once. if multiple IP has
# the same label, it will not work. Better handling required.
if {[lsearch $label_list $node_label] >= 0} {
set tmp_node [get_node_object ${node_label}]
# rename if the node default properties differs
if {[dt_node_def_checking $node_label $node_name $node_unit_addr $tmp_node] == 0} {
dtg_warning "label '$node_label' found in existing tree, rename to dtg_$node_label"
set node_label "dtg_${node_label}"
}
}
set search_pattern [gen_dt_node_search_pattern -n ${node_name} -l ${node_label} -u ${node_unit_addr}]
dtg_debug ""
dtg_debug "node_name: ${node_name}"
dtg_debug "node_label: ${node_label}"
dtg_debug "node_unit_addr: ${node_unit_addr}"
dtg_debug "search_pattern: ${search_pattern}"
dtg_debug "parent_obj: ${parent_obj}"
dtg_debug "dts_file: ${dts_file}"
# save the current working dt_tree first
set cur_working_dts [current_dt_tree]
# tree switch the target tree
set_cur_working_dts ${dts_file}
set parent_dts_file ${dts_file}
# Set correct parent object
# Check if the parent object in other dt_trees or not. If yes, update
# parent node with reference node (&parent_obj).
# Check if parent is / and see if it in the target dts file
# if not /, then check if parent is created (FIXME: is right???)
set tmp_dts_list [list_remove_element [get_dt_trees] ${dts_file}]
set node_in_dts [check_node_in_dts ${parent_obj} ${tmp_dts_list}]
if {${node_in_dts} == 1 && \
![string equal ${parent_obj} "/" ]} {
set parent_obj [get_node_object ${parent_obj} ${tmp_dts_list}]
set parent_label [get_property "NODE_LABEL" $parent_obj]
if {[string_is_empty $parent_label]} {
set parent_label [get_property "NODE_NAME" $parent_obj]
}
if {[string_is_empty $parent_label]} {
error "no parent node name/label"
}
if {[regexp "^&.*" "$parent_label" match]} {
set ref_node "${parent_label}"
} else {
set ref_node "&${parent_label}"
}
set parent_ref_in_dts [check_node_in_dts "${ref_node}" ${dts_file}]
if {${parent_ref_in_dts} != 1} {
if {$auto_ref_parent} {
set_cur_working_dts ${dts_file}
set parent_obj [create_dt_node -n "${ref_node}"]
}
} else {
set parent_obj [get_node_object ${ref_node} ${dts_file}]
}
}
# if dt node in the target dts file
# get the nodes in the current dts file
set dts_nodes [get_all_tree_nodes $dts_file]
foreach pattern ${search_pattern} {
foreach node ${dts_nodes} {
if {[regexp $pattern $node match]} {
if {[dt_node_def_checking $node_label $node_name $node_unit_addr $node] == 0} {
error "$pattern :: $node_label : $node_name @ $node_unit_addr, is differ to the node object $node"
}
set node [update_dt_parent ${node} ${parent_obj} ${dts_file}]
set_cur_working_dts ${cur_working_dts}
return $node
}
}
}
# clean up required
# special search pattern for name only node
set_cur_working_dts ${dts_file}
foreach pattern "^${node_name}$" {
foreach node ${dts_nodes} {
if {[regexp $pattern $node match]} {
set_cur_working_dts ${dts_file}
set node [update_dt_parent ${node} ${parent_obj} ${dts_file}]
set_cur_working_dts ${cur_working_dts}
return $node
}
}
}
# if dt node in other target dts files
# create a reference node if required
set found_node 0
set tmp_dts_list [list_remove_element [get_dt_trees] ${dts_file}]
foreach tmp_dts_file ${tmp_dts_list} {
set dts_nodes [get_all_tree_nodes $tmp_dts_file]
# TODO: better detection here
foreach pattern ${search_pattern} {
foreach node ${dts_nodes} {
if {[regexp $pattern $node match]} {
# create reference node
set found_node 1
set found_node_obj [get_node_object ${node} $tmp_dts_file]
break
}
}
}
}
if {$found_node == 1 && $force_create == 0} {
if {$auto_ref == 0} {
# return the object found on other dts files
set_cur_working_dts ${cur_working_dts}
return $found_node_obj
}
dtg_debug "INFO: Found node and create it as reference node &${node_label}"
if {[string equal -nocase ${node_label} ${def_string}]} {
error "Unable to create reference node as reference label is not provided"
}
set node [create_dt_node -n "&${node_label}"]
set_cur_working_dts ${cur_working_dts}
return $node
}
# Others - create the dt node
set cmd ""
if {![string equal -nocase ${node_name} ${def_string}]} {
set cmd "${cmd} -name ${node_name}"
}
if {![string equal -nocase ${node_label} ${def_string}]} {
set cmd "${cmd} -label ${node_label}"
}
if {![string equal -nocase ${node_unit_addr} ${def_string}]} {
set cmd "${cmd} -unit_addr ${node_unit_addr}"
}
if {![string equal -nocase ${parent_obj} ${def_string}] && \
![string_is_empty ${parent_obj}]} {
# temp solution for getting the right node object
#set cmd "${cmd} -objects \[get_node_object ${parent_obj} $dts_file\]"
#report_property [get_node_object ${parent_obj} $dts_file]
set cmd "${cmd} -objects \[get_node_object ${parent_obj} $parent_dts_file\]"
}
dtg_debug "create node command: create_dt_node ${cmd}"
# FIXME: create_dt_node fail detection here
set node [eval "create_dt_node ${cmd}"]
set_cur_working_dts ${cur_working_dts}
return $node
}
proc is_pl_ip {ip_inst} {
# check if the IP is a soft IP (not PS7)
# return 1 if it is soft ip
# return 0 if not
set ip_obj [get_cells -hier $ip_inst]
if {[llength [get_cells -hier $ip_inst]] < 1} {
return 0
}
set ip_name [get_property IP_NAME $ip_obj]
if {![regexp "ps._*" "$ip_name" match]} {
return 1
}
return 0
}
proc is_ps_ip {ip_inst} {
# check if the IP is a soft IP (not PS7)
# return 1 if it is soft ip
# return 0 if not
set ip_obj [get_cells -hier $ip_inst]
if {[llength [get_cells -hier $ip_inst]] < 1} {
return 0
}
set ip_name [get_property IP_NAME $ip_obj]
if {[regexp "ps._*" "$ip_name" match]} {
return 1
}
return 0
}
proc get_node_name {drv_handle} {
# FIXME: handle node that is not an ip
# what about it is a bus node
set ip [get_cells -hier $drv_handle]
# node that is not a ip
if {[string_is_empty $ip]} {
error "$drv_handle is not a valid IP"
}
set unit_addr [get_baseaddr ${ip}]
set dev_type [get_property CONFIG.dev_type $drv_handle]
if {[string_is_empty $dev_type] == 1} {
set dev_type $drv_handle
}
set dt_node [add_or_get_dt_node -n ${dev_type} -l ${drv_handle} -u ${unit_addr}]
return $dt_node
}
proc get_driver_conf_list {drv_handle} {
# Assuming the driver property starts with CONFIG.<xyz>
# Returns all the property name that should be add to the node
set dts_conf_list ""
# handle no CONFIG parameter
if {[catch {set rt [report_property -return_string -regexp $drv_handle "CONFIG\\..*"]} msg]} {
return ""
}
foreach line [split $rt "\n"] {
regsub -all {\s+} $line { } line
if {[regexp "CONFIG\\..*\\.dts(i|)" $line matched]} {
continue
}
if {[regexp "CONFIG\\..*" $line matched]} {
lappend dts_conf_list [lindex [split $line " "] 0]
}
}
# Remove config based properties
# currently it is not possible to different by type: Pending on HSI implementation
# this is currently hard coded to remove CONFIG.def_dts CONFIG.dev_type CONFIG.dtg.alias CONFIG.dtg.ip_params
set dts_conf_list [list_remove_element $dts_conf_list "CONFIG.def_dts CONFIG.dev_type CONFIG.dtg.alias CONFIG.dtg.ip_params"]
return $dts_conf_list
}
proc add_driver_prop {drv_handle dt_node prop} {
# driver property to DT node
set value [get_property ${prop} $drv_handle]
if {[string_is_empty ${prop}] != 0} {
return -1
}
regsub -all {CONFIG.} $prop {} prop
set conf_prop [lindex [get_comp_params ${prop} $drv_handle] 0 ]
if {[string_is_empty ${conf_prop}] == 0} {
set type [lindex [get_property CONFIG.TYPE $conf_prop] 0]
} else {
error "Unable to add the $prop property for $drv_handle due to missing valid type"
}
dtg_debug "${dt_node} - ${prop} - ${value} - ${type}"
# only boolean allows empty string
if {[string_is_empty ${value}] == 1 && ![regexp {boolean*} ${type} matched]} {
dtg_warning "Only boolean type can have empty value. Fail to add driver($drv_handle) property($prop) type($type) value($value)"
dtg_warning "Please add the property manually"
return 1
}
# TODO: sanity check is missing
hsi::utils::add_new_dts_param "${dt_node}" "${prop}" "${value}" "${type}"
}
proc create_dt_tree_from_dts_file {} {
global def_string dtsi_fname
set kernel_dtsi ""
set kernel_ver [get_property CONFIG.kernel_version [get_os]]
foreach i [get_sw_cores device_tree] {
set kernel_dtsi [file normalize "[get_property "REPOSITORY" $i]/data/kernel_dtsi/${kernel_ver}/${dtsi_fname}"]
if {[file exists $kernel_dtsi]} {
foreach file [glob [file normalize [file dirname ${kernel_dtsi}]/*]] {
# NOTE: ./ works only if we did not change our directory
file copy -force $file ./
}
break
}
}
if {![file exists $kernel_dtsi] || [string_is_empty $kernel_dtsi]} {
error "Unable to find the dts file $kernel_dtsi"
}
global zynq_soc_dt_tree
set default_dts [create_dt_tree -dts_file $zynq_soc_dt_tree]
set fp [open $kernel_dtsi r]
set file_data [read $fp]
set data [split $file_data "\n"]
set node_level -1
foreach line $data {
set node_start_regexp "\{(\\s+|\\s|)$"
set node_end_regexp "\}(\\s+|\\s|);(\\s+|\\s|)$"
if {[regexp $node_start_regexp $line matched]} {
regsub -all "\{| |\t" $line {} line
incr node_level
set cur_node [line_to_node $line $node_level $default_dts]
} elseif {[regexp $node_end_regexp $line matched]} {
set node_level [expr "$node_level - 1"]
}
# TODO (MAYBE): convert every property into dt node
set status_regexp "status(|\\s+)="
set value ""
if {[regexp $status_regexp $line matched]} {
regsub -all "\{| |\t|;|\"" $line {} line
set line_data [split $line "="]
set value [lindex $line_data 1]
hsi::utils::add_new_dts_param "${cur_node}" "status" $value string
}
set status_regexp "compatible(|\\s+)="
set value ""
if {[regexp $status_regexp $line matched]} {
regsub -all "\{| |\t|;|\"" $line {} line
set line_data [split $line "="]
set value [lindex $line_data 1]
hsi::utils::add_new_dts_param "${cur_node}" "compatible" $value stringlist
}
}
}
proc line_to_node {line node_level default_dts} {
# TODO: make dt_node_dict as global
global dt_node_dict
global def_string
regsub -all "\{| |\t" $line {} line
set parent_node $def_string
set node_label $def_string
set node_name $def_string
set node_unit_addr $def_string
set node_data [split $line ":"]
set node_data_size [llength $node_data]
if {$node_data_size == 2} {
set node_label [lindex $node_data 0]
set tmp_data [split [lindex $node_data 1] "@"]
set node_name [lindex $tmp_data 0]
if {[llength $tmp_data] >= 2} {
set node_unit_addr [lindex $tmp_data 1]
}
} elseif {$node_data_size == 1} {
set node_name [lindex $node_data 0]
} else {
error "invalid node found - $line"
}
if {$node_level > 0} {
set parent_node [dict get $dt_node_dict [expr $node_level - 1] parent_node]
}
set cur_node [add_or_get_dt_node -n ${node_name} -l ${node_label} -u ${node_unit_addr} -d ${default_dts} -p ${parent_node}]
dict set dt_node_dict $node_level parent_node $cur_node
return $cur_node
}
proc gen_ps7_mapping {} {
# TODO: check if it is target cpu is cortex a9
# TODO: remove def_ps7_mapping
set proctype [get_property IP_NAME [get_cells -hier [get_sw_processor]]]
set def_ps_mapping [dict create]
if {[string match -nocase $proctype "psu_cortexa53"]} {
dict set def_ps_mapping f9010000 label gic
dict set def_ps_mapping ff060000 label can0
dict set def_ps_mapping ff070000 label can1
dict set def_ps_mapping fd500000 label gdma0
dict set def_ps_mapping fd510000 label gdma1
dict set def_ps_mapping fd520000 label gdma2
dict set def_ps_mapping fd530000 label gdma3
dict set def_ps_mapping fd540000 label gdma4
dict set def_ps_mapping fd550000 label gdma5
dict set def_ps_mapping fd560000 label gdma6
dict set def_ps_mapping fd570000 label gdma7
dict set def_ps_mapping fd4b0000 label gpu
dict set def_ps_mapping ffa80000 label adma0
dict set def_ps_mapping ffa90000 label adma0
dict set def_ps_mapping ffaa0000 label adma2
dict set def_ps_mapping ffab0000 label adma3
dict set def_ps_mapping ffac0000 label adma4
dict set def_ps_mapping ffad0000 label adma5
dict set def_ps_mapping ffae0000 label adma6
dict set def_ps_mapping ffaf0000 label adma7
dict set def_ps_mapping ff100000 label nand0
dict set def_ps_mapping ff0b0000 label gem0
dict set def_ps_mapping ff0c0000 label gem1
dict set def_ps_mapping ff0d0000 label gem2