blob: 474c74e4f9f5c85e861a4b1814c3ed5007e77d5a [file] [log] [blame]
Matt Spinler7d381e12016-09-27 14:27:24 -05001#!/usr/bin/env perl
2
3#Generates a BMC device tree syntax file from the machine
4#readable workbook.
5
6use strict;
Matt Spinler889343f2017-01-30 14:14:11 -06007use warnings;
Matt Spinler7d381e12016-09-27 14:27:24 -05008use XML::Simple;
9use mrw::Targets;
10use Getopt::Long;
Matt Spinler30b461c2016-10-10 16:50:07 -050011use YAML::Tiny qw(LoadFile);
12use Scalar::Util qw(looks_like_number);
Matt Spinler7d381e12016-09-27 14:27:24 -050013
Matt Spinler30b461c2016-10-10 16:50:07 -050014use constant {
15 VERSION => "/dts-v1/;",
16 ZERO_LENGTH_PROPERTY => "zero_length_property",
17 PRE_ROOT_INCLUDES => "pre-root-node",
18 ROOT_INCLUDES => "root-node",
19 POST_ROOT_INCLUDES => "post-root-node"
20};
Matt Spinler74909132016-10-07 13:52:19 -050021
Matt Spinler7d381e12016-09-27 14:27:24 -050022
23my $serverwizFile;
Matt Spinler30b461c2016-10-10 16:50:07 -050024my $configFile;
Matt Spinler7d381e12016-09-27 14:27:24 -050025my $outputFile;
26my $debug;
27
28GetOptions("x=s" => \$serverwizFile,
Matt Spinler30b461c2016-10-10 16:50:07 -050029 "y=s" => \$configFile,
Matt Spinler7d381e12016-09-27 14:27:24 -050030 "o=s" => \$outputFile,
31 "d" => \$debug)
32or printUsage();
33
Matt Spinler30b461c2016-10-10 16:50:07 -050034if ((not defined $serverwizFile) || (not defined $outputFile) ||
35 (not defined $configFile)) {
Matt Spinler7d381e12016-09-27 14:27:24 -050036 printUsage();
37}
38
Matt Spinler30b461c2016-10-10 16:50:07 -050039my %g_configuration = %{ LoadFile($configFile) };
40
Matt Spinler7d381e12016-09-27 14:27:24 -050041my $g_targetObj = Targets->new;
42$g_targetObj->loadXML($serverwizFile);
43
Matt Spinler74909132016-10-07 13:52:19 -050044my ($g_bmc, $g_bmcModel, $g_bmcMfgr, $g_systemName);
45setGlobalAttributes();
Matt Spinler7d381e12016-09-27 14:27:24 -050046
Matt Spinler30b461c2016-10-10 16:50:07 -050047my $g_i2cBusAdjust = 0;
48getI2CBusAdjust();
Matt Spinler7d381e12016-09-27 14:27:24 -050049
50open (my $f, ">$outputFile") or die "Could not open $outputFile\n";
51
52printVersion($f);
Matt Spinler30b461c2016-10-10 16:50:07 -050053printIncludes($f, PRE_ROOT_INCLUDES);
Matt Spinler7d381e12016-09-27 14:27:24 -050054printRootNodeStart($f);
55
56printPropertyList($f, 1, "model", getSystemBMCModel());
Matt Spinler7d381e12016-09-27 14:27:24 -050057printPropertyList($f, 1, "compatible", getBMCCompatibles());
Matt Spinler995f2a22016-09-30 13:07:31 -050058
Matt Spinler23d47c22016-10-04 12:31:21 -050059printNode($f, 1, "aliases", getAliases());
Matt Spinler7d381e12016-09-27 14:27:24 -050060printNode($f, 1, "chosen", getChosen());
Matt Spinler30b461c2016-10-10 16:50:07 -050061printNode($f, 1, "memory", getBmcMemory());
Matt Spinler7d381e12016-09-27 14:27:24 -050062
Matt Spinler995f2a22016-09-30 13:07:31 -050063printNode($f, 1, "leds", getLEDNode());
64
Matt Spinler30b461c2016-10-10 16:50:07 -050065printIncludes($f, ROOT_INCLUDES);
66
Matt Spinler7d381e12016-09-27 14:27:24 -050067printRootNodeEnd($f, 0);
68
Matt Spinler96f8f242016-11-28 16:26:57 -060069printNodes($f, 0, getBMCFlashNodes());
70
71printNodes($f, 0, getOtherFlashNodes());
72
Matt Spinler74909132016-10-07 13:52:19 -050073printNodes($f, 0, getI2CNodes());
Matt Spinler7d381e12016-09-27 14:27:24 -050074printNodes($f, 0, getMacNodes());
Matt Spinler995f2a22016-09-30 13:07:31 -050075printNodes($f, 0, getUARTNodes());
Matt Spinler7d381e12016-09-27 14:27:24 -050076printNodes($f, 0, getVuartNodes());
77
Matt Spinler30b461c2016-10-10 16:50:07 -050078printIncludes($f, POST_ROOT_INCLUDES);
79
Matt Spinler7d381e12016-09-27 14:27:24 -050080close $f;
81exit 0;
82
83
Matt Spinler74909132016-10-07 13:52:19 -050084#Finds the values for these globals:
85# $g_bmc, $g_bmcModel, $g_bmcMfgr, $g_systemName
Matt Spinler889343f2017-01-30 14:14:11 -060086sub setGlobalAttributes
Matt Spinler74909132016-10-07 13:52:19 -050087{
88 $g_bmc = getBMCTarget();
89 if (length($g_bmc) == 0) {
90 die "Unable to find a BMC in this system\n";
91 }
92
93 if ($g_targetObj->isBadAttribute($g_bmc, "MODEL")) {
94 die "The MODEL attribute on $g_bmc is missing or empty.\n";
95 }
96 $g_bmcModel = $g_targetObj->getAttribute($g_bmc, "MODEL");
97
98 if ($g_targetObj->isBadAttribute($g_bmc, "MANUFACTURER")) {
99 die "The MANUFACTURER attribute on $g_bmc is missing or empty.\n";
100 }
101 $g_bmcMfgr = $g_targetObj->getAttribute($g_bmc, "MANUFACTURER");
102
103 $g_systemName = $g_targetObj->getSystemName();
104 if (length($g_systemName) == 0) {
105 die "The SYSTEM_NAME attribute is not set on the system target.\n";
106 }
107}
108
109
Matt Spinler23d47c22016-10-04 12:31:21 -0500110#Returns a hash that represents the 'aliases' node.
111#Will look like:
112# aliases {
113# name1 = &val1;
114# name2 = &val2;
115# ...
116# }
Matt Spinler889343f2017-01-30 14:14:11 -0600117sub getAliases
Matt Spinler23d47c22016-10-04 12:31:21 -0500118{
119 my %aliases;
Matt Spinler23d47c22016-10-04 12:31:21 -0500120
Matt Spinler30b461c2016-10-10 16:50:07 -0500121 #Get the info from the config file
Matt Spinler23d47c22016-10-04 12:31:21 -0500122
Matt Spinler30b461c2016-10-10 16:50:07 -0500123 if ((not exists $g_configuration{aliases}) ||
124 (keys %{$g_configuration{aliases}} == 0)) {
125 print "WARNING: Missing or empty 'aliases' section in config file.\n";
126 return %aliases;
127 }
128 %aliases = %{ $g_configuration{aliases} };
129
130 #add a & reference if one is missing
131 foreach my $a (keys %aliases) {
132 if (($aliases{$a} !~ /^&/) && ($aliases{$a} !~ /^\(ref\)/)) {
133 $aliases{$a} = "(ref)$aliases{$a}";
Matt Spinler23d47c22016-10-04 12:31:21 -0500134 }
135 }
136
137 return %aliases;
138}
139
Matt Spinler7d381e12016-09-27 14:27:24 -0500140
141#Return a hash that represents the 'chosen' node
Matt Spinler995f2a22016-09-30 13:07:31 -0500142#Will look like:
143# chosen {
144# stdout-path = ...
145# bootargs = ...
146# }
Matt Spinler889343f2017-01-30 14:14:11 -0600147sub getChosen
Matt Spinler7d381e12016-09-27 14:27:24 -0500148{
Matt Spinler7d381e12016-09-27 14:27:24 -0500149 my %chosen;
Matt Spinler30b461c2016-10-10 16:50:07 -0500150 my @allowed = qw(bootargs stdin-path stdout-path);
151
152 #Get the info from the config file
153
154 if (not exists $g_configuration{chosen}) {
155 die "ERROR: Missing 'chosen' section in config file.\n";
156 }
157 %chosen = %{ $g_configuration{chosen} };
158
159 #Check for allowed entries. Empty is OK.
160 foreach my $key (keys %chosen) {
161 my $found = 0;
162 foreach my $good (@allowed) {
163 if ($key eq $good) {
164 $found = 1;
165 }
166 }
167
168 if ($found == 0) {
169 die "Invalid entry $key in 'chosen' section in config file\n";
170 }
171 }
172
Matt Spinler7d381e12016-09-27 14:27:24 -0500173 return %chosen;
174}
175
176
Matt Spinler30b461c2016-10-10 16:50:07 -0500177#Return a hash that represents the 'memory' node.
Matt Spinler995f2a22016-09-30 13:07:31 -0500178#Will look like:
Matt Spinler30b461c2016-10-10 16:50:07 -0500179# memory {
180# reg = < base size >
181# }
Matt Spinler889343f2017-01-30 14:14:11 -0600182sub getBmcMemory
Matt Spinler30b461c2016-10-10 16:50:07 -0500183{
184 my %memory;
185
186 #Get the info from the config file
187
188 if (not exists $g_configuration{memory}) {
189 die "ERROR: Missing 'memory' section in config file.\n";
190 }
191
192 if ((not exists $g_configuration{memory}{base}) ||
193 ($g_configuration{memory}{base} !~ /0x/)) {
194 die "ERROR: The base entry in the memory section in the config " .
195 "file is either missing or invalid.\n";
196 }
197
198 if ((not exists $g_configuration{memory}{size}) ||
199 ($g_configuration{memory}{size} !~ /0x/)) {
200 die "ERROR: The size entry in the memory section in the config " .
201 "file is either missing or invalid.\n";
202 }
203
204 #Future: could do more validation on the actual values
205
206 $memory{reg} = "<$g_configuration{memory}{base} " .
207 "$g_configuration{memory}{size}>";
208
209 return %memory;
210}
211
212
Matt Spinler25d60bb2016-10-31 15:16:03 -0500213#Returns an array of hashes representing the device tree nodes for
214#the BMC flash. These nodes are BMC model specific because different
215#models can have different device drivers.
Matt Spinler889343f2017-01-30 14:14:11 -0600216sub getBMCFlashNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500217{
Matt Spinler25d60bb2016-10-31 15:16:03 -0500218 my @nodes;
219
220 if ($g_bmcModel eq "AST2500") {
221 my %node = getAST2500BMCSPIFlashNode();
222 push @nodes, { %node };
223 }
224 else {
225 die "ERROR: No BMC SPI flash support yet for BMC model $g_bmcModel\n";
226 }
227
228 return @nodes;
229}
230
231
232#Returns a hash that represents the BMC SPI flash(es) by finding the SPI
233#connections that come from the unit tagged as BMC_CODE. The code also
234#looks in the config file for any additional properties to add. Supports
235#the hardware where the same SPI master unit can be wired to more than 1
236#flash (a chip select line is used to switch between them.) This is
237#specific to the ASPEED AST2500 hardware and device driver.
238#Will look like:
239# fmc {
240# status = "okay"
241# flash@0 {
242# ...
243# };
244# flash@1 {
245# ...
246# };
Matt Spinler889343f2017-01-30 14:14:11 -0600247sub getAST2500BMCSPIFlashNode
Matt Spinler25d60bb2016-10-31 15:16:03 -0500248{
249 my %bmcFlash;
250 my $chipSelect = 0;
251 my $lastUnit = "";
252
Matt Spinler18d5f572016-11-15 15:25:45 -0600253 my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH");
Matt Spinler25d60bb2016-10-31 15:16:03 -0500254
255 if ($connections eq "") {
256 die "ERROR: No BMC SPI flashes found connected to the BMC\n";
257 }
258
259 $bmcFlash{fmc}{status} = "okay";
260
261 foreach my $spi (@{$connections->{CONN}}) {
262
263 #Looking for spi-masters with a function of 'BMC_CODE'.
264 #It's possible there are multiple flash chips here.
265 if (!$g_targetObj->isBadAttribute($spi->{SOURCE}, "SPI_FUNCTION")) {
266
267 my $function = $g_targetObj->getAttribute($spi->{SOURCE},
268 "SPI_FUNCTION");
269 if ($function eq "BMC_CODE") {
270
271 my $flashName = "flash@".$chipSelect;
272
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500273 $bmcFlash{fmc}{$flashName}{COMMENT} = connectionComment($spi);
Matt Spinler25d60bb2016-10-31 15:16:03 -0500274
275 $bmcFlash{fmc}{$flashName}{status} = "okay";
276
277 #Add in anything specified in the config file for this chip.
278 addBMCFlashConfigProperties(\%{$bmcFlash{fmc}{$flashName}},
279 $chipSelect);
280
281 #The code currently only supports the config where a chip
282 #select line is used to select between possibly multiple
283 #flash chips attached to the same SPI pins/unit. So we
284 #need to make sure if there are multiple chips found, that
285 #they are off of the same master unit.
286 if ($lastUnit eq "") {
287 $lastUnit = $spi->{SOURCE};
288 }
289 else {
290 if ($lastUnit ne $spi->{SOURCE}) {
291 die "ERROR: Currently only 1 spi-master unit is " .
292 "supported for BMC flash connections."
293 }
294 }
295
296 #Since we don't need anything chip select specific from the
297 #XML, we can just assign our own chip selects.
298 $chipSelect++;
299 }
300 }
301 }
302
303 if ($chipSelect == 0) {
304 die "ERROR: Didn't find any BMC flash chips connected";
305 }
306
307 return %bmcFlash;
308}
309
310
311#Looks in the bmc-flash-config section in the config file for the
312#chip select passed in to add any additional properties to the BMC
313#flash node.
314# $node = hash reference to the flash node
315# $cs = the flash chip select value
Matt Spinler889343f2017-01-30 14:14:11 -0600316sub addBMCFlashConfigProperties
Matt Spinler25d60bb2016-10-31 15:16:03 -0500317{
318 my ($node, $cs) = @_;
319 my $section = "chip-select-$cs";
320
321 if (exists $g_configuration{"bmc-flash-config"}{$section}) {
322 foreach my $key (sort keys $g_configuration{"bmc-flash-config"}{$section}) {
323 $node->{$key} = $g_configuration{"bmc-flash-config"}{$section}{$key};
324 }
325 }
Matt Spinler995f2a22016-09-30 13:07:31 -0500326}
327
328
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500329#Returns an array of hashes representing the other flashes used by the
330#BMC besides the ones that hold the BMC code. This is BMC model specific
331#as different models can have different interfaces.
332#Typically, these are SPI flashes.
Matt Spinler889343f2017-01-30 14:14:11 -0600333sub getOtherFlashNodes
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500334{
335 my @nodes;
336
337 if ($g_bmcModel eq "AST2500") {
338 @nodes = getAST2500SpiFlashNodes();
339 }
340 else {
341 die "ERROR: No SPI flash support yet for BMC model $g_bmcModel\n";
342 }
343
344 return @nodes;
345}
346
347
348#Returns an array of hashes representing the SPI flashes in an
349#AST2500. These are for the SPI1 and SPI2 interfaces in the chip.
350#Each SPI master interface can support multiple flash chips. If
351#no hardware is connected to the interface, the node won't be present.
Matt Spinler889343f2017-01-30 14:14:11 -0600352sub getAST2500SpiFlashNodes
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500353{
354 my @nodes;
355
356 #The AST2500 has 2 SPI master units, 1 and 2.
357 my @units = (1, 2);
358
359 foreach my $unit (@units) {
360
361 my %node = getAST2500SpiMasterNode($unit);
362
363 if (keys %node) {
364 my %spiNode;
365 my $nodeName = "spi$unit";
366 $spiNode{$nodeName} = { %node };
367 push @nodes, { %spiNode };
368 }
369 }
370
371 return @nodes;
372}
373
374
375#Returns a hash that represents the device tree node for the SPI1
376#or SPI2 master interface on the AST2500. Each master can support
377#multiple chips by use of a chip select.
378#Will look like:
379# spi1 {
380# status = "okay";
381# flash@0 {
382# ...
383# };
384# };
385#
386# $spiNum = The SPI master unit number to use
Matt Spinler889343f2017-01-30 14:14:11 -0600387sub getAST2500SpiMasterNode
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500388{
389 my $spiNum = shift;
390 my %spiMaster;
391 my $chipSelect = 0;
392
Matt Spinler18d5f572016-11-15 15:25:45 -0600393 my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH");
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500394
395 if ($connections eq "") {
396 return %spiMaster;
397 }
398
399 #Looking for spi-masters with a chip-unit of $spiNum
400 #It's possible there are multiple flash chips off the master
401 foreach my $spi (@{$connections->{CONN}}) {
402
403 my $unitNum = $g_targetObj->getAttribute($spi->{SOURCE},
404 "CHIP_UNIT");
405 if ($unitNum == $spiNum) {
406 $spiMaster{status} = "okay";
Matt Spinler2efdcba2016-11-08 15:37:20 -0600407
408 #Add in any pinctrl properties. These would come from the parent
409 #of $spi{SOURCE}, which would be a unit-pingroup-bmc if the
410 #pins for this connection are multi-function.
411 addPinCtrlProps($g_targetObj->getTargetParent($spi->{SOURCE}),
412 \%spiMaster);
413
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500414 my $flashName = "flash@".$chipSelect;
415
416 $spiMaster{$flashName}{COMMENT} = connectionComment($spi);
417
418 $spiMaster{$flashName}{status} = "okay";
419
Matt Spinler0eda4882016-11-30 15:20:11 -0600420 #AST2500 PNORs need a label
421 my $function = $g_targetObj->getAttribute($spi->{SOURCE},
422 "SPI_FUNCTION");
423 if ($function eq "PNOR") {
424 $spiMaster{$flashName}{label} = "pnor";
425 }
426
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500427 $chipSelect++;
428 }
429 }
430
431 return %spiMaster;
432}
433
434
Matt Spinler995f2a22016-09-30 13:07:31 -0500435#Returns a hash that represents the leds node by finding all of the
436#GPIO connections to LEDs.
437#Node will look like:
438# leds {
439# <ledname> {
440# gpios = &gpio ASPEED_GPIO(x, y) GPIO_ACTIVE_xxx>
441# };
442# <another ledname> {
443# ...
444# }
Matt Spinler889343f2017-01-30 14:14:11 -0600445sub getLEDNode
Matt Spinler995f2a22016-09-30 13:07:31 -0500446{
447 my %leds;
448
Matt Spinlereca7f062016-11-07 09:59:23 -0600449 $leds{compatible} = "gpio-leds";
Matt Spinler995f2a22016-09-30 13:07:31 -0500450
Matt Spinler18d5f572016-11-15 15:25:45 -0600451 my $connections = $g_targetObj->findConnections($g_bmc, "GPIO", "LED");
Matt Spinler995f2a22016-09-30 13:07:31 -0500452
453 if ($connections eq "") {
454 print "WARNING: No LEDs found connected to the BMC\n";
455 return %leds;
456 }
457
458 foreach my $gpio (@{$connections->{CONN}}) {
459 my %ledNode;
460
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500461 $ledNode{COMMENT} = connectionComment($gpio);
Matt Spinler995f2a22016-09-30 13:07:31 -0500462
463 #The node name will be the simplified LED name
464 my $name = $gpio->{DEST_PARENT};
465 $name =~ s/(-\d+$)//; #remove trailing position
466 $name =~ s/.*\///; #remove the front of the path
467
468 #For now only supports ASPEED.
469 if (uc($g_bmcMfgr) ne "ASPEED") {
470 die "ERROR: Unsupported BMC manufacturer $g_bmcMfgr\n";
471 }
472 my $num = $g_targetObj->getAttribute($gpio->{SOURCE}, "PIN_NUM");
473 my $macro = getAspeedGpioMacro($num);
474
475 #If it's active high or low
476 my $state = $g_targetObj->getAttribute($gpio->{DEST_PARENT}, "ON_STATE");
477 my $activeString = getGpioActiveString($state);
478
479 $ledNode{gpios} = "<&gpio $macro $activeString>";
480
481 $leds{$name} = { %ledNode };
482 }
483
484 return %leds;
485}
486
487
488#Returns a either GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW
489# $val = either a 1 or a 0 for active high or low
Matt Spinler889343f2017-01-30 14:14:11 -0600490sub getGpioActiveString
491{
Matt Spinler995f2a22016-09-30 13:07:31 -0500492 my $val = shift;
493
494 if ($val == 0) {
495 return "GPIO_ACTIVE_LOW";
496 }
497
498 return "GPIO_ACTIVE_HIGH";
499}
500
501
502#Turns a GPIO number into something like ASPEED_GPIO(A, 0) for the
503#ASPEED GPIO numbering scheme A[0-7] -> Z[0-7] and then starts at
504#AA[0-7] after that.
505# $num = the GPIO number
Matt Spinler889343f2017-01-30 14:14:11 -0600506sub getAspeedGpioMacro
507{
Matt Spinler995f2a22016-09-30 13:07:31 -0500508 my $num = shift;
509 my $char;
510 my $offset = $num % 8;
511 my $block = int($num / 8);
512
513 #If past Z, wraps to AA, AB, etc
514 if ((ord('A') + $block) > ord('Z')) {
515 #how far past Z?
516 $char = $block - (ord('Z') - ord('A'));
517
518 #Don't let it wrap twice
519 if ($char > (ord('Z') - ord('A') + 1)) {
520 die "ERROR: Invalid PIN_NUM value $num found for GPIO\n";
521 }
522
523 #start back at 'A' again, and convert to a character
524 $char = chr($char + ord('A') - 1);
525
526 #Add in a bonus 'A', to get something like AB
527 $char = "A".$char;
528 }
529 else {
530 $char = ord('A') + $block;
531 $char = chr($char);
532 }
533
534 return "ASPEED_GPIO($char, $offset)";
535}
536
537
538#Returns a list of hashes that represent the UART nodes on the BMC by
539#finding the UART connections.
540#Nodes will look like:
541# &uartX {
542# status = "okay"
543# }
Matt Spinler889343f2017-01-30 14:14:11 -0600544sub getUARTNodes
Matt Spinler995f2a22016-09-30 13:07:31 -0500545{
546 my @nodes;
547
Matt Spinler23d47c22016-10-04 12:31:21 -0500548 #Using U750 for legacy MRW reasons
Matt Spinler18d5f572016-11-15 15:25:45 -0600549 my $connections = $g_targetObj->findConnections($g_bmc, "U750");
Matt Spinler995f2a22016-09-30 13:07:31 -0500550
551 if ($connections eq "") {
552 print "WARNING: No UART buses found connected to the BMC\n";
553 return @nodes;
554 }
555
556 foreach my $uart (@{$connections->{CONN}}) {
557 my %node;
558
559 my $num = $g_targetObj->getAttribute($uart->{SOURCE}, "CHIP_UNIT");
560 my $name = "uart$num";
561
562 $node{$name}{status} = "okay";
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500563 $node{$name}{COMMENT} = connectionComment($uart);
Matt Spinler995f2a22016-09-30 13:07:31 -0500564
Matt Spinler2efdcba2016-11-08 15:37:20 -0600565 #Add in any pinctrl properties. These would come from the parent
566 #of $uart{SOURCE}, which would be a unit-pingroup-bmc if the
567 #pins for this connection are multi-function.
568 addPinCtrlProps($g_targetObj->getTargetParent($uart->{SOURCE}),
569 \%{$node{$name}});
570
Matt Spinler995f2a22016-09-30 13:07:31 -0500571 push @nodes, { %node };
572 }
573
Matt Spinler7d381e12016-09-27 14:27:24 -0500574 return @nodes;
575}
576
577
Matt Spinler995f2a22016-09-30 13:07:31 -0500578#Returns a list of hashes that represent the MAC (ethernet) nodes on the BMC
579#by finding the connections of type ETHERNET.
580#Nodes will look like:
581# &macX {
582# ...
583# }
Matt Spinler889343f2017-01-30 14:14:11 -0600584sub getMacNodes
Matt Spinler995f2a22016-09-30 13:07:31 -0500585{
586 my @nodes;
587
Matt Spinler18d5f572016-11-15 15:25:45 -0600588 my $connections = $g_targetObj->findConnections($g_bmc, "ETHERNET");
Matt Spinler995f2a22016-09-30 13:07:31 -0500589
590 if ($connections eq "") {
591 print "WARNING: No ethernet buses found connected to the BMC\n";
592 return @nodes;
593 }
594
595 foreach my $eth (@{$connections->{CONN}}) {
596 my %node;
597
598 my $num = $g_targetObj->getAttribute($eth->{SOURCE}, "CHIP_UNIT");
599 my $ncsi = $g_targetObj->getAttribute($eth->{SOURCE}, "NCSI_MODE");
600 my $hwChecksum = $g_targetObj->getAttribute($eth->{SOURCE},
601 "USE_HW_CHECKSUM");
602
603 my $name = "mac$num";
604 $node{$name}{status} = "okay";
605
606 if ($ncsi == 1) {
Matt Spinler74909132016-10-07 13:52:19 -0500607 $node{$name}{"use-ncsi"} = ZERO_LENGTH_PROPERTY;
Matt Spinler995f2a22016-09-30 13:07:31 -0500608 }
609 if ($hwChecksum == 0) {
Matt Spinler74909132016-10-07 13:52:19 -0500610 $node{$name}{"no-hw-checksum"} = ZERO_LENGTH_PROPERTY;
Matt Spinler995f2a22016-09-30 13:07:31 -0500611 }
612
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500613 $node{$name}{COMMENT} = connectionComment($eth);
Matt Spinler995f2a22016-09-30 13:07:31 -0500614
Matt Spinler2efdcba2016-11-08 15:37:20 -0600615 #Add in any pinctrl properties. These would come from the parent
616 #of $eth{SOURCE}, which would be a unit-pingroup-bmc if the
617 #pins for this connection are multi-function.
618 addPinCtrlProps($g_targetObj->getTargetParent($eth->{SOURCE}),
619 \%{$node{$name}});
620
Matt Spinler995f2a22016-09-30 13:07:31 -0500621 push @nodes, { %node };
622 }
623
624 return @nodes;
625}
626
627
628#Returns a list of hashes that represent the virtual UART nodes
629#Node will look like:
630# &vuart {
631# status = "okay"
632# }
Matt Spinler889343f2017-01-30 14:14:11 -0600633sub getVuartNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500634{
635 my @nodes;
636 my %node;
637
638 #For now, enable 1 node all the time.
Matt Spinler995f2a22016-09-30 13:07:31 -0500639 #TBD if this needs to be fixed
Matt Spinler7d381e12016-09-27 14:27:24 -0500640 $node{vuart}{status} = "okay";
641
642 push @nodes, { %node };
643
644 return @nodes;
645}
646
Matt Spinler74909132016-10-07 13:52:19 -0500647#Returns a list of hashes that represent the I2C device nodes.
648#There is 1 parent node for each bus, which then have subnodes
649#for each device on that bus. If a bus doesn't have any
650#attached devices, it doesn't need to show up.
651#The nodes will look like:
652# &i2c0 {
653# status = "okay"
654# device1@addr { (addr = 7 bit I2C address)
655# reg = <addr>
656# compatible = ...
657# ...
658# }
659# device2@addr {
660# reg = <addr>
661# ...
662# }
663# }
664# &i2c1 {
665# ...
666# }
Matt Spinler889343f2017-01-30 14:14:11 -0600667sub getI2CNodes
Matt Spinler74909132016-10-07 13:52:19 -0500668{
669 my @nodes;
670 my %busNodes;
671
Matt Spinler18d5f572016-11-15 15:25:45 -0600672 my $connections = $g_targetObj->findConnections($g_bmc, "I2C");
Matt Spinler74909132016-10-07 13:52:19 -0500673
674 if ($connections eq "") {
675 print "WARNING: No I2C buses found connected to the BMC\n";
676 return @nodes;
677 }
678
679 foreach my $i2c (@{$connections->{CONN}}) {
680
681 my %deviceNode, my $deviceName;
682
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500683 $deviceNode{COMMENT} = connectionComment($i2c);
Matt Spinler74909132016-10-07 13:52:19 -0500684
685 $deviceName = lc $i2c->{DEST_PARENT};
686 $deviceName =~ s/-\d+$//; #remove trailing position
687 $deviceName =~ s/.*\///; #remove the front of the path
688
689 #Get the I2C address
690 my $i2cAddress = $g_targetObj->getAttribute($i2c->{DEST}, "I2C_ADDRESS");
691 $i2cAddress = hex($i2cAddress);
692 if ($i2cAddress == 0) {
693 die "ERROR: Missing I2C address on $i2c->{DEST}\n";
694 }
695
696 #Put it in the format we want to print it in
697 $i2cAddress = adjustI2CAddress($i2cAddress);
698 $deviceNode{reg} = "<$i2cAddress>";
699
700 $deviceName = makeNodeName($deviceName, $deviceNode{reg});
701
702 #Get the I2C bus number
703 if ($g_targetObj->isBadAttribute($i2c->{SOURCE},
704 "I2C_PORT")) {
705 die "ERROR: I2C_PORT attribute in $i2c->{DEST_PARENT} " .
706 "is either missing or empty.\n";
707 }
708
709 my $busNum = $g_targetObj->getAttribute($i2c->{SOURCE}, "I2C_PORT");
710 if ($busNum =~ /0x/i) {
711 $busNum = hex($busNum);
712 }
713
714 #Convert the number to the Linux numbering scheme.
Matt Spinler30b461c2016-10-10 16:50:07 -0500715 $busNum += $g_i2cBusAdjust;
Matt Spinler74909132016-10-07 13:52:19 -0500716
717 #Get the compatible property
718 if ($g_targetObj->isBadAttribute($i2c->{DEST_PARENT},
719 "BMC_DT_COMPATIBLE")) {
720 die "ERROR: BMC_DT_COMPATIBLE attribute in $i2c->{DEST_PARENT} " .
721 "is either missing or empty.\n";
722 }
723
724 $deviceNode{compatible} = $g_targetObj->getAttribute(
725 $i2c->{DEST_PARENT},
726 "BMC_DT_COMPATIBLE");
727
728 #Get any other part specific properties, where the property
729 #names are actually defined in the XML.
730 my %props = getPartDefinedDTProperties($i2c->{DEST_PARENT});
731 foreach my $prop (sort keys %props) {
732 $deviceNode{$prop} = $props{$prop};
733 }
734
735 #busNodeName is the hash twice so when we loop
736 #below it doesn't get lost
737 my $busNodeName = "i2c$busNum";
738 $busNodes{$busNodeName}{$busNodeName}{status} = "okay";
739 $busNodes{$busNodeName}{$busNodeName}{$deviceName} = { %deviceNode };
Matt Spinler2efdcba2016-11-08 15:37:20 -0600740
741 #Add in any pinctrl properties. These would come from the parent
742 #of $i2c{SOURCE}, which would be a unit-pingroup-bmc if the
743 #pins for this connection are multi-function.
744 addPinCtrlProps($g_targetObj->getTargetParent($i2c->{SOURCE}),
745 \%{$busNodes{$busNodeName}{$busNodeName}});
Matt Spinler74909132016-10-07 13:52:19 -0500746 }
747
748 #Each bus gets its own hash entry in the array
749 for my $b (sort keys %busNodes) {
750 push @nodes, { %{$busNodes{$b}} };
751 }
752
753 return @nodes;
754}
755
756
757#Returns a hash of property names and values that should be stored in
758#the device tree node for this device. The names of the properties and
759#the attributes to find their values in are stored in the
760#BMC_DT_ATTR_NAMES attribute in the chip.
761# $chip = the chip target
Matt Spinler889343f2017-01-30 14:14:11 -0600762sub getPartDefinedDTProperties
Matt Spinler74909132016-10-07 13:52:19 -0500763{
764 my $chip = shift;
765 my %props;
766
767 if ($g_targetObj->isBadAttribute($chip, "BMC_DT_ATTR_NAMES")) {
768 return %props;
769 }
770
771 my $attr = $g_targetObj->getAttribute($chip, "BMC_DT_ATTR_NAMES");
772 $attr =~ s/\s//g;
773 my @names = split(',', $attr);
774
775 #There can be up to 4 entries in this attribute
776 for (my $i = 0; $i < scalar @names; $i += 2) {
777
778 #$names[$i] holds the name of the attribute.
779 #$names[$i+1] holds the name of the property to store its value in.
780 if (($names[$i] ne "NA") && ($names[$i] ne "")) {
781
782 my $val = $g_targetObj->getAttribute($chip, $names[$i]);
783
784 #if the value is empty, assume it's for a standalone property,
785 #which gets turned into: some-property;
786 if ($val eq "") {
787 $props{$names[$i+1]} = ZERO_LENGTH_PROPERTY;
788 }
789 else {
790 $props{$names[$i+1]} = "<$val>";
791 }
792 }
793 }
794
795 return %props;
796}
797
798
799#Convert the MRW I2C address into the format the dts needs
800# $addr = the I2C Address
Matt Spinler889343f2017-01-30 14:14:11 -0600801sub adjustI2CAddress
Matt Spinler74909132016-10-07 13:52:19 -0500802{
803 my $addr = shift;
804
805 #MRW holds the 8 bit value. We need the 7 bit one.
Matt Spinler96f8f242016-11-28 16:26:57 -0600806 $addr = $addr >> 1;
Matt Spinler74909132016-10-07 13:52:19 -0500807 $addr = sprintf("0x%X", $addr);
808 $addr = lc $addr;
809
810 return $addr;
811}
812
813
Matt Spinler30b461c2016-10-10 16:50:07 -0500814#Sets the global $g_i2cBusAdjust from the configuration file.
Matt Spinler889343f2017-01-30 14:14:11 -0600815sub getI2CBusAdjust
Matt Spinler74909132016-10-07 13:52:19 -0500816{
Matt Spinler30b461c2016-10-10 16:50:07 -0500817 if (exists $g_configuration{"i2c-bus-adjust"}) {
Matt Spinler74909132016-10-07 13:52:19 -0500818
Matt Spinler30b461c2016-10-10 16:50:07 -0500819 $g_i2cBusAdjust = $g_configuration{"i2c-bus-adjust"};
Matt Spinler74909132016-10-07 13:52:19 -0500820
Matt Spinler30b461c2016-10-10 16:50:07 -0500821 if (!looks_like_number($g_i2cBusAdjust)) {
822 die "ERROR: Invalid i2c-bus-adjust value $g_i2cBusAdjust " .
823 "found in config file.\n";
Matt Spinler7d381e12016-09-27 14:27:24 -0500824 }
825 }
Matt Spinler30b461c2016-10-10 16:50:07 -0500826 else {
827 $g_i2cBusAdjust = 0;
828 print "WARNING: No I2C Bus number adjustment done " .
829 "for this system.\n";
830 }
Matt Spinler7d381e12016-09-27 14:27:24 -0500831}
832
833
Matt Spinler2efdcba2016-11-08 15:37:20 -0600834
835#Adds two pinctrl properties to the device node hash passed in,
836#if specified in the MRW. Pin Control refers to a mechanism for
837#Linux to know which function of a multi-function pin to configure.
838#For example, a pin could either be configured to be a GPIO, or
839#an I2C clock line. The pin function depends on board wiring,
840#so is known by the MRW.
841# $target = the target to get the BMC_DT_PINCTRL_FUNCTS attribute from
842# $node = a hash reference to the device tree node to add the properties to
Matt Spinler889343f2017-01-30 14:14:11 -0600843sub addPinCtrlProps
Matt Spinler2efdcba2016-11-08 15:37:20 -0600844{
845 my ($target, $node) = @_;
846
847 if (!$g_targetObj->isBadAttribute($target, "BMC_DT_PINCTRL_FUNCS")) {
848 my $attr = $g_targetObj->getAttribute($target,
849 "BMC_DT_PINCTRL_FUNCS");
850
851 my $pinCtrl0Prop = makePinCtrl0PropValue($attr);
852 if ($pinCtrl0Prop ne "") {
853 $node->{"pinctrl-names"} = "default";
854 $node->{"pinctrl-0"} = $pinCtrl0Prop;
855 }
856 }
857}
858
859
860#Constructs the pinctrl-0 property value based on the
861#BMC_DT_PINCTRL_FUNCS attribute passed in.
862# $attr = BMC_DT_PINCTRL_FUNCS attribute value, which is an array
Matt Spinler889343f2017-01-30 14:14:11 -0600863sub makePinCtrl0PropValue
Matt Spinler2efdcba2016-11-08 15:37:20 -0600864{
865 my $attr = shift;
866 my @entries;
867 my $value = "";
868
869 $attr =~ s/\s//g;
870 my @funcs = split(',', $attr);
871 foreach my $func (@funcs) {
872 if (($func ne "NA") && ($func ne "")) {
873 push @entries, $func;
874 }
875 }
876
877 #<&pinctrl_funcA_default &pinctrl_funcB_default ...>
878 if (scalar @entries) {
879 $value = "<";
880 foreach my $entry (@entries) {
881 $value .= "&pinctrl_".$entry."_default ";
882 }
883 $value =~ s/\s$//; #Remove the trailing space
884 $value .= ">";
885 }
886
887 return $value;
888}
889
890
Matt Spinler7d381e12016-09-27 14:27:24 -0500891#Returns a list of compatible fields for the BMC itself.
Matt Spinler889343f2017-01-30 14:14:11 -0600892sub getBMCCompatibles
Matt Spinler7d381e12016-09-27 14:27:24 -0500893{
894 my @compats;
895
Matt Spinler23d47c22016-10-04 12:31:21 -0500896 #1st entry: <system mfgr>,<system name>-bmc
897 #2nd entry: <bmc mfgr>,<bmc model>
Matt Spinler7d381e12016-09-27 14:27:24 -0500898
Matt Spinler23d47c22016-10-04 12:31:21 -0500899 foreach my $target (sort keys %{ $g_targetObj->getAllTargets() }) {
900 if ($g_targetObj->getType($target) eq "SYS") {
901 my $mfgr = $g_targetObj->getAttribute($target, "MANUFACTURER");
902 push @compats, lc "$mfgr,$g_systemName-bmc";
903 last;
904 }
Matt Spinler7d381e12016-09-27 14:27:24 -0500905 }
906
907 push @compats, lc($g_bmcMfgr).",".lc($g_bmcModel);
908
909 return @compats;
910}
911
912
913#Returns a string for the system's BMC model property
Matt Spinler889343f2017-01-30 14:14:11 -0600914sub getSystemBMCModel
Matt Spinler7d381e12016-09-27 14:27:24 -0500915{
Matt Spinler995f2a22016-09-30 13:07:31 -0500916 #'<System> BMC'
Matt Spinler7d381e12016-09-27 14:27:24 -0500917 my $sys = lc $g_systemName;
918 $sys = uc(substr($sys, 0, 1)) . substr($sys, 1);
919
920 return $sys . " BMC";
921}
922
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500923#Create the comment that will show up in the device tree
924#for a connection. In the output, will look like:
925# // sourceUnit ->
926# // destChip
927#
928# $conn = The connection hash reference
Matt Spinler889343f2017-01-30 14:14:11 -0600929sub connectionComment
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500930{
931 my $conn = shift;
932 my $comment = "$conn->{SOURCE} ->\n$conn->{DEST_PARENT}";
933 return $comment;
934}
935
Matt Spinler7d381e12016-09-27 14:27:24 -0500936
937#Prints a list of nodes at the same indent level
938# $f = file handle
939# $level = indent level (0,1,etc)
940# @nodes = array of node hashes to print, where the
941# key for the hash is the name of the node
Matt Spinler889343f2017-01-30 14:14:11 -0600942sub printNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500943{
944 my ($f, $level, @nodes) = @_;
945
946 foreach my $n (@nodes) {
947 my %node = %$n;
948
949 foreach my $name (sort keys %node) {
950 my %n = %{ $node{$name} };
951 printNode($f, $level, $name, %n);
952 }
953 }
954}
955
956
957#Print a single node and its children
958# $f = file handle
959# $level = indent level (0,1,etc)
960# $name = the name of the node - shows up as:
961# name { ...
962# %vals = The contents of the node, with the following options:
963# if the key is:
964# - 'DTSI_INCLUDE', then value gets turned into a #include
Matt Spinler995f2a22016-09-30 13:07:31 -0500965# - 'COMMENT', then value gets turned into a // comment
Matt Spinler74909132016-10-07 13:52:19 -0500966# - 'ZERO_LENGTH_PROPERTY' then value gets turned into: value;
Matt Spinler7d381e12016-09-27 14:27:24 -0500967#
968# If the value is:
969# - a hash - then that hash gets turned into a child node
970# where the key is the name of the child node
Matt Spinler995f2a22016-09-30 13:07:31 -0500971# - an array of hashes indicates an array of child nodes
Matt Spinler889343f2017-01-30 14:14:11 -0600972sub printNode
Matt Spinler7d381e12016-09-27 14:27:24 -0500973{
974 my ($f, $level, $name, %vals) = @_;
975 my $include = "";
976
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500977 #No reason to print an empty node
978 if (!keys %vals) {
979 return;
980 }
981
Matt Spinler7d381e12016-09-27 14:27:24 -0500982 if ($level == 0) {
983 $name = "&".$name;
984 }
985
Matt Spinler995f2a22016-09-30 13:07:31 -0500986 print $f "\n";
987
988 if (exists $vals{COMMENT}) {
989 my @lines = split('\n', $vals{COMMENT});
990 foreach my $l (@lines) {
991 print $f indent($level) . "// $l\n";
992 }
993 }
994
995 print $f indent($level) . "$name {\n";
Matt Spinler7d381e12016-09-27 14:27:24 -0500996
Matt Spinler74909132016-10-07 13:52:19 -0500997 #First print properties, then includes, then subnodes
998
999 #Print Properties
Matt Spinler7d381e12016-09-27 14:27:24 -05001000 foreach my $v (sort keys %vals) {
1001
Matt Spinler995f2a22016-09-30 13:07:31 -05001002 next if ($v eq "COMMENT");
Matt Spinler74909132016-10-07 13:52:19 -05001003 next if ($v eq "DTSI_INCLUDE");
1004 next if (ref($vals{$v}) eq "HASH");
1005 next if (ref($vals{$v}) eq "ARRAY");
Matt Spinler995f2a22016-09-30 13:07:31 -05001006
Matt Spinler74909132016-10-07 13:52:19 -05001007 if ($vals{$v} ne ZERO_LENGTH_PROPERTY) {
1008 printProperty($f, $level+1, $v, $vals{$v});
Matt Spinler7d381e12016-09-27 14:27:24 -05001009 }
Matt Spinler74909132016-10-07 13:52:19 -05001010 else {
1011 printZeroLengthProperty($f, $level+1, $v);
1012 }
1013 }
1014
1015 #Print Includes
1016 foreach my $v (sort keys %vals) {
1017
1018 if ($v eq "DTSI_INCLUDE") {
1019 #print 1 include per line
1020 my @incs = split(',', $vals{$v});
1021 foreach my $i (@incs) {
1022 print $f qq(#include "$i";\n);
1023 }
1024 }
1025 }
1026
1027 #Print Nodes
1028 foreach my $v (sort keys %vals) {
1029
1030 if (ref($vals{$v}) eq "HASH") {
Matt Spinler7d381e12016-09-27 14:27:24 -05001031 printNode($f, $level+1, $v, %{$vals{$v}});
1032 }
Matt Spinler995f2a22016-09-30 13:07:31 -05001033 #An array of nested nodes
1034 elsif (ref($vals{$v}) eq "ARRAY") {
1035 my @array = @{$vals{$v}};
1036 &printNodes($f, $level+1, @array);
1037 }
Matt Spinler7d381e12016-09-27 14:27:24 -05001038 }
1039
1040 print $f indent($level) . "};\n";
1041}
1042
1043
1044#Prints a comma separated list of properties.
1045#e.g. a = "b, c, d";
1046# $f = file handle
1047# $level = indent level (0,1,etc)
1048# $name = name of property
1049# @vals = list of property values
Matt Spinler889343f2017-01-30 14:14:11 -06001050sub printPropertyList
Matt Spinler7d381e12016-09-27 14:27:24 -05001051{
1052 my ($f, $level, $name, @vals) = @_;
1053
1054 print $f indent($level) . "$name = ";
1055
1056 for (my $i = 0;$i < scalar @vals; $i++) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001057 print $f qq("$vals[$i]");
Matt Spinler7d381e12016-09-27 14:27:24 -05001058 if ($i < (scalar(@vals) - 1)) {
1059 print $f ", ";
1060 }
1061 }
1062 print $f ";\n"
1063}
1064
1065
1066#Prints a single property. e.g. a = "b";
1067# $f = file handle
1068# $level = indent level (0,1,etc)
1069# $name = name of property
1070# @vals = property values
Matt Spinler889343f2017-01-30 14:14:11 -06001071sub printProperty
Matt Spinler7d381e12016-09-27 14:27:24 -05001072{
1073 my ($f, $level, $name, $val) = @_;
Matt Spinler30b461c2016-10-10 16:50:07 -05001074 my $quoteChar = qq(");
Matt Spinler23d47c22016-10-04 12:31:21 -05001075
Matt Spinler30b461c2016-10-10 16:50:07 -05001076 $val = convertReference($val);
Matt Spinler23d47c22016-10-04 12:31:21 -05001077
1078 #properties with < > or single word aliases don't need quotes
1079 if (($val =~ /<.*>/) || ($val =~ /^&\w+$/)) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001080 $quoteChar = "";
Matt Spinler23d47c22016-10-04 12:31:21 -05001081 }
1082
Matt Spinler30b461c2016-10-10 16:50:07 -05001083 print $f indent($level) . "$name = $quoteChar$val$quoteChar;\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001084}
1085
1086
Matt Spinler30b461c2016-10-10 16:50:07 -05001087#Prints a zero length property e.g. some-property;
Matt Spinler7d381e12016-09-27 14:27:24 -05001088# $f = file handle
1089# $level = indent level (0,1,etc)
1090# $name = name of property
Matt Spinler889343f2017-01-30 14:14:11 -06001091sub printZeroLengthProperty
Matt Spinler7d381e12016-09-27 14:27:24 -05001092{
1093 my ($f, $level, $name) = @_;
1094 print $f indent($level) . "$name;\n";
1095}
1096
1097
Matt Spinler30b461c2016-10-10 16:50:07 -05001098#Replace '(ref)' with '&'.
Matt Spinler7d381e12016-09-27 14:27:24 -05001099#Needed because Serverwiz doesn't properly escape '&'s in the XML,
Matt Spinler30b461c2016-10-10 16:50:07 -05001100#so the '(ref)' string is used to represent the reference
Matt Spinler7d381e12016-09-27 14:27:24 -05001101#specifier instead of '&'.
Matt Spinler889343f2017-01-30 14:14:11 -06001102sub convertReference
1103{
Matt Spinler7d381e12016-09-27 14:27:24 -05001104 my $val = shift;
Matt Spinler30b461c2016-10-10 16:50:07 -05001105 $val =~ s/\(ref\)/&/g;
Matt Spinler7d381e12016-09-27 14:27:24 -05001106 return $val
1107}
1108
1109
1110#Returns the target for the BMC chip.
1111#Not worrying about multiple BMC systems for now.
1112sub getBMCTarget()
1113{
1114 foreach my $target (sort keys %{ $g_targetObj->getAllTargets() })
1115 {
1116 if ($g_targetObj->getType($target) eq "BMC") {
1117 return $target;
1118 }
1119 }
1120 return "";
1121}
1122
1123
1124#Prints the device tree version line.
1125# $f = file handle
Matt Spinler889343f2017-01-30 14:14:11 -06001126sub printVersion
Matt Spinler7d381e12016-09-27 14:27:24 -05001127{
1128 my $f = shift;
1129 print $f VERSION."\n"
1130}
1131
1132
1133#Prints the #include line for pulling in an include file.
Matt Spinler30b461c2016-10-10 16:50:07 -05001134#The files to include come from the configuration file.
Matt Spinler7d381e12016-09-27 14:27:24 -05001135# $f = file handle
Matt Spinler30b461c2016-10-10 16:50:07 -05001136# $type = include type
Matt Spinler889343f2017-01-30 14:14:11 -06001137sub printIncludes
Matt Spinler7d381e12016-09-27 14:27:24 -05001138{
Matt Spinler30b461c2016-10-10 16:50:07 -05001139 my ($f, $type) = @_;
1140 my @includes = getIncludes($type);
Matt Spinler7d381e12016-09-27 14:27:24 -05001141
1142 foreach my $i (@includes) {
1143 #if a .dtsi, gets " ", otherwise < >
1144 if ($i =~ /\.dtsi$/) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001145 $i = qq("$i");
Matt Spinler7d381e12016-09-27 14:27:24 -05001146 }
1147 else {
Matt Spinler30b461c2016-10-10 16:50:07 -05001148 $i = "<$i>";
Matt Spinler7d381e12016-09-27 14:27:24 -05001149 }
Matt Spinler30b461c2016-10-10 16:50:07 -05001150 print $f "#include $i\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001151 }
1152}
1153
1154
Matt Spinler30b461c2016-10-10 16:50:07 -05001155#Returns an array of include files found in the config file
1156#for the type specified.
1157# $type = the include type, which is the section name in the
1158# YAML configuration file.
Matt Spinler889343f2017-01-30 14:14:11 -06001159sub getIncludes
Matt Spinler7d381e12016-09-27 14:27:24 -05001160{
Matt Spinler30b461c2016-10-10 16:50:07 -05001161 my $type = shift;
Matt Spinler7d381e12016-09-27 14:27:24 -05001162 my @includes;
1163
Matt Spinler30b461c2016-10-10 16:50:07 -05001164 #The config file may have a section but no includes
1165 #listed in it, which is OK.
1166 if ((exists $g_configuration{includes}{$type}) &&
1167 (ref($g_configuration{includes}{$type}) eq "ARRAY")) {
Matt Spinler7d381e12016-09-27 14:27:24 -05001168
Matt Spinler30b461c2016-10-10 16:50:07 -05001169 @includes = @{$g_configuration{includes}{$type}};
Matt Spinler7d381e12016-09-27 14:27:24 -05001170 }
1171
1172 return @includes;
1173}
1174
Matt Spinler30b461c2016-10-10 16:50:07 -05001175
Matt Spinler74909132016-10-07 13:52:19 -05001176#Appends the first value of the 'reg' property
1177#passed in to the name passed in to create the
1178#full name for the node
1179# $name = node name that will be appended to
1180# $reg = the reg property values
Matt Spinler889343f2017-01-30 14:14:11 -06001181sub makeNodeName
Matt Spinler74909132016-10-07 13:52:19 -05001182{
1183 my ($name, $reg) = @_;
1184
1185 $reg =~ s/<//g;
1186 $reg =~ s/>//g;
1187 my @vals = split(' ', $reg);
1188
1189 if (scalar @vals > 0) {
1190 $vals[0] =~ s/0x//;
1191 $name .= "@" . lc $vals[0];
1192 }
1193
1194 return $name;
1195}
1196
Matt Spinler7d381e12016-09-27 14:27:24 -05001197
1198#Prints the root node starting bracket.
1199# $f = file handle
Matt Spinler889343f2017-01-30 14:14:11 -06001200sub printRootNodeStart
1201{
Matt Spinler7d381e12016-09-27 14:27:24 -05001202 my $f = shift;
Matt Spinler30b461c2016-10-10 16:50:07 -05001203 print $f qq(/ {\n);
Matt Spinler7d381e12016-09-27 14:27:24 -05001204}
1205
1206
1207#Prints the root node ending bracket.
1208# $f = file handle
1209# $level = indent level (0,1,etc)
Matt Spinler889343f2017-01-30 14:14:11 -06001210sub printRootNodeEnd
1211{
Matt Spinler7d381e12016-09-27 14:27:24 -05001212 my ($f, $level) = @_;
Matt Spinler30b461c2016-10-10 16:50:07 -05001213 print $f indent($level).qq(};\n);
Matt Spinler7d381e12016-09-27 14:27:24 -05001214}
1215
1216
1217#Returns a string that can be used to indent based on the
1218#level passed in. Each level is an additional 4 spaces.
1219# $level = indent level (0,1,etc)
Matt Spinler889343f2017-01-30 14:14:11 -06001220sub indent
1221{
Matt Spinler7d381e12016-09-27 14:27:24 -05001222 my $level = shift;
1223 return ' ' x ($level * 4);
1224}
1225
1226
Matt Spinler7d381e12016-09-27 14:27:24 -05001227sub printUsage
1228{
Matt Spinler30b461c2016-10-10 16:50:07 -05001229 print "gen_devtree.pl -x [XML filename] -y [yaml config file] " .
1230 "-o [output filename]\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001231 exit(1);
1232}