blob: 2eb36221eaebc6777277377afee72513e02a7846 [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
Matt Spinler30b461c2016-10-10 16:50:07 -0500159 foreach my $key (keys %chosen) {
Matt Spinler30b461c2016-10-10 16:50:07 -0500160
Matt Spinler28fb1a92017-01-30 12:54:10 -0600161 #Check for allowed entries. Empty is OK.
162 if (!grep(/^$key$/, @allowed)) {
Matt Spinler30b461c2016-10-10 16:50:07 -0500163 die "Invalid entry $key in 'chosen' section in config file\n";
164 }
Matt Spinler28fb1a92017-01-30 12:54:10 -0600165
166 #stdout-path and stdin-path can use aliases, which will look like
167 #(alias)uart5 in the yaml. Change to (ref)uart5 so it will be
168 #converted to a '&' later.
169 $chosen{$key} =~ s/\(alias\)/\(ref\)/g;
Matt Spinler30b461c2016-10-10 16:50:07 -0500170 }
171
Matt Spinler7d381e12016-09-27 14:27:24 -0500172 return %chosen;
173}
174
175
Matt Spinler30b461c2016-10-10 16:50:07 -0500176#Return a hash that represents the 'memory' node.
Matt Spinler995f2a22016-09-30 13:07:31 -0500177#Will look like:
Matt Spinler30b461c2016-10-10 16:50:07 -0500178# memory {
179# reg = < base size >
180# }
Matt Spinler889343f2017-01-30 14:14:11 -0600181sub getBmcMemory
Matt Spinler30b461c2016-10-10 16:50:07 -0500182{
183 my %memory;
184
185 #Get the info from the config file
186
187 if (not exists $g_configuration{memory}) {
188 die "ERROR: Missing 'memory' section in config file.\n";
189 }
190
191 if ((not exists $g_configuration{memory}{base}) ||
192 ($g_configuration{memory}{base} !~ /0x/)) {
193 die "ERROR: The base entry in the memory section in the config " .
194 "file is either missing or invalid.\n";
195 }
196
197 if ((not exists $g_configuration{memory}{size}) ||
198 ($g_configuration{memory}{size} !~ /0x/)) {
199 die "ERROR: The size entry in the memory section in the config " .
200 "file is either missing or invalid.\n";
201 }
202
203 #Future: could do more validation on the actual values
204
205 $memory{reg} = "<$g_configuration{memory}{base} " .
206 "$g_configuration{memory}{size}>";
207
208 return %memory;
209}
210
211
Matt Spinler25d60bb2016-10-31 15:16:03 -0500212#Returns an array of hashes representing the device tree nodes for
213#the BMC flash. These nodes are BMC model specific because different
214#models can have different device drivers.
Matt Spinler889343f2017-01-30 14:14:11 -0600215sub getBMCFlashNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500216{
Matt Spinler25d60bb2016-10-31 15:16:03 -0500217 my @nodes;
218
219 if ($g_bmcModel eq "AST2500") {
220 my %node = getAST2500BMCSPIFlashNode();
221 push @nodes, { %node };
222 }
223 else {
224 die "ERROR: No BMC SPI flash support yet for BMC model $g_bmcModel\n";
225 }
226
227 return @nodes;
228}
229
230
231#Returns a hash that represents the BMC SPI flash(es) by finding the SPI
232#connections that come from the unit tagged as BMC_CODE. The code also
233#looks in the config file for any additional properties to add. Supports
234#the hardware where the same SPI master unit can be wired to more than 1
235#flash (a chip select line is used to switch between them.) This is
236#specific to the ASPEED AST2500 hardware and device driver.
237#Will look like:
238# fmc {
239# status = "okay"
240# flash@0 {
241# ...
242# };
243# flash@1 {
244# ...
245# };
Matt Spinler889343f2017-01-30 14:14:11 -0600246sub getAST2500BMCSPIFlashNode
Matt Spinler25d60bb2016-10-31 15:16:03 -0500247{
248 my %bmcFlash;
249 my $chipSelect = 0;
250 my $lastUnit = "";
251
Matt Spinler18d5f572016-11-15 15:25:45 -0600252 my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH");
Matt Spinler25d60bb2016-10-31 15:16:03 -0500253
254 if ($connections eq "") {
255 die "ERROR: No BMC SPI flashes found connected to the BMC\n";
256 }
257
258 $bmcFlash{fmc}{status} = "okay";
259
260 foreach my $spi (@{$connections->{CONN}}) {
261
262 #Looking for spi-masters with a function of 'BMC_CODE'.
263 #It's possible there are multiple flash chips here.
264 if (!$g_targetObj->isBadAttribute($spi->{SOURCE}, "SPI_FUNCTION")) {
265
266 my $function = $g_targetObj->getAttribute($spi->{SOURCE},
267 "SPI_FUNCTION");
268 if ($function eq "BMC_CODE") {
269
270 my $flashName = "flash@".$chipSelect;
271
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500272 $bmcFlash{fmc}{$flashName}{COMMENT} = connectionComment($spi);
Matt Spinler25d60bb2016-10-31 15:16:03 -0500273
274 $bmcFlash{fmc}{$flashName}{status} = "okay";
275
276 #Add in anything specified in the config file for this chip.
277 addBMCFlashConfigProperties(\%{$bmcFlash{fmc}{$flashName}},
278 $chipSelect);
279
280 #The code currently only supports the config where a chip
281 #select line is used to select between possibly multiple
282 #flash chips attached to the same SPI pins/unit. So we
283 #need to make sure if there are multiple chips found, that
284 #they are off of the same master unit.
285 if ($lastUnit eq "") {
286 $lastUnit = $spi->{SOURCE};
287 }
288 else {
289 if ($lastUnit ne $spi->{SOURCE}) {
290 die "ERROR: Currently only 1 spi-master unit is " .
291 "supported for BMC flash connections."
292 }
293 }
294
295 #Since we don't need anything chip select specific from the
296 #XML, we can just assign our own chip selects.
297 $chipSelect++;
298 }
299 }
300 }
301
302 if ($chipSelect == 0) {
303 die "ERROR: Didn't find any BMC flash chips connected";
304 }
305
306 return %bmcFlash;
307}
308
309
310#Looks in the bmc-flash-config section in the config file for the
311#chip select passed in to add any additional properties to the BMC
312#flash node.
313# $node = hash reference to the flash node
314# $cs = the flash chip select value
Matt Spinler889343f2017-01-30 14:14:11 -0600315sub addBMCFlashConfigProperties
Matt Spinler25d60bb2016-10-31 15:16:03 -0500316{
317 my ($node, $cs) = @_;
318 my $section = "chip-select-$cs";
319
320 if (exists $g_configuration{"bmc-flash-config"}{$section}) {
321 foreach my $key (sort keys $g_configuration{"bmc-flash-config"}{$section}) {
322 $node->{$key} = $g_configuration{"bmc-flash-config"}{$section}{$key};
323 }
324 }
Matt Spinler995f2a22016-09-30 13:07:31 -0500325}
326
327
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500328#Returns an array of hashes representing the other flashes used by the
329#BMC besides the ones that hold the BMC code. This is BMC model specific
330#as different models can have different interfaces.
331#Typically, these are SPI flashes.
Matt Spinler889343f2017-01-30 14:14:11 -0600332sub getOtherFlashNodes
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500333{
334 my @nodes;
335
336 if ($g_bmcModel eq "AST2500") {
337 @nodes = getAST2500SpiFlashNodes();
338 }
339 else {
340 die "ERROR: No SPI flash support yet for BMC model $g_bmcModel\n";
341 }
342
343 return @nodes;
344}
345
346
347#Returns an array of hashes representing the SPI flashes in an
348#AST2500. These are for the SPI1 and SPI2 interfaces in the chip.
349#Each SPI master interface can support multiple flash chips. If
350#no hardware is connected to the interface, the node won't be present.
Matt Spinler889343f2017-01-30 14:14:11 -0600351sub getAST2500SpiFlashNodes
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500352{
353 my @nodes;
354
355 #The AST2500 has 2 SPI master units, 1 and 2.
356 my @units = (1, 2);
357
358 foreach my $unit (@units) {
359
360 my %node = getAST2500SpiMasterNode($unit);
361
362 if (keys %node) {
363 my %spiNode;
364 my $nodeName = "spi$unit";
365 $spiNode{$nodeName} = { %node };
366 push @nodes, { %spiNode };
367 }
368 }
369
370 return @nodes;
371}
372
373
374#Returns a hash that represents the device tree node for the SPI1
375#or SPI2 master interface on the AST2500. Each master can support
376#multiple chips by use of a chip select.
377#Will look like:
378# spi1 {
379# status = "okay";
380# flash@0 {
381# ...
382# };
383# };
384#
385# $spiNum = The SPI master unit number to use
Matt Spinler889343f2017-01-30 14:14:11 -0600386sub getAST2500SpiMasterNode
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500387{
388 my $spiNum = shift;
389 my %spiMaster;
390 my $chipSelect = 0;
391
Matt Spinler18d5f572016-11-15 15:25:45 -0600392 my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH");
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500393
394 if ($connections eq "") {
395 return %spiMaster;
396 }
397
398 #Looking for spi-masters with a chip-unit of $spiNum
399 #It's possible there are multiple flash chips off the master
400 foreach my $spi (@{$connections->{CONN}}) {
401
402 my $unitNum = $g_targetObj->getAttribute($spi->{SOURCE},
403 "CHIP_UNIT");
404 if ($unitNum == $spiNum) {
405 $spiMaster{status} = "okay";
Matt Spinler2efdcba2016-11-08 15:37:20 -0600406
407 #Add in any pinctrl properties. These would come from the parent
408 #of $spi{SOURCE}, which would be a unit-pingroup-bmc if the
409 #pins for this connection are multi-function.
410 addPinCtrlProps($g_targetObj->getTargetParent($spi->{SOURCE}),
411 \%spiMaster);
412
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500413 my $flashName = "flash@".$chipSelect;
414
415 $spiMaster{$flashName}{COMMENT} = connectionComment($spi);
416
417 $spiMaster{$flashName}{status} = "okay";
418
Matt Spinler0eda4882016-11-30 15:20:11 -0600419 #AST2500 PNORs need a label
420 my $function = $g_targetObj->getAttribute($spi->{SOURCE},
421 "SPI_FUNCTION");
422 if ($function eq "PNOR") {
423 $spiMaster{$flashName}{label} = "pnor";
424 }
425
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500426 $chipSelect++;
427 }
428 }
429
430 return %spiMaster;
431}
432
433
Matt Spinler995f2a22016-09-30 13:07:31 -0500434#Returns a hash that represents the leds node by finding all of the
435#GPIO connections to LEDs.
436#Node will look like:
437# leds {
438# <ledname> {
439# gpios = &gpio ASPEED_GPIO(x, y) GPIO_ACTIVE_xxx>
440# };
441# <another ledname> {
442# ...
443# }
Matt Spinler889343f2017-01-30 14:14:11 -0600444sub getLEDNode
Matt Spinler995f2a22016-09-30 13:07:31 -0500445{
446 my %leds;
447
Matt Spinlereca7f062016-11-07 09:59:23 -0600448 $leds{compatible} = "gpio-leds";
Matt Spinler995f2a22016-09-30 13:07:31 -0500449
Matt Spinler18d5f572016-11-15 15:25:45 -0600450 my $connections = $g_targetObj->findConnections($g_bmc, "GPIO", "LED");
Matt Spinler995f2a22016-09-30 13:07:31 -0500451
452 if ($connections eq "") {
453 print "WARNING: No LEDs found connected to the BMC\n";
454 return %leds;
455 }
456
457 foreach my $gpio (@{$connections->{CONN}}) {
458 my %ledNode;
459
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500460 $ledNode{COMMENT} = connectionComment($gpio);
Matt Spinler995f2a22016-09-30 13:07:31 -0500461
462 #The node name will be the simplified LED name
463 my $name = $gpio->{DEST_PARENT};
464 $name =~ s/(-\d+$)//; #remove trailing position
465 $name =~ s/.*\///; #remove the front of the path
466
467 #For now only supports ASPEED.
468 if (uc($g_bmcMfgr) ne "ASPEED") {
469 die "ERROR: Unsupported BMC manufacturer $g_bmcMfgr\n";
470 }
471 my $num = $g_targetObj->getAttribute($gpio->{SOURCE}, "PIN_NUM");
472 my $macro = getAspeedGpioMacro($num);
473
474 #If it's active high or low
475 my $state = $g_targetObj->getAttribute($gpio->{DEST_PARENT}, "ON_STATE");
476 my $activeString = getGpioActiveString($state);
477
478 $ledNode{gpios} = "<&gpio $macro $activeString>";
479
480 $leds{$name} = { %ledNode };
481 }
482
483 return %leds;
484}
485
486
487#Returns a either GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW
488# $val = either a 1 or a 0 for active high or low
Matt Spinler889343f2017-01-30 14:14:11 -0600489sub getGpioActiveString
490{
Matt Spinler995f2a22016-09-30 13:07:31 -0500491 my $val = shift;
492
493 if ($val == 0) {
494 return "GPIO_ACTIVE_LOW";
495 }
496
497 return "GPIO_ACTIVE_HIGH";
498}
499
500
501#Turns a GPIO number into something like ASPEED_GPIO(A, 0) for the
502#ASPEED GPIO numbering scheme A[0-7] -> Z[0-7] and then starts at
503#AA[0-7] after that.
504# $num = the GPIO number
Matt Spinler889343f2017-01-30 14:14:11 -0600505sub getAspeedGpioMacro
506{
Matt Spinler995f2a22016-09-30 13:07:31 -0500507 my $num = shift;
508 my $char;
509 my $offset = $num % 8;
510 my $block = int($num / 8);
511
512 #If past Z, wraps to AA, AB, etc
513 if ((ord('A') + $block) > ord('Z')) {
514 #how far past Z?
515 $char = $block - (ord('Z') - ord('A'));
516
517 #Don't let it wrap twice
518 if ($char > (ord('Z') - ord('A') + 1)) {
519 die "ERROR: Invalid PIN_NUM value $num found for GPIO\n";
520 }
521
522 #start back at 'A' again, and convert to a character
523 $char = chr($char + ord('A') - 1);
524
525 #Add in a bonus 'A', to get something like AB
526 $char = "A".$char;
527 }
528 else {
529 $char = ord('A') + $block;
530 $char = chr($char);
531 }
532
533 return "ASPEED_GPIO($char, $offset)";
534}
535
536
537#Returns a list of hashes that represent the UART nodes on the BMC by
538#finding the UART connections.
539#Nodes will look like:
540# &uartX {
541# status = "okay"
542# }
Matt Spinler889343f2017-01-30 14:14:11 -0600543sub getUARTNodes
Matt Spinler995f2a22016-09-30 13:07:31 -0500544{
545 my @nodes;
546
Matt Spinler23d47c22016-10-04 12:31:21 -0500547 #Using U750 for legacy MRW reasons
Matt Spinler18d5f572016-11-15 15:25:45 -0600548 my $connections = $g_targetObj->findConnections($g_bmc, "U750");
Matt Spinler995f2a22016-09-30 13:07:31 -0500549
550 if ($connections eq "") {
551 print "WARNING: No UART buses found connected to the BMC\n";
552 return @nodes;
553 }
554
555 foreach my $uart (@{$connections->{CONN}}) {
556 my %node;
557
558 my $num = $g_targetObj->getAttribute($uart->{SOURCE}, "CHIP_UNIT");
559 my $name = "uart$num";
560
561 $node{$name}{status} = "okay";
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500562 $node{$name}{COMMENT} = connectionComment($uart);
Matt Spinler995f2a22016-09-30 13:07:31 -0500563
Matt Spinler2efdcba2016-11-08 15:37:20 -0600564 #Add in any pinctrl properties. These would come from the parent
565 #of $uart{SOURCE}, which would be a unit-pingroup-bmc if the
566 #pins for this connection are multi-function.
567 addPinCtrlProps($g_targetObj->getTargetParent($uart->{SOURCE}),
568 \%{$node{$name}});
569
Matt Spinler995f2a22016-09-30 13:07:31 -0500570 push @nodes, { %node };
571 }
572
Matt Spinler7d381e12016-09-27 14:27:24 -0500573 return @nodes;
574}
575
576
Matt Spinler995f2a22016-09-30 13:07:31 -0500577#Returns a list of hashes that represent the MAC (ethernet) nodes on the BMC
578#by finding the connections of type ETHERNET.
579#Nodes will look like:
580# &macX {
581# ...
582# }
Matt Spinler889343f2017-01-30 14:14:11 -0600583sub getMacNodes
Matt Spinler995f2a22016-09-30 13:07:31 -0500584{
585 my @nodes;
586
Matt Spinler18d5f572016-11-15 15:25:45 -0600587 my $connections = $g_targetObj->findConnections($g_bmc, "ETHERNET");
Matt Spinler995f2a22016-09-30 13:07:31 -0500588
589 if ($connections eq "") {
590 print "WARNING: No ethernet buses found connected to the BMC\n";
591 return @nodes;
592 }
593
594 foreach my $eth (@{$connections->{CONN}}) {
595 my %node;
596
597 my $num = $g_targetObj->getAttribute($eth->{SOURCE}, "CHIP_UNIT");
598 my $ncsi = $g_targetObj->getAttribute($eth->{SOURCE}, "NCSI_MODE");
599 my $hwChecksum = $g_targetObj->getAttribute($eth->{SOURCE},
600 "USE_HW_CHECKSUM");
601
602 my $name = "mac$num";
603 $node{$name}{status} = "okay";
604
605 if ($ncsi == 1) {
Matt Spinler74909132016-10-07 13:52:19 -0500606 $node{$name}{"use-ncsi"} = ZERO_LENGTH_PROPERTY;
Matt Spinler995f2a22016-09-30 13:07:31 -0500607 }
608 if ($hwChecksum == 0) {
Matt Spinler74909132016-10-07 13:52:19 -0500609 $node{$name}{"no-hw-checksum"} = ZERO_LENGTH_PROPERTY;
Matt Spinler995f2a22016-09-30 13:07:31 -0500610 }
611
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500612 $node{$name}{COMMENT} = connectionComment($eth);
Matt Spinler995f2a22016-09-30 13:07:31 -0500613
Matt Spinler2efdcba2016-11-08 15:37:20 -0600614 #Add in any pinctrl properties. These would come from the parent
615 #of $eth{SOURCE}, which would be a unit-pingroup-bmc if the
616 #pins for this connection are multi-function.
617 addPinCtrlProps($g_targetObj->getTargetParent($eth->{SOURCE}),
618 \%{$node{$name}});
619
Matt Spinler995f2a22016-09-30 13:07:31 -0500620 push @nodes, { %node };
621 }
622
623 return @nodes;
624}
625
626
627#Returns a list of hashes that represent the virtual UART nodes
628#Node will look like:
629# &vuart {
630# status = "okay"
631# }
Matt Spinler889343f2017-01-30 14:14:11 -0600632sub getVuartNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500633{
634 my @nodes;
635 my %node;
636
637 #For now, enable 1 node all the time.
Matt Spinler995f2a22016-09-30 13:07:31 -0500638 #TBD if this needs to be fixed
Matt Spinler7d381e12016-09-27 14:27:24 -0500639 $node{vuart}{status} = "okay";
640
641 push @nodes, { %node };
642
643 return @nodes;
644}
645
Matt Spinler74909132016-10-07 13:52:19 -0500646#Returns a list of hashes that represent the I2C device nodes.
647#There is 1 parent node for each bus, which then have subnodes
648#for each device on that bus. If a bus doesn't have any
649#attached devices, it doesn't need to show up.
650#The nodes will look like:
651# &i2c0 {
652# status = "okay"
653# device1@addr { (addr = 7 bit I2C address)
654# reg = <addr>
655# compatible = ...
656# ...
657# }
658# device2@addr {
659# reg = <addr>
660# ...
661# }
662# }
663# &i2c1 {
664# ...
665# }
Matt Spinler889343f2017-01-30 14:14:11 -0600666sub getI2CNodes
Matt Spinler74909132016-10-07 13:52:19 -0500667{
668 my @nodes;
669 my %busNodes;
670
Matt Spinler18d5f572016-11-15 15:25:45 -0600671 my $connections = $g_targetObj->findConnections($g_bmc, "I2C");
Matt Spinler74909132016-10-07 13:52:19 -0500672
673 if ($connections eq "") {
674 print "WARNING: No I2C buses found connected to the BMC\n";
675 return @nodes;
676 }
677
678 foreach my $i2c (@{$connections->{CONN}}) {
679
680 my %deviceNode, my $deviceName;
681
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500682 $deviceNode{COMMENT} = connectionComment($i2c);
Matt Spinler74909132016-10-07 13:52:19 -0500683
684 $deviceName = lc $i2c->{DEST_PARENT};
685 $deviceName =~ s/-\d+$//; #remove trailing position
686 $deviceName =~ s/.*\///; #remove the front of the path
687
688 #Get the I2C address
689 my $i2cAddress = $g_targetObj->getAttribute($i2c->{DEST}, "I2C_ADDRESS");
690 $i2cAddress = hex($i2cAddress);
691 if ($i2cAddress == 0) {
692 die "ERROR: Missing I2C address on $i2c->{DEST}\n";
693 }
694
695 #Put it in the format we want to print it in
696 $i2cAddress = adjustI2CAddress($i2cAddress);
697 $deviceNode{reg} = "<$i2cAddress>";
698
699 $deviceName = makeNodeName($deviceName, $deviceNode{reg});
700
701 #Get the I2C bus number
702 if ($g_targetObj->isBadAttribute($i2c->{SOURCE},
703 "I2C_PORT")) {
704 die "ERROR: I2C_PORT attribute in $i2c->{DEST_PARENT} " .
705 "is either missing or empty.\n";
706 }
707
708 my $busNum = $g_targetObj->getAttribute($i2c->{SOURCE}, "I2C_PORT");
709 if ($busNum =~ /0x/i) {
710 $busNum = hex($busNum);
711 }
712
713 #Convert the number to the Linux numbering scheme.
Matt Spinler30b461c2016-10-10 16:50:07 -0500714 $busNum += $g_i2cBusAdjust;
Matt Spinler74909132016-10-07 13:52:19 -0500715
716 #Get the compatible property
717 if ($g_targetObj->isBadAttribute($i2c->{DEST_PARENT},
718 "BMC_DT_COMPATIBLE")) {
719 die "ERROR: BMC_DT_COMPATIBLE attribute in $i2c->{DEST_PARENT} " .
720 "is either missing or empty.\n";
721 }
722
723 $deviceNode{compatible} = $g_targetObj->getAttribute(
724 $i2c->{DEST_PARENT},
725 "BMC_DT_COMPATIBLE");
726
727 #Get any other part specific properties, where the property
728 #names are actually defined in the XML.
729 my %props = getPartDefinedDTProperties($i2c->{DEST_PARENT});
730 foreach my $prop (sort keys %props) {
731 $deviceNode{$prop} = $props{$prop};
732 }
733
734 #busNodeName is the hash twice so when we loop
735 #below it doesn't get lost
736 my $busNodeName = "i2c$busNum";
737 $busNodes{$busNodeName}{$busNodeName}{status} = "okay";
738 $busNodes{$busNodeName}{$busNodeName}{$deviceName} = { %deviceNode };
Matt Spinler2efdcba2016-11-08 15:37:20 -0600739
740 #Add in any pinctrl properties. These would come from the parent
741 #of $i2c{SOURCE}, which would be a unit-pingroup-bmc if the
742 #pins for this connection are multi-function.
743 addPinCtrlProps($g_targetObj->getTargetParent($i2c->{SOURCE}),
744 \%{$busNodes{$busNodeName}{$busNodeName}});
Matt Spinler74909132016-10-07 13:52:19 -0500745 }
746
747 #Each bus gets its own hash entry in the array
748 for my $b (sort keys %busNodes) {
749 push @nodes, { %{$busNodes{$b}} };
750 }
751
752 return @nodes;
753}
754
755
756#Returns a hash of property names and values that should be stored in
757#the device tree node for this device. The names of the properties and
758#the attributes to find their values in are stored in the
759#BMC_DT_ATTR_NAMES attribute in the chip.
760# $chip = the chip target
Matt Spinler889343f2017-01-30 14:14:11 -0600761sub getPartDefinedDTProperties
Matt Spinler74909132016-10-07 13:52:19 -0500762{
763 my $chip = shift;
764 my %props;
765
766 if ($g_targetObj->isBadAttribute($chip, "BMC_DT_ATTR_NAMES")) {
767 return %props;
768 }
769
770 my $attr = $g_targetObj->getAttribute($chip, "BMC_DT_ATTR_NAMES");
771 $attr =~ s/\s//g;
772 my @names = split(',', $attr);
773
774 #There can be up to 4 entries in this attribute
775 for (my $i = 0; $i < scalar @names; $i += 2) {
776
777 #$names[$i] holds the name of the attribute.
778 #$names[$i+1] holds the name of the property to store its value in.
779 if (($names[$i] ne "NA") && ($names[$i] ne "")) {
780
781 my $val = $g_targetObj->getAttribute($chip, $names[$i]);
782
783 #if the value is empty, assume it's for a standalone property,
784 #which gets turned into: some-property;
785 if ($val eq "") {
786 $props{$names[$i+1]} = ZERO_LENGTH_PROPERTY;
787 }
788 else {
789 $props{$names[$i+1]} = "<$val>";
790 }
791 }
792 }
793
794 return %props;
795}
796
797
798#Convert the MRW I2C address into the format the dts needs
799# $addr = the I2C Address
Matt Spinler889343f2017-01-30 14:14:11 -0600800sub adjustI2CAddress
Matt Spinler74909132016-10-07 13:52:19 -0500801{
802 my $addr = shift;
803
804 #MRW holds the 8 bit value. We need the 7 bit one.
Matt Spinler96f8f242016-11-28 16:26:57 -0600805 $addr = $addr >> 1;
Matt Spinler74909132016-10-07 13:52:19 -0500806 $addr = sprintf("0x%X", $addr);
807 $addr = lc $addr;
808
809 return $addr;
810}
811
812
Matt Spinler30b461c2016-10-10 16:50:07 -0500813#Sets the global $g_i2cBusAdjust from the configuration file.
Matt Spinler889343f2017-01-30 14:14:11 -0600814sub getI2CBusAdjust
Matt Spinler74909132016-10-07 13:52:19 -0500815{
Matt Spinler30b461c2016-10-10 16:50:07 -0500816 if (exists $g_configuration{"i2c-bus-adjust"}) {
Matt Spinler74909132016-10-07 13:52:19 -0500817
Matt Spinler30b461c2016-10-10 16:50:07 -0500818 $g_i2cBusAdjust = $g_configuration{"i2c-bus-adjust"};
Matt Spinler74909132016-10-07 13:52:19 -0500819
Matt Spinler30b461c2016-10-10 16:50:07 -0500820 if (!looks_like_number($g_i2cBusAdjust)) {
821 die "ERROR: Invalid i2c-bus-adjust value $g_i2cBusAdjust " .
822 "found in config file.\n";
Matt Spinler7d381e12016-09-27 14:27:24 -0500823 }
824 }
Matt Spinler30b461c2016-10-10 16:50:07 -0500825 else {
826 $g_i2cBusAdjust = 0;
827 print "WARNING: No I2C Bus number adjustment done " .
828 "for this system.\n";
829 }
Matt Spinler7d381e12016-09-27 14:27:24 -0500830}
831
832
Matt Spinler2efdcba2016-11-08 15:37:20 -0600833
834#Adds two pinctrl properties to the device node hash passed in,
835#if specified in the MRW. Pin Control refers to a mechanism for
836#Linux to know which function of a multi-function pin to configure.
837#For example, a pin could either be configured to be a GPIO, or
838#an I2C clock line. The pin function depends on board wiring,
839#so is known by the MRW.
840# $target = the target to get the BMC_DT_PINCTRL_FUNCTS attribute from
841# $node = a hash reference to the device tree node to add the properties to
Matt Spinler889343f2017-01-30 14:14:11 -0600842sub addPinCtrlProps
Matt Spinler2efdcba2016-11-08 15:37:20 -0600843{
844 my ($target, $node) = @_;
845
846 if (!$g_targetObj->isBadAttribute($target, "BMC_DT_PINCTRL_FUNCS")) {
847 my $attr = $g_targetObj->getAttribute($target,
848 "BMC_DT_PINCTRL_FUNCS");
849
850 my $pinCtrl0Prop = makePinCtrl0PropValue($attr);
851 if ($pinCtrl0Prop ne "") {
852 $node->{"pinctrl-names"} = "default";
853 $node->{"pinctrl-0"} = $pinCtrl0Prop;
854 }
855 }
856}
857
858
859#Constructs the pinctrl-0 property value based on the
860#BMC_DT_PINCTRL_FUNCS attribute passed in.
861# $attr = BMC_DT_PINCTRL_FUNCS attribute value, which is an array
Matt Spinler889343f2017-01-30 14:14:11 -0600862sub makePinCtrl0PropValue
Matt Spinler2efdcba2016-11-08 15:37:20 -0600863{
864 my $attr = shift;
865 my @entries;
866 my $value = "";
867
868 $attr =~ s/\s//g;
869 my @funcs = split(',', $attr);
870 foreach my $func (@funcs) {
871 if (($func ne "NA") && ($func ne "")) {
872 push @entries, $func;
873 }
874 }
875
876 #<&pinctrl_funcA_default &pinctrl_funcB_default ...>
877 if (scalar @entries) {
878 $value = "<";
879 foreach my $entry (@entries) {
880 $value .= "&pinctrl_".$entry."_default ";
881 }
882 $value =~ s/\s$//; #Remove the trailing space
883 $value .= ">";
884 }
885
886 return $value;
887}
888
889
Matt Spinler7d381e12016-09-27 14:27:24 -0500890#Returns a list of compatible fields for the BMC itself.
Matt Spinler889343f2017-01-30 14:14:11 -0600891sub getBMCCompatibles
Matt Spinler7d381e12016-09-27 14:27:24 -0500892{
893 my @compats;
894
Matt Spinler23d47c22016-10-04 12:31:21 -0500895 #1st entry: <system mfgr>,<system name>-bmc
896 #2nd entry: <bmc mfgr>,<bmc model>
Matt Spinler7d381e12016-09-27 14:27:24 -0500897
Matt Spinler23d47c22016-10-04 12:31:21 -0500898 foreach my $target (sort keys %{ $g_targetObj->getAllTargets() }) {
899 if ($g_targetObj->getType($target) eq "SYS") {
900 my $mfgr = $g_targetObj->getAttribute($target, "MANUFACTURER");
901 push @compats, lc "$mfgr,$g_systemName-bmc";
902 last;
903 }
Matt Spinler7d381e12016-09-27 14:27:24 -0500904 }
905
906 push @compats, lc($g_bmcMfgr).",".lc($g_bmcModel);
907
908 return @compats;
909}
910
911
912#Returns a string for the system's BMC model property
Matt Spinler889343f2017-01-30 14:14:11 -0600913sub getSystemBMCModel
Matt Spinler7d381e12016-09-27 14:27:24 -0500914{
Matt Spinler995f2a22016-09-30 13:07:31 -0500915 #'<System> BMC'
Matt Spinler7d381e12016-09-27 14:27:24 -0500916 my $sys = lc $g_systemName;
917 $sys = uc(substr($sys, 0, 1)) . substr($sys, 1);
918
919 return $sys . " BMC";
920}
921
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500922#Create the comment that will show up in the device tree
923#for a connection. In the output, will look like:
924# // sourceUnit ->
925# // destChip
926#
927# $conn = The connection hash reference
Matt Spinler889343f2017-01-30 14:14:11 -0600928sub connectionComment
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500929{
930 my $conn = shift;
931 my $comment = "$conn->{SOURCE} ->\n$conn->{DEST_PARENT}";
932 return $comment;
933}
934
Matt Spinler7d381e12016-09-27 14:27:24 -0500935
936#Prints a list of nodes at the same indent level
937# $f = file handle
938# $level = indent level (0,1,etc)
939# @nodes = array of node hashes to print, where the
940# key for the hash is the name of the node
Matt Spinler889343f2017-01-30 14:14:11 -0600941sub printNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500942{
943 my ($f, $level, @nodes) = @_;
944
945 foreach my $n (@nodes) {
946 my %node = %$n;
947
948 foreach my $name (sort keys %node) {
949 my %n = %{ $node{$name} };
950 printNode($f, $level, $name, %n);
951 }
952 }
953}
954
955
956#Print a single node and its children
957# $f = file handle
958# $level = indent level (0,1,etc)
959# $name = the name of the node - shows up as:
960# name { ...
961# %vals = The contents of the node, with the following options:
962# if the key is:
963# - 'DTSI_INCLUDE', then value gets turned into a #include
Matt Spinler995f2a22016-09-30 13:07:31 -0500964# - 'COMMENT', then value gets turned into a // comment
Matt Spinler74909132016-10-07 13:52:19 -0500965# - 'ZERO_LENGTH_PROPERTY' then value gets turned into: value;
Matt Spinler7d381e12016-09-27 14:27:24 -0500966#
967# If the value is:
968# - a hash - then that hash gets turned into a child node
969# where the key is the name of the child node
Matt Spinler995f2a22016-09-30 13:07:31 -0500970# - an array of hashes indicates an array of child nodes
Matt Spinler889343f2017-01-30 14:14:11 -0600971sub printNode
Matt Spinler7d381e12016-09-27 14:27:24 -0500972{
973 my ($f, $level, $name, %vals) = @_;
974 my $include = "";
975
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500976 #No reason to print an empty node
977 if (!keys %vals) {
978 return;
979 }
980
Matt Spinler7d381e12016-09-27 14:27:24 -0500981 if ($level == 0) {
982 $name = "&".$name;
983 }
984
Matt Spinler995f2a22016-09-30 13:07:31 -0500985 print $f "\n";
986
987 if (exists $vals{COMMENT}) {
988 my @lines = split('\n', $vals{COMMENT});
989 foreach my $l (@lines) {
990 print $f indent($level) . "// $l\n";
991 }
992 }
993
994 print $f indent($level) . "$name {\n";
Matt Spinler7d381e12016-09-27 14:27:24 -0500995
Matt Spinler74909132016-10-07 13:52:19 -0500996 #First print properties, then includes, then subnodes
997
998 #Print Properties
Matt Spinler7d381e12016-09-27 14:27:24 -0500999 foreach my $v (sort keys %vals) {
1000
Matt Spinler995f2a22016-09-30 13:07:31 -05001001 next if ($v eq "COMMENT");
Matt Spinler74909132016-10-07 13:52:19 -05001002 next if ($v eq "DTSI_INCLUDE");
1003 next if (ref($vals{$v}) eq "HASH");
1004 next if (ref($vals{$v}) eq "ARRAY");
Matt Spinler995f2a22016-09-30 13:07:31 -05001005
Matt Spinler74909132016-10-07 13:52:19 -05001006 if ($vals{$v} ne ZERO_LENGTH_PROPERTY) {
1007 printProperty($f, $level+1, $v, $vals{$v});
Matt Spinler7d381e12016-09-27 14:27:24 -05001008 }
Matt Spinler74909132016-10-07 13:52:19 -05001009 else {
1010 printZeroLengthProperty($f, $level+1, $v);
1011 }
1012 }
1013
1014 #Print Includes
1015 foreach my $v (sort keys %vals) {
1016
1017 if ($v eq "DTSI_INCLUDE") {
1018 #print 1 include per line
1019 my @incs = split(',', $vals{$v});
1020 foreach my $i (@incs) {
1021 print $f qq(#include "$i";\n);
1022 }
1023 }
1024 }
1025
1026 #Print Nodes
1027 foreach my $v (sort keys %vals) {
1028
1029 if (ref($vals{$v}) eq "HASH") {
Matt Spinler7d381e12016-09-27 14:27:24 -05001030 printNode($f, $level+1, $v, %{$vals{$v}});
1031 }
Matt Spinler995f2a22016-09-30 13:07:31 -05001032 #An array of nested nodes
1033 elsif (ref($vals{$v}) eq "ARRAY") {
1034 my @array = @{$vals{$v}};
1035 &printNodes($f, $level+1, @array);
1036 }
Matt Spinler7d381e12016-09-27 14:27:24 -05001037 }
1038
1039 print $f indent($level) . "};\n";
1040}
1041
1042
1043#Prints a comma separated list of properties.
1044#e.g. a = "b, c, d";
1045# $f = file handle
1046# $level = indent level (0,1,etc)
1047# $name = name of property
1048# @vals = list of property values
Matt Spinler889343f2017-01-30 14:14:11 -06001049sub printPropertyList
Matt Spinler7d381e12016-09-27 14:27:24 -05001050{
1051 my ($f, $level, $name, @vals) = @_;
1052
1053 print $f indent($level) . "$name = ";
1054
1055 for (my $i = 0;$i < scalar @vals; $i++) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001056 print $f qq("$vals[$i]");
Matt Spinler7d381e12016-09-27 14:27:24 -05001057 if ($i < (scalar(@vals) - 1)) {
1058 print $f ", ";
1059 }
1060 }
1061 print $f ";\n"
1062}
1063
1064
1065#Prints a single property. e.g. a = "b";
1066# $f = file handle
1067# $level = indent level (0,1,etc)
1068# $name = name of property
1069# @vals = property values
Matt Spinler889343f2017-01-30 14:14:11 -06001070sub printProperty
Matt Spinler7d381e12016-09-27 14:27:24 -05001071{
1072 my ($f, $level, $name, $val) = @_;
Matt Spinler30b461c2016-10-10 16:50:07 -05001073 my $quoteChar = qq(");
Matt Spinler23d47c22016-10-04 12:31:21 -05001074
Matt Spinler30b461c2016-10-10 16:50:07 -05001075 $val = convertReference($val);
Matt Spinler23d47c22016-10-04 12:31:21 -05001076
1077 #properties with < > or single word aliases don't need quotes
1078 if (($val =~ /<.*>/) || ($val =~ /^&\w+$/)) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001079 $quoteChar = "";
Matt Spinler23d47c22016-10-04 12:31:21 -05001080 }
1081
Matt Spinler30b461c2016-10-10 16:50:07 -05001082 print $f indent($level) . "$name = $quoteChar$val$quoteChar;\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001083}
1084
1085
Matt Spinler30b461c2016-10-10 16:50:07 -05001086#Prints a zero length property e.g. some-property;
Matt Spinler7d381e12016-09-27 14:27:24 -05001087# $f = file handle
1088# $level = indent level (0,1,etc)
1089# $name = name of property
Matt Spinler889343f2017-01-30 14:14:11 -06001090sub printZeroLengthProperty
Matt Spinler7d381e12016-09-27 14:27:24 -05001091{
1092 my ($f, $level, $name) = @_;
1093 print $f indent($level) . "$name;\n";
1094}
1095
1096
Matt Spinler30b461c2016-10-10 16:50:07 -05001097#Replace '(ref)' with '&'.
Matt Spinler7d381e12016-09-27 14:27:24 -05001098#Needed because Serverwiz doesn't properly escape '&'s in the XML,
Matt Spinler30b461c2016-10-10 16:50:07 -05001099#so the '(ref)' string is used to represent the reference
Matt Spinler7d381e12016-09-27 14:27:24 -05001100#specifier instead of '&'.
Matt Spinler889343f2017-01-30 14:14:11 -06001101sub convertReference
1102{
Matt Spinler7d381e12016-09-27 14:27:24 -05001103 my $val = shift;
Matt Spinler30b461c2016-10-10 16:50:07 -05001104 $val =~ s/\(ref\)/&/g;
Matt Spinler7d381e12016-09-27 14:27:24 -05001105 return $val
1106}
1107
1108
1109#Returns the target for the BMC chip.
1110#Not worrying about multiple BMC systems for now.
1111sub getBMCTarget()
1112{
1113 foreach my $target (sort keys %{ $g_targetObj->getAllTargets() })
1114 {
1115 if ($g_targetObj->getType($target) eq "BMC") {
1116 return $target;
1117 }
1118 }
1119 return "";
1120}
1121
1122
1123#Prints the device tree version line.
1124# $f = file handle
Matt Spinler889343f2017-01-30 14:14:11 -06001125sub printVersion
Matt Spinler7d381e12016-09-27 14:27:24 -05001126{
1127 my $f = shift;
1128 print $f VERSION."\n"
1129}
1130
1131
1132#Prints the #include line for pulling in an include file.
Matt Spinler30b461c2016-10-10 16:50:07 -05001133#The files to include come from the configuration file.
Matt Spinler7d381e12016-09-27 14:27:24 -05001134# $f = file handle
Matt Spinler30b461c2016-10-10 16:50:07 -05001135# $type = include type
Matt Spinler889343f2017-01-30 14:14:11 -06001136sub printIncludes
Matt Spinler7d381e12016-09-27 14:27:24 -05001137{
Matt Spinler30b461c2016-10-10 16:50:07 -05001138 my ($f, $type) = @_;
1139 my @includes = getIncludes($type);
Matt Spinler7d381e12016-09-27 14:27:24 -05001140
1141 foreach my $i (@includes) {
1142 #if a .dtsi, gets " ", otherwise < >
1143 if ($i =~ /\.dtsi$/) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001144 $i = qq("$i");
Matt Spinler7d381e12016-09-27 14:27:24 -05001145 }
1146 else {
Matt Spinler30b461c2016-10-10 16:50:07 -05001147 $i = "<$i>";
Matt Spinler7d381e12016-09-27 14:27:24 -05001148 }
Matt Spinler30b461c2016-10-10 16:50:07 -05001149 print $f "#include $i\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001150 }
1151}
1152
1153
Matt Spinler30b461c2016-10-10 16:50:07 -05001154#Returns an array of include files found in the config file
1155#for the type specified.
1156# $type = the include type, which is the section name in the
1157# YAML configuration file.
Matt Spinler889343f2017-01-30 14:14:11 -06001158sub getIncludes
Matt Spinler7d381e12016-09-27 14:27:24 -05001159{
Matt Spinler30b461c2016-10-10 16:50:07 -05001160 my $type = shift;
Matt Spinler7d381e12016-09-27 14:27:24 -05001161 my @includes;
1162
Matt Spinler30b461c2016-10-10 16:50:07 -05001163 #The config file may have a section but no includes
1164 #listed in it, which is OK.
1165 if ((exists $g_configuration{includes}{$type}) &&
1166 (ref($g_configuration{includes}{$type}) eq "ARRAY")) {
Matt Spinler7d381e12016-09-27 14:27:24 -05001167
Matt Spinler30b461c2016-10-10 16:50:07 -05001168 @includes = @{$g_configuration{includes}{$type}};
Matt Spinler7d381e12016-09-27 14:27:24 -05001169 }
1170
1171 return @includes;
1172}
1173
Matt Spinler30b461c2016-10-10 16:50:07 -05001174
Matt Spinler74909132016-10-07 13:52:19 -05001175#Appends the first value of the 'reg' property
1176#passed in to the name passed in to create the
1177#full name for the node
1178# $name = node name that will be appended to
1179# $reg = the reg property values
Matt Spinler889343f2017-01-30 14:14:11 -06001180sub makeNodeName
Matt Spinler74909132016-10-07 13:52:19 -05001181{
1182 my ($name, $reg) = @_;
1183
1184 $reg =~ s/<//g;
1185 $reg =~ s/>//g;
1186 my @vals = split(' ', $reg);
1187
1188 if (scalar @vals > 0) {
1189 $vals[0] =~ s/0x//;
1190 $name .= "@" . lc $vals[0];
1191 }
1192
1193 return $name;
1194}
1195
Matt Spinler7d381e12016-09-27 14:27:24 -05001196
1197#Prints the root node starting bracket.
1198# $f = file handle
Matt Spinler889343f2017-01-30 14:14:11 -06001199sub printRootNodeStart
1200{
Matt Spinler7d381e12016-09-27 14:27:24 -05001201 my $f = shift;
Matt Spinler30b461c2016-10-10 16:50:07 -05001202 print $f qq(/ {\n);
Matt Spinler7d381e12016-09-27 14:27:24 -05001203}
1204
1205
1206#Prints the root node ending bracket.
1207# $f = file handle
1208# $level = indent level (0,1,etc)
Matt Spinler889343f2017-01-30 14:14:11 -06001209sub printRootNodeEnd
1210{
Matt Spinler7d381e12016-09-27 14:27:24 -05001211 my ($f, $level) = @_;
Matt Spinler30b461c2016-10-10 16:50:07 -05001212 print $f indent($level).qq(};\n);
Matt Spinler7d381e12016-09-27 14:27:24 -05001213}
1214
1215
1216#Returns a string that can be used to indent based on the
1217#level passed in. Each level is an additional 4 spaces.
1218# $level = indent level (0,1,etc)
Matt Spinler889343f2017-01-30 14:14:11 -06001219sub indent
1220{
Matt Spinler7d381e12016-09-27 14:27:24 -05001221 my $level = shift;
1222 return ' ' x ($level * 4);
1223}
1224
1225
Matt Spinler7d381e12016-09-27 14:27:24 -05001226sub printUsage
1227{
Matt Spinler30b461c2016-10-10 16:50:07 -05001228 print "gen_devtree.pl -x [XML filename] -y [yaml config file] " .
1229 "-o [output filename]\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001230 exit(1);
1231}