blob: baa4056f9f1811b33054baa292b1b2fd10a17d77 [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;
Matt Spinlere2bf4392017-01-30 13:16:28 -060010use mrw::Util;
Matt Spinler7d381e12016-09-27 14:27:24 -050011use Getopt::Long;
Matt Spinler30b461c2016-10-10 16:50:07 -050012use YAML::Tiny qw(LoadFile);
13use Scalar::Util qw(looks_like_number);
Matt Spinler7d381e12016-09-27 14:27:24 -050014
Matt Spinler30b461c2016-10-10 16:50:07 -050015use constant {
16 VERSION => "/dts-v1/;",
17 ZERO_LENGTH_PROPERTY => "zero_length_property",
18 PRE_ROOT_INCLUDES => "pre-root-node",
19 ROOT_INCLUDES => "root-node",
20 POST_ROOT_INCLUDES => "post-root-node"
21};
Matt Spinler74909132016-10-07 13:52:19 -050022
Matt Spinler7d381e12016-09-27 14:27:24 -050023
24my $serverwizFile;
Matt Spinler30b461c2016-10-10 16:50:07 -050025my $configFile;
Matt Spinler7d381e12016-09-27 14:27:24 -050026my $outputFile;
27my $debug;
28
29GetOptions("x=s" => \$serverwizFile,
Matt Spinler30b461c2016-10-10 16:50:07 -050030 "y=s" => \$configFile,
Matt Spinler7d381e12016-09-27 14:27:24 -050031 "o=s" => \$outputFile,
32 "d" => \$debug)
33or printUsage();
34
Matt Spinler30b461c2016-10-10 16:50:07 -050035if ((not defined $serverwizFile) || (not defined $outputFile) ||
36 (not defined $configFile)) {
Matt Spinler7d381e12016-09-27 14:27:24 -050037 printUsage();
38}
39
Matt Spinler30b461c2016-10-10 16:50:07 -050040my %g_configuration = %{ LoadFile($configFile) };
41
Matt Spinler7d381e12016-09-27 14:27:24 -050042my $g_targetObj = Targets->new;
43$g_targetObj->loadXML($serverwizFile);
44
Matt Spinler74909132016-10-07 13:52:19 -050045my ($g_bmc, $g_bmcModel, $g_bmcMfgr, $g_systemName);
46setGlobalAttributes();
Matt Spinler7d381e12016-09-27 14:27:24 -050047
Matt Spinler30b461c2016-10-10 16:50:07 -050048my $g_i2cBusAdjust = 0;
49getI2CBusAdjust();
Matt Spinler7d381e12016-09-27 14:27:24 -050050
51open (my $f, ">$outputFile") or die "Could not open $outputFile\n";
52
53printVersion($f);
Matt Spinler30b461c2016-10-10 16:50:07 -050054printIncludes($f, PRE_ROOT_INCLUDES);
Matt Spinler7d381e12016-09-27 14:27:24 -050055printRootNodeStart($f);
56
57printPropertyList($f, 1, "model", getSystemBMCModel());
Matt Spinler7d381e12016-09-27 14:27:24 -050058printPropertyList($f, 1, "compatible", getBMCCompatibles());
Matt Spinler995f2a22016-09-30 13:07:31 -050059
Matt Spinler23d47c22016-10-04 12:31:21 -050060printNode($f, 1, "aliases", getAliases());
Matt Spinler7d381e12016-09-27 14:27:24 -050061printNode($f, 1, "chosen", getChosen());
Matt Spinler30b461c2016-10-10 16:50:07 -050062printNode($f, 1, "memory", getBmcMemory());
Matt Spinler7d381e12016-09-27 14:27:24 -050063
Matt Spinler995f2a22016-09-30 13:07:31 -050064printNode($f, 1, "leds", getLEDNode());
65
Matt Spinler30b461c2016-10-10 16:50:07 -050066printIncludes($f, ROOT_INCLUDES);
67
Matt Spinler7d381e12016-09-27 14:27:24 -050068printRootNodeEnd($f, 0);
69
Matt Spinler96f8f242016-11-28 16:26:57 -060070printNodes($f, 0, getBMCFlashNodes());
71
72printNodes($f, 0, getOtherFlashNodes());
73
Matt Spinler74909132016-10-07 13:52:19 -050074printNodes($f, 0, getI2CNodes());
Matt Spinler7d381e12016-09-27 14:27:24 -050075printNodes($f, 0, getMacNodes());
Matt Spinler995f2a22016-09-30 13:07:31 -050076printNodes($f, 0, getUARTNodes());
Matt Spinler7d381e12016-09-27 14:27:24 -050077printNodes($f, 0, getVuartNodes());
78
Matt Spinler30b461c2016-10-10 16:50:07 -050079printIncludes($f, POST_ROOT_INCLUDES);
80
Matt Spinler7d381e12016-09-27 14:27:24 -050081close $f;
82exit 0;
83
84
Matt Spinler74909132016-10-07 13:52:19 -050085#Finds the values for these globals:
86# $g_bmc, $g_bmcModel, $g_bmcMfgr, $g_systemName
Matt Spinler889343f2017-01-30 14:14:11 -060087sub setGlobalAttributes
Matt Spinler74909132016-10-07 13:52:19 -050088{
Matt Spinlere2bf4392017-01-30 13:16:28 -060089 $g_bmc = Util::getBMCTarget($g_targetObj);
Matt Spinler74909132016-10-07 13:52:19 -050090
91 if ($g_targetObj->isBadAttribute($g_bmc, "MODEL")) {
92 die "The MODEL attribute on $g_bmc is missing or empty.\n";
93 }
94 $g_bmcModel = $g_targetObj->getAttribute($g_bmc, "MODEL");
95
96 if ($g_targetObj->isBadAttribute($g_bmc, "MANUFACTURER")) {
97 die "The MANUFACTURER attribute on $g_bmc is missing or empty.\n";
98 }
99 $g_bmcMfgr = $g_targetObj->getAttribute($g_bmc, "MANUFACTURER");
100
101 $g_systemName = $g_targetObj->getSystemName();
102 if (length($g_systemName) == 0) {
103 die "The SYSTEM_NAME attribute is not set on the system target.\n";
104 }
105}
106
107
Matt Spinler23d47c22016-10-04 12:31:21 -0500108#Returns a hash that represents the 'aliases' node.
109#Will look like:
110# aliases {
111# name1 = &val1;
112# name2 = &val2;
113# ...
114# }
Matt Spinler889343f2017-01-30 14:14:11 -0600115sub getAliases
Matt Spinler23d47c22016-10-04 12:31:21 -0500116{
117 my %aliases;
Matt Spinler23d47c22016-10-04 12:31:21 -0500118
Matt Spinler30b461c2016-10-10 16:50:07 -0500119 #Get the info from the config file
Matt Spinler23d47c22016-10-04 12:31:21 -0500120
Matt Spinler30b461c2016-10-10 16:50:07 -0500121 if ((not exists $g_configuration{aliases}) ||
122 (keys %{$g_configuration{aliases}} == 0)) {
123 print "WARNING: Missing or empty 'aliases' section in config file.\n";
124 return %aliases;
125 }
126 %aliases = %{ $g_configuration{aliases} };
127
128 #add a & reference if one is missing
129 foreach my $a (keys %aliases) {
130 if (($aliases{$a} !~ /^&/) && ($aliases{$a} !~ /^\(ref\)/)) {
131 $aliases{$a} = "(ref)$aliases{$a}";
Matt Spinler23d47c22016-10-04 12:31:21 -0500132 }
133 }
134
135 return %aliases;
136}
137
Matt Spinler7d381e12016-09-27 14:27:24 -0500138
139#Return a hash that represents the 'chosen' node
Matt Spinler995f2a22016-09-30 13:07:31 -0500140#Will look like:
141# chosen {
142# stdout-path = ...
143# bootargs = ...
144# }
Matt Spinler889343f2017-01-30 14:14:11 -0600145sub getChosen
Matt Spinler7d381e12016-09-27 14:27:24 -0500146{
Matt Spinler7d381e12016-09-27 14:27:24 -0500147 my %chosen;
Matt Spinler30b461c2016-10-10 16:50:07 -0500148 my @allowed = qw(bootargs stdin-path stdout-path);
149
150 #Get the info from the config file
151
152 if (not exists $g_configuration{chosen}) {
153 die "ERROR: Missing 'chosen' section in config file.\n";
154 }
155 %chosen = %{ $g_configuration{chosen} };
156
Matt Spinler30b461c2016-10-10 16:50:07 -0500157 foreach my $key (keys %chosen) {
Matt Spinler30b461c2016-10-10 16:50:07 -0500158
Matt Spinler28fb1a92017-01-30 12:54:10 -0600159 #Check for allowed entries. Empty is OK.
160 if (!grep(/^$key$/, @allowed)) {
Matt Spinler30b461c2016-10-10 16:50:07 -0500161 die "Invalid entry $key in 'chosen' section in config file\n";
162 }
Matt Spinler28fb1a92017-01-30 12:54:10 -0600163
164 #stdout-path and stdin-path can use aliases, which will look like
165 #(alias)uart5 in the yaml. Change to (ref)uart5 so it will be
166 #converted to a '&' later.
167 $chosen{$key} =~ s/\(alias\)/\(ref\)/g;
Matt Spinler30b461c2016-10-10 16:50:07 -0500168 }
169
Matt Spinler7d381e12016-09-27 14:27:24 -0500170 return %chosen;
171}
172
173
Matt Spinler30b461c2016-10-10 16:50:07 -0500174#Return a hash that represents the 'memory' node.
Matt Spinler995f2a22016-09-30 13:07:31 -0500175#Will look like:
Matt Spinler30b461c2016-10-10 16:50:07 -0500176# memory {
177# reg = < base size >
178# }
Matt Spinler889343f2017-01-30 14:14:11 -0600179sub getBmcMemory
Matt Spinler30b461c2016-10-10 16:50:07 -0500180{
181 my %memory;
182
183 #Get the info from the config file
184
185 if (not exists $g_configuration{memory}) {
186 die "ERROR: Missing 'memory' section in config file.\n";
187 }
188
189 if ((not exists $g_configuration{memory}{base}) ||
190 ($g_configuration{memory}{base} !~ /0x/)) {
191 die "ERROR: The base entry in the memory section in the config " .
192 "file is either missing or invalid.\n";
193 }
194
195 if ((not exists $g_configuration{memory}{size}) ||
196 ($g_configuration{memory}{size} !~ /0x/)) {
197 die "ERROR: The size entry in the memory section in the config " .
198 "file is either missing or invalid.\n";
199 }
200
201 #Future: could do more validation on the actual values
202
203 $memory{reg} = "<$g_configuration{memory}{base} " .
204 "$g_configuration{memory}{size}>";
205
206 return %memory;
207}
208
209
Matt Spinler25d60bb2016-10-31 15:16:03 -0500210#Returns an array of hashes representing the device tree nodes for
211#the BMC flash. These nodes are BMC model specific because different
212#models can have different device drivers.
Matt Spinler889343f2017-01-30 14:14:11 -0600213sub getBMCFlashNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500214{
Matt Spinler25d60bb2016-10-31 15:16:03 -0500215 my @nodes;
216
217 if ($g_bmcModel eq "AST2500") {
218 my %node = getAST2500BMCSPIFlashNode();
219 push @nodes, { %node };
220 }
221 else {
222 die "ERROR: No BMC SPI flash support yet for BMC model $g_bmcModel\n";
223 }
224
225 return @nodes;
226}
227
228
229#Returns a hash that represents the BMC SPI flash(es) by finding the SPI
230#connections that come from the unit tagged as BMC_CODE. The code also
231#looks in the config file for any additional properties to add. Supports
232#the hardware where the same SPI master unit can be wired to more than 1
233#flash (a chip select line is used to switch between them.) This is
234#specific to the ASPEED AST2500 hardware and device driver.
235#Will look like:
236# fmc {
237# status = "okay"
238# flash@0 {
239# ...
240# };
241# flash@1 {
242# ...
243# };
Matt Spinler889343f2017-01-30 14:14:11 -0600244sub getAST2500BMCSPIFlashNode
Matt Spinler25d60bb2016-10-31 15:16:03 -0500245{
246 my %bmcFlash;
247 my $chipSelect = 0;
248 my $lastUnit = "";
249
Matt Spinler18d5f572016-11-15 15:25:45 -0600250 my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH");
Matt Spinler25d60bb2016-10-31 15:16:03 -0500251
252 if ($connections eq "") {
253 die "ERROR: No BMC SPI flashes found connected to the BMC\n";
254 }
255
256 $bmcFlash{fmc}{status} = "okay";
257
258 foreach my $spi (@{$connections->{CONN}}) {
259
260 #Looking for spi-masters with a function of 'BMC_CODE'.
261 #It's possible there are multiple flash chips here.
262 if (!$g_targetObj->isBadAttribute($spi->{SOURCE}, "SPI_FUNCTION")) {
263
264 my $function = $g_targetObj->getAttribute($spi->{SOURCE},
265 "SPI_FUNCTION");
266 if ($function eq "BMC_CODE") {
267
268 my $flashName = "flash@".$chipSelect;
269
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500270 $bmcFlash{fmc}{$flashName}{COMMENT} = connectionComment($spi);
Matt Spinler25d60bb2016-10-31 15:16:03 -0500271
272 $bmcFlash{fmc}{$flashName}{status} = "okay";
273
274 #Add in anything specified in the config file for this chip.
275 addBMCFlashConfigProperties(\%{$bmcFlash{fmc}{$flashName}},
276 $chipSelect);
277
278 #The code currently only supports the config where a chip
279 #select line is used to select between possibly multiple
280 #flash chips attached to the same SPI pins/unit. So we
281 #need to make sure if there are multiple chips found, that
282 #they are off of the same master unit.
283 if ($lastUnit eq "") {
284 $lastUnit = $spi->{SOURCE};
285 }
286 else {
287 if ($lastUnit ne $spi->{SOURCE}) {
288 die "ERROR: Currently only 1 spi-master unit is " .
289 "supported for BMC flash connections."
290 }
291 }
292
293 #Since we don't need anything chip select specific from the
294 #XML, we can just assign our own chip selects.
295 $chipSelect++;
296 }
297 }
298 }
299
300 if ($chipSelect == 0) {
301 die "ERROR: Didn't find any BMC flash chips connected";
302 }
303
304 return %bmcFlash;
305}
306
307
308#Looks in the bmc-flash-config section in the config file for the
309#chip select passed in to add any additional properties to the BMC
310#flash node.
311# $node = hash reference to the flash node
312# $cs = the flash chip select value
Matt Spinler889343f2017-01-30 14:14:11 -0600313sub addBMCFlashConfigProperties
Matt Spinler25d60bb2016-10-31 15:16:03 -0500314{
315 my ($node, $cs) = @_;
316 my $section = "chip-select-$cs";
317
318 if (exists $g_configuration{"bmc-flash-config"}{$section}) {
319 foreach my $key (sort keys $g_configuration{"bmc-flash-config"}{$section}) {
320 $node->{$key} = $g_configuration{"bmc-flash-config"}{$section}{$key};
321 }
322 }
Matt Spinler995f2a22016-09-30 13:07:31 -0500323}
324
325
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500326#Returns an array of hashes representing the other flashes used by the
327#BMC besides the ones that hold the BMC code. This is BMC model specific
328#as different models can have different interfaces.
329#Typically, these are SPI flashes.
Matt Spinler889343f2017-01-30 14:14:11 -0600330sub getOtherFlashNodes
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500331{
332 my @nodes;
333
334 if ($g_bmcModel eq "AST2500") {
335 @nodes = getAST2500SpiFlashNodes();
336 }
337 else {
338 die "ERROR: No SPI flash support yet for BMC model $g_bmcModel\n";
339 }
340
341 return @nodes;
342}
343
344
345#Returns an array of hashes representing the SPI flashes in an
346#AST2500. These are for the SPI1 and SPI2 interfaces in the chip.
347#Each SPI master interface can support multiple flash chips. If
348#no hardware is connected to the interface, the node won't be present.
Matt Spinler889343f2017-01-30 14:14:11 -0600349sub getAST2500SpiFlashNodes
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500350{
351 my @nodes;
352
353 #The AST2500 has 2 SPI master units, 1 and 2.
354 my @units = (1, 2);
355
356 foreach my $unit (@units) {
357
358 my %node = getAST2500SpiMasterNode($unit);
359
360 if (keys %node) {
361 my %spiNode;
362 my $nodeName = "spi$unit";
363 $spiNode{$nodeName} = { %node };
364 push @nodes, { %spiNode };
365 }
366 }
367
368 return @nodes;
369}
370
371
372#Returns a hash that represents the device tree node for the SPI1
373#or SPI2 master interface on the AST2500. Each master can support
374#multiple chips by use of a chip select.
375#Will look like:
376# spi1 {
377# status = "okay";
378# flash@0 {
379# ...
380# };
381# };
382#
383# $spiNum = The SPI master unit number to use
Matt Spinler889343f2017-01-30 14:14:11 -0600384sub getAST2500SpiMasterNode
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500385{
386 my $spiNum = shift;
387 my %spiMaster;
388 my $chipSelect = 0;
389
Matt Spinler18d5f572016-11-15 15:25:45 -0600390 my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH");
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500391
392 if ($connections eq "") {
393 return %spiMaster;
394 }
395
396 #Looking for spi-masters with a chip-unit of $spiNum
397 #It's possible there are multiple flash chips off the master
398 foreach my $spi (@{$connections->{CONN}}) {
399
400 my $unitNum = $g_targetObj->getAttribute($spi->{SOURCE},
401 "CHIP_UNIT");
402 if ($unitNum == $spiNum) {
403 $spiMaster{status} = "okay";
Matt Spinler2efdcba2016-11-08 15:37:20 -0600404
405 #Add in any pinctrl properties. These would come from the parent
406 #of $spi{SOURCE}, which would be a unit-pingroup-bmc if the
407 #pins for this connection are multi-function.
408 addPinCtrlProps($g_targetObj->getTargetParent($spi->{SOURCE}),
409 \%spiMaster);
410
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500411 my $flashName = "flash@".$chipSelect;
412
413 $spiMaster{$flashName}{COMMENT} = connectionComment($spi);
414
415 $spiMaster{$flashName}{status} = "okay";
416
Matt Spinler0eda4882016-11-30 15:20:11 -0600417 #AST2500 PNORs need a label
418 my $function = $g_targetObj->getAttribute($spi->{SOURCE},
419 "SPI_FUNCTION");
420 if ($function eq "PNOR") {
421 $spiMaster{$flashName}{label} = "pnor";
422 }
423
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500424 $chipSelect++;
425 }
426 }
427
428 return %spiMaster;
429}
430
431
Matt Spinler995f2a22016-09-30 13:07:31 -0500432#Returns a hash that represents the leds node by finding all of the
433#GPIO connections to LEDs.
434#Node will look like:
435# leds {
436# <ledname> {
437# gpios = &gpio ASPEED_GPIO(x, y) GPIO_ACTIVE_xxx>
438# };
439# <another ledname> {
440# ...
441# }
Matt Spinler889343f2017-01-30 14:14:11 -0600442sub getLEDNode
Matt Spinler995f2a22016-09-30 13:07:31 -0500443{
444 my %leds;
445
Matt Spinlereca7f062016-11-07 09:59:23 -0600446 $leds{compatible} = "gpio-leds";
Matt Spinler995f2a22016-09-30 13:07:31 -0500447
Matt Spinler18d5f572016-11-15 15:25:45 -0600448 my $connections = $g_targetObj->findConnections($g_bmc, "GPIO", "LED");
Matt Spinler995f2a22016-09-30 13:07:31 -0500449
450 if ($connections eq "") {
451 print "WARNING: No LEDs found connected to the BMC\n";
452 return %leds;
453 }
454
455 foreach my $gpio (@{$connections->{CONN}}) {
456 my %ledNode;
457
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500458 $ledNode{COMMENT} = connectionComment($gpio);
Matt Spinler995f2a22016-09-30 13:07:31 -0500459
460 #The node name will be the simplified LED name
461 my $name = $gpio->{DEST_PARENT};
462 $name =~ s/(-\d+$)//; #remove trailing position
463 $name =~ s/.*\///; #remove the front of the path
464
465 #For now only supports ASPEED.
466 if (uc($g_bmcMfgr) ne "ASPEED") {
467 die "ERROR: Unsupported BMC manufacturer $g_bmcMfgr\n";
468 }
469 my $num = $g_targetObj->getAttribute($gpio->{SOURCE}, "PIN_NUM");
470 my $macro = getAspeedGpioMacro($num);
471
472 #If it's active high or low
473 my $state = $g_targetObj->getAttribute($gpio->{DEST_PARENT}, "ON_STATE");
474 my $activeString = getGpioActiveString($state);
475
476 $ledNode{gpios} = "<&gpio $macro $activeString>";
477
478 $leds{$name} = { %ledNode };
479 }
480
481 return %leds;
482}
483
484
485#Returns a either GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW
486# $val = either a 1 or a 0 for active high or low
Matt Spinler889343f2017-01-30 14:14:11 -0600487sub getGpioActiveString
488{
Matt Spinler995f2a22016-09-30 13:07:31 -0500489 my $val = shift;
490
491 if ($val == 0) {
492 return "GPIO_ACTIVE_LOW";
493 }
494
495 return "GPIO_ACTIVE_HIGH";
496}
497
498
499#Turns a GPIO number into something like ASPEED_GPIO(A, 0) for the
500#ASPEED GPIO numbering scheme A[0-7] -> Z[0-7] and then starts at
501#AA[0-7] after that.
502# $num = the GPIO number
Matt Spinler889343f2017-01-30 14:14:11 -0600503sub getAspeedGpioMacro
504{
Matt Spinler995f2a22016-09-30 13:07:31 -0500505 my $num = shift;
506 my $char;
507 my $offset = $num % 8;
508 my $block = int($num / 8);
509
510 #If past Z, wraps to AA, AB, etc
511 if ((ord('A') + $block) > ord('Z')) {
512 #how far past Z?
513 $char = $block - (ord('Z') - ord('A'));
514
515 #Don't let it wrap twice
516 if ($char > (ord('Z') - ord('A') + 1)) {
517 die "ERROR: Invalid PIN_NUM value $num found for GPIO\n";
518 }
519
520 #start back at 'A' again, and convert to a character
521 $char = chr($char + ord('A') - 1);
522
523 #Add in a bonus 'A', to get something like AB
524 $char = "A".$char;
525 }
526 else {
527 $char = ord('A') + $block;
528 $char = chr($char);
529 }
530
531 return "ASPEED_GPIO($char, $offset)";
532}
533
534
535#Returns a list of hashes that represent the UART nodes on the BMC by
536#finding the UART connections.
537#Nodes will look like:
538# &uartX {
539# status = "okay"
540# }
Matt Spinler889343f2017-01-30 14:14:11 -0600541sub getUARTNodes
Matt Spinler995f2a22016-09-30 13:07:31 -0500542{
543 my @nodes;
544
Matt Spinler23d47c22016-10-04 12:31:21 -0500545 #Using U750 for legacy MRW reasons
Matt Spinler18d5f572016-11-15 15:25:45 -0600546 my $connections = $g_targetObj->findConnections($g_bmc, "U750");
Matt Spinler995f2a22016-09-30 13:07:31 -0500547
548 if ($connections eq "") {
549 print "WARNING: No UART buses found connected to the BMC\n";
550 return @nodes;
551 }
552
553 foreach my $uart (@{$connections->{CONN}}) {
554 my %node;
555
556 my $num = $g_targetObj->getAttribute($uart->{SOURCE}, "CHIP_UNIT");
557 my $name = "uart$num";
558
559 $node{$name}{status} = "okay";
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500560 $node{$name}{COMMENT} = connectionComment($uart);
Matt Spinler995f2a22016-09-30 13:07:31 -0500561
Matt Spinler2efdcba2016-11-08 15:37:20 -0600562 #Add in any pinctrl properties. These would come from the parent
563 #of $uart{SOURCE}, which would be a unit-pingroup-bmc if the
564 #pins for this connection are multi-function.
565 addPinCtrlProps($g_targetObj->getTargetParent($uart->{SOURCE}),
566 \%{$node{$name}});
567
Matt Spinler995f2a22016-09-30 13:07:31 -0500568 push @nodes, { %node };
569 }
570
Matt Spinler7d381e12016-09-27 14:27:24 -0500571 return @nodes;
572}
573
574
Matt Spinler995f2a22016-09-30 13:07:31 -0500575#Returns a list of hashes that represent the MAC (ethernet) nodes on the BMC
576#by finding the connections of type ETHERNET.
577#Nodes will look like:
578# &macX {
579# ...
580# }
Matt Spinler889343f2017-01-30 14:14:11 -0600581sub getMacNodes
Matt Spinler995f2a22016-09-30 13:07:31 -0500582{
583 my @nodes;
584
Matt Spinler18d5f572016-11-15 15:25:45 -0600585 my $connections = $g_targetObj->findConnections($g_bmc, "ETHERNET");
Matt Spinler995f2a22016-09-30 13:07:31 -0500586
587 if ($connections eq "") {
588 print "WARNING: No ethernet buses found connected to the BMC\n";
589 return @nodes;
590 }
591
592 foreach my $eth (@{$connections->{CONN}}) {
593 my %node;
594
595 my $num = $g_targetObj->getAttribute($eth->{SOURCE}, "CHIP_UNIT");
596 my $ncsi = $g_targetObj->getAttribute($eth->{SOURCE}, "NCSI_MODE");
597 my $hwChecksum = $g_targetObj->getAttribute($eth->{SOURCE},
598 "USE_HW_CHECKSUM");
599
600 my $name = "mac$num";
601 $node{$name}{status} = "okay";
602
603 if ($ncsi == 1) {
Matt Spinler74909132016-10-07 13:52:19 -0500604 $node{$name}{"use-ncsi"} = ZERO_LENGTH_PROPERTY;
Matt Spinler995f2a22016-09-30 13:07:31 -0500605 }
606 if ($hwChecksum == 0) {
Matt Spinler74909132016-10-07 13:52:19 -0500607 $node{$name}{"no-hw-checksum"} = ZERO_LENGTH_PROPERTY;
Matt Spinler995f2a22016-09-30 13:07:31 -0500608 }
609
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500610 $node{$name}{COMMENT} = connectionComment($eth);
Matt Spinler995f2a22016-09-30 13:07:31 -0500611
Matt Spinler2efdcba2016-11-08 15:37:20 -0600612 #Add in any pinctrl properties. These would come from the parent
613 #of $eth{SOURCE}, which would be a unit-pingroup-bmc if the
614 #pins for this connection are multi-function.
615 addPinCtrlProps($g_targetObj->getTargetParent($eth->{SOURCE}),
616 \%{$node{$name}});
617
Matt Spinler995f2a22016-09-30 13:07:31 -0500618 push @nodes, { %node };
619 }
620
621 return @nodes;
622}
623
624
625#Returns a list of hashes that represent the virtual UART nodes
626#Node will look like:
627# &vuart {
628# status = "okay"
629# }
Matt Spinler889343f2017-01-30 14:14:11 -0600630sub getVuartNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500631{
632 my @nodes;
633 my %node;
634
635 #For now, enable 1 node all the time.
Matt Spinler995f2a22016-09-30 13:07:31 -0500636 #TBD if this needs to be fixed
Matt Spinler7d381e12016-09-27 14:27:24 -0500637 $node{vuart}{status} = "okay";
638
639 push @nodes, { %node };
640
641 return @nodes;
642}
643
Matt Spinler74909132016-10-07 13:52:19 -0500644#Returns a list of hashes that represent the I2C device nodes.
645#There is 1 parent node for each bus, which then have subnodes
646#for each device on that bus. If a bus doesn't have any
647#attached devices, it doesn't need to show up.
648#The nodes will look like:
649# &i2c0 {
650# status = "okay"
651# device1@addr { (addr = 7 bit I2C address)
652# reg = <addr>
653# compatible = ...
654# ...
655# }
656# device2@addr {
657# reg = <addr>
658# ...
659# }
660# }
661# &i2c1 {
662# ...
663# }
Matt Spinler889343f2017-01-30 14:14:11 -0600664sub getI2CNodes
Matt Spinler74909132016-10-07 13:52:19 -0500665{
666 my @nodes;
667 my %busNodes;
668
Matt Spinler18d5f572016-11-15 15:25:45 -0600669 my $connections = $g_targetObj->findConnections($g_bmc, "I2C");
Matt Spinler74909132016-10-07 13:52:19 -0500670
671 if ($connections eq "") {
672 print "WARNING: No I2C buses found connected to the BMC\n";
673 return @nodes;
674 }
675
676 foreach my $i2c (@{$connections->{CONN}}) {
677
678 my %deviceNode, my $deviceName;
679
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500680 $deviceNode{COMMENT} = connectionComment($i2c);
Matt Spinler74909132016-10-07 13:52:19 -0500681
682 $deviceName = lc $i2c->{DEST_PARENT};
683 $deviceName =~ s/-\d+$//; #remove trailing position
684 $deviceName =~ s/.*\///; #remove the front of the path
685
686 #Get the I2C address
687 my $i2cAddress = $g_targetObj->getAttribute($i2c->{DEST}, "I2C_ADDRESS");
688 $i2cAddress = hex($i2cAddress);
689 if ($i2cAddress == 0) {
690 die "ERROR: Missing I2C address on $i2c->{DEST}\n";
691 }
692
693 #Put it in the format we want to print it in
694 $i2cAddress = adjustI2CAddress($i2cAddress);
695 $deviceNode{reg} = "<$i2cAddress>";
696
697 $deviceName = makeNodeName($deviceName, $deviceNode{reg});
698
699 #Get the I2C bus number
700 if ($g_targetObj->isBadAttribute($i2c->{SOURCE},
701 "I2C_PORT")) {
702 die "ERROR: I2C_PORT attribute in $i2c->{DEST_PARENT} " .
703 "is either missing or empty.\n";
704 }
705
706 my $busNum = $g_targetObj->getAttribute($i2c->{SOURCE}, "I2C_PORT");
707 if ($busNum =~ /0x/i) {
708 $busNum = hex($busNum);
709 }
710
711 #Convert the number to the Linux numbering scheme.
Matt Spinler30b461c2016-10-10 16:50:07 -0500712 $busNum += $g_i2cBusAdjust;
Matt Spinler74909132016-10-07 13:52:19 -0500713
714 #Get the compatible property
715 if ($g_targetObj->isBadAttribute($i2c->{DEST_PARENT},
716 "BMC_DT_COMPATIBLE")) {
717 die "ERROR: BMC_DT_COMPATIBLE attribute in $i2c->{DEST_PARENT} " .
718 "is either missing or empty.\n";
719 }
720
721 $deviceNode{compatible} = $g_targetObj->getAttribute(
722 $i2c->{DEST_PARENT},
723 "BMC_DT_COMPATIBLE");
724
725 #Get any other part specific properties, where the property
726 #names are actually defined in the XML.
727 my %props = getPartDefinedDTProperties($i2c->{DEST_PARENT});
728 foreach my $prop (sort keys %props) {
729 $deviceNode{$prop} = $props{$prop};
730 }
731
732 #busNodeName is the hash twice so when we loop
733 #below it doesn't get lost
734 my $busNodeName = "i2c$busNum";
735 $busNodes{$busNodeName}{$busNodeName}{status} = "okay";
736 $busNodes{$busNodeName}{$busNodeName}{$deviceName} = { %deviceNode };
Matt Spinler2efdcba2016-11-08 15:37:20 -0600737
738 #Add in any pinctrl properties. These would come from the parent
739 #of $i2c{SOURCE}, which would be a unit-pingroup-bmc if the
740 #pins for this connection are multi-function.
741 addPinCtrlProps($g_targetObj->getTargetParent($i2c->{SOURCE}),
742 \%{$busNodes{$busNodeName}{$busNodeName}});
Matt Spinler74909132016-10-07 13:52:19 -0500743 }
744
745 #Each bus gets its own hash entry in the array
746 for my $b (sort keys %busNodes) {
747 push @nodes, { %{$busNodes{$b}} };
748 }
749
750 return @nodes;
751}
752
753
754#Returns a hash of property names and values that should be stored in
755#the device tree node for this device. The names of the properties and
756#the attributes to find their values in are stored in the
757#BMC_DT_ATTR_NAMES attribute in the chip.
758# $chip = the chip target
Matt Spinler889343f2017-01-30 14:14:11 -0600759sub getPartDefinedDTProperties
Matt Spinler74909132016-10-07 13:52:19 -0500760{
761 my $chip = shift;
762 my %props;
763
764 if ($g_targetObj->isBadAttribute($chip, "BMC_DT_ATTR_NAMES")) {
765 return %props;
766 }
767
768 my $attr = $g_targetObj->getAttribute($chip, "BMC_DT_ATTR_NAMES");
769 $attr =~ s/\s//g;
770 my @names = split(',', $attr);
771
772 #There can be up to 4 entries in this attribute
773 for (my $i = 0; $i < scalar @names; $i += 2) {
774
775 #$names[$i] holds the name of the attribute.
776 #$names[$i+1] holds the name of the property to store its value in.
777 if (($names[$i] ne "NA") && ($names[$i] ne "")) {
778
779 my $val = $g_targetObj->getAttribute($chip, $names[$i]);
780
781 #if the value is empty, assume it's for a standalone property,
782 #which gets turned into: some-property;
783 if ($val eq "") {
784 $props{$names[$i+1]} = ZERO_LENGTH_PROPERTY;
785 }
786 else {
787 $props{$names[$i+1]} = "<$val>";
788 }
789 }
790 }
791
792 return %props;
793}
794
795
796#Convert the MRW I2C address into the format the dts needs
797# $addr = the I2C Address
Matt Spinler889343f2017-01-30 14:14:11 -0600798sub adjustI2CAddress
Matt Spinler74909132016-10-07 13:52:19 -0500799{
800 my $addr = shift;
801
802 #MRW holds the 8 bit value. We need the 7 bit one.
Matt Spinler96f8f242016-11-28 16:26:57 -0600803 $addr = $addr >> 1;
Matt Spinler74909132016-10-07 13:52:19 -0500804 $addr = sprintf("0x%X", $addr);
805 $addr = lc $addr;
806
807 return $addr;
808}
809
810
Matt Spinler30b461c2016-10-10 16:50:07 -0500811#Sets the global $g_i2cBusAdjust from the configuration file.
Matt Spinler889343f2017-01-30 14:14:11 -0600812sub getI2CBusAdjust
Matt Spinler74909132016-10-07 13:52:19 -0500813{
Matt Spinler30b461c2016-10-10 16:50:07 -0500814 if (exists $g_configuration{"i2c-bus-adjust"}) {
Matt Spinler74909132016-10-07 13:52:19 -0500815
Matt Spinler30b461c2016-10-10 16:50:07 -0500816 $g_i2cBusAdjust = $g_configuration{"i2c-bus-adjust"};
Matt Spinler74909132016-10-07 13:52:19 -0500817
Matt Spinler30b461c2016-10-10 16:50:07 -0500818 if (!looks_like_number($g_i2cBusAdjust)) {
819 die "ERROR: Invalid i2c-bus-adjust value $g_i2cBusAdjust " .
820 "found in config file.\n";
Matt Spinler7d381e12016-09-27 14:27:24 -0500821 }
822 }
Matt Spinler30b461c2016-10-10 16:50:07 -0500823 else {
824 $g_i2cBusAdjust = 0;
825 print "WARNING: No I2C Bus number adjustment done " .
826 "for this system.\n";
827 }
Matt Spinler7d381e12016-09-27 14:27:24 -0500828}
829
830
Matt Spinler2efdcba2016-11-08 15:37:20 -0600831
832#Adds two pinctrl properties to the device node hash passed in,
833#if specified in the MRW. Pin Control refers to a mechanism for
834#Linux to know which function of a multi-function pin to configure.
835#For example, a pin could either be configured to be a GPIO, or
836#an I2C clock line. The pin function depends on board wiring,
837#so is known by the MRW.
838# $target = the target to get the BMC_DT_PINCTRL_FUNCTS attribute from
839# $node = a hash reference to the device tree node to add the properties to
Matt Spinler889343f2017-01-30 14:14:11 -0600840sub addPinCtrlProps
Matt Spinler2efdcba2016-11-08 15:37:20 -0600841{
842 my ($target, $node) = @_;
843
844 if (!$g_targetObj->isBadAttribute($target, "BMC_DT_PINCTRL_FUNCS")) {
845 my $attr = $g_targetObj->getAttribute($target,
846 "BMC_DT_PINCTRL_FUNCS");
847
848 my $pinCtrl0Prop = makePinCtrl0PropValue($attr);
849 if ($pinCtrl0Prop ne "") {
850 $node->{"pinctrl-names"} = "default";
851 $node->{"pinctrl-0"} = $pinCtrl0Prop;
852 }
853 }
854}
855
856
857#Constructs the pinctrl-0 property value based on the
858#BMC_DT_PINCTRL_FUNCS attribute passed in.
859# $attr = BMC_DT_PINCTRL_FUNCS attribute value, which is an array
Matt Spinler889343f2017-01-30 14:14:11 -0600860sub makePinCtrl0PropValue
Matt Spinler2efdcba2016-11-08 15:37:20 -0600861{
862 my $attr = shift;
863 my @entries;
864 my $value = "";
865
866 $attr =~ s/\s//g;
867 my @funcs = split(',', $attr);
868 foreach my $func (@funcs) {
869 if (($func ne "NA") && ($func ne "")) {
870 push @entries, $func;
871 }
872 }
873
874 #<&pinctrl_funcA_default &pinctrl_funcB_default ...>
875 if (scalar @entries) {
876 $value = "<";
877 foreach my $entry (@entries) {
878 $value .= "&pinctrl_".$entry."_default ";
879 }
880 $value =~ s/\s$//; #Remove the trailing space
881 $value .= ">";
882 }
883
884 return $value;
885}
886
887
Matt Spinler7d381e12016-09-27 14:27:24 -0500888#Returns a list of compatible fields for the BMC itself.
Matt Spinler889343f2017-01-30 14:14:11 -0600889sub getBMCCompatibles
Matt Spinler7d381e12016-09-27 14:27:24 -0500890{
891 my @compats;
892
Matt Spinler23d47c22016-10-04 12:31:21 -0500893 #1st entry: <system mfgr>,<system name>-bmc
894 #2nd entry: <bmc mfgr>,<bmc model>
Matt Spinler7d381e12016-09-27 14:27:24 -0500895
Matt Spinler23d47c22016-10-04 12:31:21 -0500896 foreach my $target (sort keys %{ $g_targetObj->getAllTargets() }) {
897 if ($g_targetObj->getType($target) eq "SYS") {
898 my $mfgr = $g_targetObj->getAttribute($target, "MANUFACTURER");
899 push @compats, lc "$mfgr,$g_systemName-bmc";
900 last;
901 }
Matt Spinler7d381e12016-09-27 14:27:24 -0500902 }
903
904 push @compats, lc($g_bmcMfgr).",".lc($g_bmcModel);
905
906 return @compats;
907}
908
909
910#Returns a string for the system's BMC model property
Matt Spinler889343f2017-01-30 14:14:11 -0600911sub getSystemBMCModel
Matt Spinler7d381e12016-09-27 14:27:24 -0500912{
Matt Spinler995f2a22016-09-30 13:07:31 -0500913 #'<System> BMC'
Matt Spinler7d381e12016-09-27 14:27:24 -0500914 my $sys = lc $g_systemName;
915 $sys = uc(substr($sys, 0, 1)) . substr($sys, 1);
916
917 return $sys . " BMC";
918}
919
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500920#Create the comment that will show up in the device tree
921#for a connection. In the output, will look like:
922# // sourceUnit ->
923# // destChip
924#
925# $conn = The connection hash reference
Matt Spinler889343f2017-01-30 14:14:11 -0600926sub connectionComment
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500927{
928 my $conn = shift;
929 my $comment = "$conn->{SOURCE} ->\n$conn->{DEST_PARENT}";
930 return $comment;
931}
932
Matt Spinler7d381e12016-09-27 14:27:24 -0500933
934#Prints a list of nodes at the same indent level
935# $f = file handle
936# $level = indent level (0,1,etc)
937# @nodes = array of node hashes to print, where the
938# key for the hash is the name of the node
Matt Spinler889343f2017-01-30 14:14:11 -0600939sub printNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500940{
941 my ($f, $level, @nodes) = @_;
942
943 foreach my $n (@nodes) {
944 my %node = %$n;
945
946 foreach my $name (sort keys %node) {
947 my %n = %{ $node{$name} };
948 printNode($f, $level, $name, %n);
949 }
950 }
951}
952
953
954#Print a single node and its children
955# $f = file handle
956# $level = indent level (0,1,etc)
957# $name = the name of the node - shows up as:
958# name { ...
959# %vals = The contents of the node, with the following options:
960# if the key is:
961# - 'DTSI_INCLUDE', then value gets turned into a #include
Matt Spinler995f2a22016-09-30 13:07:31 -0500962# - 'COMMENT', then value gets turned into a // comment
Matt Spinler74909132016-10-07 13:52:19 -0500963# - 'ZERO_LENGTH_PROPERTY' then value gets turned into: value;
Matt Spinler7d381e12016-09-27 14:27:24 -0500964#
965# If the value is:
966# - a hash - then that hash gets turned into a child node
967# where the key is the name of the child node
Matt Spinler995f2a22016-09-30 13:07:31 -0500968# - an array of hashes indicates an array of child nodes
Matt Spinler889343f2017-01-30 14:14:11 -0600969sub printNode
Matt Spinler7d381e12016-09-27 14:27:24 -0500970{
971 my ($f, $level, $name, %vals) = @_;
972 my $include = "";
973
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500974 #No reason to print an empty node
975 if (!keys %vals) {
976 return;
977 }
978
Matt Spinler7d381e12016-09-27 14:27:24 -0500979 if ($level == 0) {
980 $name = "&".$name;
981 }
982
Matt Spinler995f2a22016-09-30 13:07:31 -0500983 print $f "\n";
984
985 if (exists $vals{COMMENT}) {
986 my @lines = split('\n', $vals{COMMENT});
987 foreach my $l (@lines) {
988 print $f indent($level) . "// $l\n";
989 }
990 }
991
992 print $f indent($level) . "$name {\n";
Matt Spinler7d381e12016-09-27 14:27:24 -0500993
Matt Spinler74909132016-10-07 13:52:19 -0500994 #First print properties, then includes, then subnodes
995
996 #Print Properties
Matt Spinler7d381e12016-09-27 14:27:24 -0500997 foreach my $v (sort keys %vals) {
998
Matt Spinler995f2a22016-09-30 13:07:31 -0500999 next if ($v eq "COMMENT");
Matt Spinler74909132016-10-07 13:52:19 -05001000 next if ($v eq "DTSI_INCLUDE");
1001 next if (ref($vals{$v}) eq "HASH");
1002 next if (ref($vals{$v}) eq "ARRAY");
Matt Spinler995f2a22016-09-30 13:07:31 -05001003
Matt Spinler74909132016-10-07 13:52:19 -05001004 if ($vals{$v} ne ZERO_LENGTH_PROPERTY) {
1005 printProperty($f, $level+1, $v, $vals{$v});
Matt Spinler7d381e12016-09-27 14:27:24 -05001006 }
Matt Spinler74909132016-10-07 13:52:19 -05001007 else {
1008 printZeroLengthProperty($f, $level+1, $v);
1009 }
1010 }
1011
1012 #Print Includes
1013 foreach my $v (sort keys %vals) {
1014
1015 if ($v eq "DTSI_INCLUDE") {
1016 #print 1 include per line
1017 my @incs = split(',', $vals{$v});
1018 foreach my $i (@incs) {
1019 print $f qq(#include "$i";\n);
1020 }
1021 }
1022 }
1023
1024 #Print Nodes
1025 foreach my $v (sort keys %vals) {
1026
1027 if (ref($vals{$v}) eq "HASH") {
Matt Spinler7d381e12016-09-27 14:27:24 -05001028 printNode($f, $level+1, $v, %{$vals{$v}});
1029 }
Matt Spinler995f2a22016-09-30 13:07:31 -05001030 #An array of nested nodes
1031 elsif (ref($vals{$v}) eq "ARRAY") {
1032 my @array = @{$vals{$v}};
1033 &printNodes($f, $level+1, @array);
1034 }
Matt Spinler7d381e12016-09-27 14:27:24 -05001035 }
1036
1037 print $f indent($level) . "};\n";
1038}
1039
1040
1041#Prints a comma separated list of properties.
1042#e.g. a = "b, c, d";
1043# $f = file handle
1044# $level = indent level (0,1,etc)
1045# $name = name of property
1046# @vals = list of property values
Matt Spinler889343f2017-01-30 14:14:11 -06001047sub printPropertyList
Matt Spinler7d381e12016-09-27 14:27:24 -05001048{
1049 my ($f, $level, $name, @vals) = @_;
1050
1051 print $f indent($level) . "$name = ";
1052
1053 for (my $i = 0;$i < scalar @vals; $i++) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001054 print $f qq("$vals[$i]");
Matt Spinler7d381e12016-09-27 14:27:24 -05001055 if ($i < (scalar(@vals) - 1)) {
1056 print $f ", ";
1057 }
1058 }
1059 print $f ";\n"
1060}
1061
1062
1063#Prints a single property. e.g. a = "b";
1064# $f = file handle
1065# $level = indent level (0,1,etc)
1066# $name = name of property
1067# @vals = property values
Matt Spinler889343f2017-01-30 14:14:11 -06001068sub printProperty
Matt Spinler7d381e12016-09-27 14:27:24 -05001069{
1070 my ($f, $level, $name, $val) = @_;
Matt Spinler30b461c2016-10-10 16:50:07 -05001071 my $quoteChar = qq(");
Matt Spinler23d47c22016-10-04 12:31:21 -05001072
Matt Spinler30b461c2016-10-10 16:50:07 -05001073 $val = convertReference($val);
Matt Spinler23d47c22016-10-04 12:31:21 -05001074
1075 #properties with < > or single word aliases don't need quotes
1076 if (($val =~ /<.*>/) || ($val =~ /^&\w+$/)) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001077 $quoteChar = "";
Matt Spinler23d47c22016-10-04 12:31:21 -05001078 }
1079
Matt Spinler30b461c2016-10-10 16:50:07 -05001080 print $f indent($level) . "$name = $quoteChar$val$quoteChar;\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001081}
1082
1083
Matt Spinler30b461c2016-10-10 16:50:07 -05001084#Prints a zero length property e.g. some-property;
Matt Spinler7d381e12016-09-27 14:27:24 -05001085# $f = file handle
1086# $level = indent level (0,1,etc)
1087# $name = name of property
Matt Spinler889343f2017-01-30 14:14:11 -06001088sub printZeroLengthProperty
Matt Spinler7d381e12016-09-27 14:27:24 -05001089{
1090 my ($f, $level, $name) = @_;
1091 print $f indent($level) . "$name;\n";
1092}
1093
1094
Matt Spinler30b461c2016-10-10 16:50:07 -05001095#Replace '(ref)' with '&'.
Matt Spinler7d381e12016-09-27 14:27:24 -05001096#Needed because Serverwiz doesn't properly escape '&'s in the XML,
Matt Spinler30b461c2016-10-10 16:50:07 -05001097#so the '(ref)' string is used to represent the reference
Matt Spinler7d381e12016-09-27 14:27:24 -05001098#specifier instead of '&'.
Matt Spinler889343f2017-01-30 14:14:11 -06001099sub convertReference
1100{
Matt Spinler7d381e12016-09-27 14:27:24 -05001101 my $val = shift;
Matt Spinler30b461c2016-10-10 16:50:07 -05001102 $val =~ s/\(ref\)/&/g;
Matt Spinler7d381e12016-09-27 14:27:24 -05001103 return $val
1104}
1105
1106
Matt Spinler7d381e12016-09-27 14:27:24 -05001107#Prints the device tree version line.
1108# $f = file handle
Matt Spinler889343f2017-01-30 14:14:11 -06001109sub printVersion
Matt Spinler7d381e12016-09-27 14:27:24 -05001110{
1111 my $f = shift;
1112 print $f VERSION."\n"
1113}
1114
1115
1116#Prints the #include line for pulling in an include file.
Matt Spinler30b461c2016-10-10 16:50:07 -05001117#The files to include come from the configuration file.
Matt Spinler7d381e12016-09-27 14:27:24 -05001118# $f = file handle
Matt Spinler30b461c2016-10-10 16:50:07 -05001119# $type = include type
Matt Spinler889343f2017-01-30 14:14:11 -06001120sub printIncludes
Matt Spinler7d381e12016-09-27 14:27:24 -05001121{
Matt Spinler30b461c2016-10-10 16:50:07 -05001122 my ($f, $type) = @_;
1123 my @includes = getIncludes($type);
Matt Spinler7d381e12016-09-27 14:27:24 -05001124
1125 foreach my $i (@includes) {
1126 #if a .dtsi, gets " ", otherwise < >
1127 if ($i =~ /\.dtsi$/) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001128 $i = qq("$i");
Matt Spinler7d381e12016-09-27 14:27:24 -05001129 }
1130 else {
Matt Spinler30b461c2016-10-10 16:50:07 -05001131 $i = "<$i>";
Matt Spinler7d381e12016-09-27 14:27:24 -05001132 }
Matt Spinler30b461c2016-10-10 16:50:07 -05001133 print $f "#include $i\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001134 }
1135}
1136
1137
Matt Spinler30b461c2016-10-10 16:50:07 -05001138#Returns an array of include files found in the config file
1139#for the type specified.
1140# $type = the include type, which is the section name in the
1141# YAML configuration file.
Matt Spinler889343f2017-01-30 14:14:11 -06001142sub getIncludes
Matt Spinler7d381e12016-09-27 14:27:24 -05001143{
Matt Spinler30b461c2016-10-10 16:50:07 -05001144 my $type = shift;
Matt Spinler7d381e12016-09-27 14:27:24 -05001145 my @includes;
1146
Matt Spinler30b461c2016-10-10 16:50:07 -05001147 #The config file may have a section but no includes
1148 #listed in it, which is OK.
1149 if ((exists $g_configuration{includes}{$type}) &&
1150 (ref($g_configuration{includes}{$type}) eq "ARRAY")) {
Matt Spinler7d381e12016-09-27 14:27:24 -05001151
Matt Spinler30b461c2016-10-10 16:50:07 -05001152 @includes = @{$g_configuration{includes}{$type}};
Matt Spinler7d381e12016-09-27 14:27:24 -05001153 }
1154
1155 return @includes;
1156}
1157
Matt Spinler30b461c2016-10-10 16:50:07 -05001158
Matt Spinler74909132016-10-07 13:52:19 -05001159#Appends the first value of the 'reg' property
1160#passed in to the name passed in to create the
1161#full name for the node
1162# $name = node name that will be appended to
1163# $reg = the reg property values
Matt Spinler889343f2017-01-30 14:14:11 -06001164sub makeNodeName
Matt Spinler74909132016-10-07 13:52:19 -05001165{
1166 my ($name, $reg) = @_;
1167
1168 $reg =~ s/<//g;
1169 $reg =~ s/>//g;
1170 my @vals = split(' ', $reg);
1171
1172 if (scalar @vals > 0) {
1173 $vals[0] =~ s/0x//;
1174 $name .= "@" . lc $vals[0];
1175 }
1176
1177 return $name;
1178}
1179
Matt Spinler7d381e12016-09-27 14:27:24 -05001180
1181#Prints the root node starting bracket.
1182# $f = file handle
Matt Spinler889343f2017-01-30 14:14:11 -06001183sub printRootNodeStart
1184{
Matt Spinler7d381e12016-09-27 14:27:24 -05001185 my $f = shift;
Matt Spinler30b461c2016-10-10 16:50:07 -05001186 print $f qq(/ {\n);
Matt Spinler7d381e12016-09-27 14:27:24 -05001187}
1188
1189
1190#Prints the root node ending bracket.
1191# $f = file handle
1192# $level = indent level (0,1,etc)
Matt Spinler889343f2017-01-30 14:14:11 -06001193sub printRootNodeEnd
1194{
Matt Spinler7d381e12016-09-27 14:27:24 -05001195 my ($f, $level) = @_;
Matt Spinler30b461c2016-10-10 16:50:07 -05001196 print $f indent($level).qq(};\n);
Matt Spinler7d381e12016-09-27 14:27:24 -05001197}
1198
1199
1200#Returns a string that can be used to indent based on the
1201#level passed in. Each level is an additional 4 spaces.
1202# $level = indent level (0,1,etc)
Matt Spinler889343f2017-01-30 14:14:11 -06001203sub indent
1204{
Matt Spinler7d381e12016-09-27 14:27:24 -05001205 my $level = shift;
1206 return ' ' x ($level * 4);
1207}
1208
1209
Matt Spinler7d381e12016-09-27 14:27:24 -05001210sub printUsage
1211{
Matt Spinler30b461c2016-10-10 16:50:07 -05001212 print "gen_devtree.pl -x [XML filename] -y [yaml config file] " .
1213 "-o [output filename]\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001214 exit(1);
1215}