blob: 9ba335d9f6f1d784a856452c619383e5685520b6 [file] [log] [blame]
Matt Spinler7d381e12016-09-27 14:27:24 -05001#!/usr/bin/env perl
2
Matt Spinler5cb5f4e2017-01-31 14:17:09 -06003#Generates an OpenBMC device tree syntax file from the machine
4#readable workbook. It relies on the fact that the dts include
5#file for the BMC chip itself contains the BMC chip specific
6#data, so this can just generate the system specific data.
7#It also makes use of a YAML configuration file to contain
8#settings that are outside the scope of the MRW.
9#
10#This doesn't attempt to support every possible type of device
11#tree node from the start. Support may need to be added as newer
12#systems come along that make use of different features.
Matt Spinler7d381e12016-09-27 14:27:24 -050013
14use strict;
Matt Spinler889343f2017-01-30 14:14:11 -060015use warnings;
Matt Spinler7d381e12016-09-27 14:27:24 -050016use XML::Simple;
17use mrw::Targets;
Matt Spinlere2bf4392017-01-30 13:16:28 -060018use mrw::Util;
Matt Spinler7d381e12016-09-27 14:27:24 -050019use Getopt::Long;
Matt Spinler30b461c2016-10-10 16:50:07 -050020use YAML::Tiny qw(LoadFile);
21use Scalar::Util qw(looks_like_number);
Matt Spinler7d381e12016-09-27 14:27:24 -050022
Matt Spinler30b461c2016-10-10 16:50:07 -050023use constant {
24 VERSION => "/dts-v1/;",
25 ZERO_LENGTH_PROPERTY => "zero_length_property",
26 PRE_ROOT_INCLUDES => "pre-root-node",
27 ROOT_INCLUDES => "root-node",
Matt Spinler6d391252017-01-31 13:46:06 -060028 POST_ROOT_INCLUDES => "post-root-node",
29 HOST_SPI_FLASH_MEM_REGION_NODE_LABEL => "flash_memory"
Matt Spinler30b461c2016-10-10 16:50:07 -050030};
Matt Spinler74909132016-10-07 13:52:19 -050031
Matt Spinler7d381e12016-09-27 14:27:24 -050032
33my $serverwizFile;
Matt Spinler30b461c2016-10-10 16:50:07 -050034my $configFile;
Matt Spinler7d381e12016-09-27 14:27:24 -050035my $outputFile;
36my $debug;
37
38GetOptions("x=s" => \$serverwizFile,
Matt Spinler30b461c2016-10-10 16:50:07 -050039 "y=s" => \$configFile,
Matt Spinler7d381e12016-09-27 14:27:24 -050040 "o=s" => \$outputFile,
41 "d" => \$debug)
42or printUsage();
43
Matt Spinler30b461c2016-10-10 16:50:07 -050044if ((not defined $serverwizFile) || (not defined $outputFile) ||
45 (not defined $configFile)) {
Matt Spinler7d381e12016-09-27 14:27:24 -050046 printUsage();
47}
48
Matt Spinler908e1822017-01-31 14:02:58 -060049my $g_pnorNodeName = undef;
Matt Spinler30b461c2016-10-10 16:50:07 -050050my %g_configuration = %{ LoadFile($configFile) };
51
Matt Spinler7d381e12016-09-27 14:27:24 -050052my $g_targetObj = Targets->new;
53$g_targetObj->loadXML($serverwizFile);
54
Matt Spinler74909132016-10-07 13:52:19 -050055my ($g_bmc, $g_bmcModel, $g_bmcMfgr, $g_systemName);
56setGlobalAttributes();
Matt Spinler7d381e12016-09-27 14:27:24 -050057
Matt Spinler30b461c2016-10-10 16:50:07 -050058my $g_i2cBusAdjust = 0;
59getI2CBusAdjust();
Matt Spinler7d381e12016-09-27 14:27:24 -050060
61open (my $f, ">$outputFile") or die "Could not open $outputFile\n";
62
63printVersion($f);
Matt Spinler30b461c2016-10-10 16:50:07 -050064printIncludes($f, PRE_ROOT_INCLUDES);
Matt Spinler7d381e12016-09-27 14:27:24 -050065printRootNodeStart($f);
66
67printPropertyList($f, 1, "model", getSystemBMCModel());
Matt Spinler7d381e12016-09-27 14:27:24 -050068printPropertyList($f, 1, "compatible", getBMCCompatibles());
Matt Spinler995f2a22016-09-30 13:07:31 -050069
Matt Spinler23d47c22016-10-04 12:31:21 -050070printNode($f, 1, "aliases", getAliases());
Matt Spinler7d381e12016-09-27 14:27:24 -050071printNode($f, 1, "chosen", getChosen());
Matt Spinler30b461c2016-10-10 16:50:07 -050072printNode($f, 1, "memory", getBmcMemory());
Matt Spinler6d391252017-01-31 13:46:06 -060073printNode($f, 1, "reserved-memory", getReservedMemory());
Matt Spinler7d381e12016-09-27 14:27:24 -050074
Matt Spinler995f2a22016-09-30 13:07:31 -050075printNode($f, 1, "leds", getLEDNode());
76
Matt Spinler70a80ab2017-02-13 14:31:22 -060077printNode($f, 1, "fsi-master", getFSINode());
78
Matt Spinler30b461c2016-10-10 16:50:07 -050079printIncludes($f, ROOT_INCLUDES);
80
Matt Spinler7d381e12016-09-27 14:27:24 -050081printRootNodeEnd($f, 0);
82
Matt Spinler96f8f242016-11-28 16:26:57 -060083printNodes($f, 0, getBMCFlashNodes());
Matt Spinler96f8f242016-11-28 16:26:57 -060084printNodes($f, 0, getOtherFlashNodes());
85
Matt Spinler908e1822017-01-31 14:02:58 -060086printNode($f, 0, "lpc_ctrl", getLPCNode());
87printNode($f, 0, "mbox", getMBoxNode());
88
Matt Spinler995f2a22016-09-30 13:07:31 -050089printNodes($f, 0, getUARTNodes());
Matt Spinler41dcb622017-01-31 14:55:19 -060090printNodes($f, 0, getMacNodes());
91
92printNodes($f, 0, getI2CNodes());
Matt Spinler7d381e12016-09-27 14:27:24 -050093printNodes($f, 0, getVuartNodes());
94
Matt Spinler30b461c2016-10-10 16:50:07 -050095printIncludes($f, POST_ROOT_INCLUDES);
96
Matt Spinler7d381e12016-09-27 14:27:24 -050097close $f;
98exit 0;
99
100
Matt Spinler74909132016-10-07 13:52:19 -0500101#Finds the values for these globals:
102# $g_bmc, $g_bmcModel, $g_bmcMfgr, $g_systemName
Matt Spinler889343f2017-01-30 14:14:11 -0600103sub setGlobalAttributes
Matt Spinler74909132016-10-07 13:52:19 -0500104{
Matt Spinlere2bf4392017-01-30 13:16:28 -0600105 $g_bmc = Util::getBMCTarget($g_targetObj);
Matt Spinler74909132016-10-07 13:52:19 -0500106
107 if ($g_targetObj->isBadAttribute($g_bmc, "MODEL")) {
108 die "The MODEL attribute on $g_bmc is missing or empty.\n";
109 }
110 $g_bmcModel = $g_targetObj->getAttribute($g_bmc, "MODEL");
111
112 if ($g_targetObj->isBadAttribute($g_bmc, "MANUFACTURER")) {
113 die "The MANUFACTURER attribute on $g_bmc is missing or empty.\n";
114 }
115 $g_bmcMfgr = $g_targetObj->getAttribute($g_bmc, "MANUFACTURER");
116
117 $g_systemName = $g_targetObj->getSystemName();
118 if (length($g_systemName) == 0) {
119 die "The SYSTEM_NAME attribute is not set on the system target.\n";
120 }
121}
122
123
Matt Spinler23d47c22016-10-04 12:31:21 -0500124#Returns a hash that represents the 'aliases' node.
125#Will look like:
126# aliases {
127# name1 = &val1;
128# name2 = &val2;
129# ...
130# }
Matt Spinler889343f2017-01-30 14:14:11 -0600131sub getAliases
Matt Spinler23d47c22016-10-04 12:31:21 -0500132{
133 my %aliases;
Matt Spinler23d47c22016-10-04 12:31:21 -0500134
Matt Spinler30b461c2016-10-10 16:50:07 -0500135 #Get the info from the config file
Matt Spinler23d47c22016-10-04 12:31:21 -0500136
Matt Spinler30b461c2016-10-10 16:50:07 -0500137 if ((not exists $g_configuration{aliases}) ||
138 (keys %{$g_configuration{aliases}} == 0)) {
139 print "WARNING: Missing or empty 'aliases' section in config file.\n";
140 return %aliases;
141 }
142 %aliases = %{ $g_configuration{aliases} };
143
144 #add a & reference if one is missing
145 foreach my $a (keys %aliases) {
146 if (($aliases{$a} !~ /^&/) && ($aliases{$a} !~ /^\(ref\)/)) {
147 $aliases{$a} = "(ref)$aliases{$a}";
Matt Spinler23d47c22016-10-04 12:31:21 -0500148 }
149 }
150
151 return %aliases;
152}
153
Matt Spinler7d381e12016-09-27 14:27:24 -0500154
155#Return a hash that represents the 'chosen' node
Matt Spinler995f2a22016-09-30 13:07:31 -0500156#Will look like:
157# chosen {
158# stdout-path = ...
159# bootargs = ...
160# }
Matt Spinler889343f2017-01-30 14:14:11 -0600161sub getChosen
Matt Spinler7d381e12016-09-27 14:27:24 -0500162{
Matt Spinler7d381e12016-09-27 14:27:24 -0500163 my %chosen;
Matt Spinler30b461c2016-10-10 16:50:07 -0500164 my @allowed = qw(bootargs stdin-path stdout-path);
165
166 #Get the info from the config file
167
168 if (not exists $g_configuration{chosen}) {
169 die "ERROR: Missing 'chosen' section in config file.\n";
170 }
171 %chosen = %{ $g_configuration{chosen} };
172
Matt Spinler30b461c2016-10-10 16:50:07 -0500173 foreach my $key (keys %chosen) {
Matt Spinler30b461c2016-10-10 16:50:07 -0500174
Matt Spinler28fb1a92017-01-30 12:54:10 -0600175 #Check for allowed entries. Empty is OK.
176 if (!grep(/^$key$/, @allowed)) {
Matt Spinler30b461c2016-10-10 16:50:07 -0500177 die "Invalid entry $key in 'chosen' section in config file\n";
178 }
Matt Spinler28fb1a92017-01-30 12:54:10 -0600179
180 #stdout-path and stdin-path can use aliases, which will look like
181 #(alias)uart5 in the yaml. Change to (ref)uart5 so it will be
182 #converted to a '&' later.
183 $chosen{$key} =~ s/\(alias\)/\(ref\)/g;
Matt Spinler30b461c2016-10-10 16:50:07 -0500184 }
185
Matt Spinler7d381e12016-09-27 14:27:24 -0500186 return %chosen;
187}
188
189
Matt Spinler30b461c2016-10-10 16:50:07 -0500190#Return a hash that represents the 'memory' node.
Matt Spinler995f2a22016-09-30 13:07:31 -0500191#Will look like:
Matt Spinler30b461c2016-10-10 16:50:07 -0500192# memory {
193# reg = < base size >
194# }
Matt Spinler889343f2017-01-30 14:14:11 -0600195sub getBmcMemory
Matt Spinler30b461c2016-10-10 16:50:07 -0500196{
197 my %memory;
198
199 #Get the info from the config file
200
201 if (not exists $g_configuration{memory}) {
202 die "ERROR: Missing 'memory' section in config file.\n";
203 }
204
205 if ((not exists $g_configuration{memory}{base}) ||
206 ($g_configuration{memory}{base} !~ /0x/)) {
207 die "ERROR: The base entry in the memory section in the config " .
208 "file is either missing or invalid.\n";
209 }
210
211 if ((not exists $g_configuration{memory}{size}) ||
212 ($g_configuration{memory}{size} !~ /0x/)) {
213 die "ERROR: The size entry in the memory section in the config " .
214 "file is either missing or invalid.\n";
215 }
216
217 #Future: could do more validation on the actual values
218
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600219 addRegProp(\%memory,
220 $g_configuration{memory}{base},
221 $g_configuration{memory}{size});
Matt Spinler30b461c2016-10-10 16:50:07 -0500222
223 return %memory;
224}
225
226
Matt Spinler6d391252017-01-31 13:46:06 -0600227#Returns a hash that represents the 'reserved-memory' node.
228#This currently only supports the memory region for the LPC
229#host spi flash mailbox. Will look like:
230# reserved-memory {
231# #address-cells = <1>;
232# #size-cells = <1>;
233# ranges;
234#
235# flash_memory: region@94000000 {
236# no-map;
237# reg = <0x94000000 0x04000000>;
238# };
239# };
240sub getReservedMemory
241{
242 my %memory;
243
244 if (not exists $g_configuration{"lpc-host-spi-flash-mailbox"}) {
245 return %memory;
246 }
247
248 $memory{"#address-cells"} = "<1>";
249 $memory{"#size-cells"} = "<1>";
250 $memory{ranges} = ZERO_LENGTH_PROPERTY;
251
252 #Get the sub node that contains the address range
253 my ($name, $node) = getHostSpiFlashMboxRegion();
254 $memory{$name} = { %$node };
255
256 return %memory;
257}
258
259
260#Returns a hash that represents a child node of the
261#reserved-memory node which contains the address range
262#that the host spi flash is mapped to.
263sub getHostSpiFlashMboxRegion
264{
265 my %node;
266
267 $node{"no-map"} = ZERO_LENGTH_PROPERTY;
268
269 #This node needs a label the LPC node can refer to.
270 $node{NODE_LABEL} = HOST_SPI_FLASH_MEM_REGION_NODE_LABEL;
271
272 #Get the memory region's base address and size from the config file
273 if (not exists $g_configuration{"lpc-host-spi-flash-mailbox"}
274 {"bmc-address-range"}{base}) {
275 die "Could not find lpc-host-spi-flash-mailbox base " .
276 "address in config file\n";
277 }
278
279 my $base = $g_configuration{"lpc-host-spi-flash-mailbox"}
280 {"bmc-address-range"}{base};
281 #Allow 1 hex value, up to 4B
282 if ($base !~ /^0x[0-9a-fA-F]{1,8}$/) {
283 die "lpc-host-spi-flash-mailbox base address $base is invalid\n";
284 }
285
286 if (not exists $g_configuration{"lpc-host-spi-flash-mailbox"}
287 {"bmc-address-range"}{size}) {
288 die "Could not find lpc-host-spi-flash-mailbox address size " .
289 "in config file\n";
290 }
291
292 my $size = $g_configuration{"lpc-host-spi-flash-mailbox"}
293 {"bmc-address-range"}{size};
294 if ($size !~ /^0x[0-9a-fA-F]{1,8}$/) {
295 die "lpc-host-spi-flash-mailbox address range size " .
296 "$size is invalid\n";
297 }
298
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600299 addRegProp(\%node, $base, $size);
Matt Spinler6d391252017-01-31 13:46:06 -0600300 my $name = makeNodeName("region", $node{reg});
301
302 return ($name, \%node);
303}
304
305
Matt Spinler25d60bb2016-10-31 15:16:03 -0500306#Returns an array of hashes representing the device tree nodes for
307#the BMC flash. These nodes are BMC model specific because different
308#models can have different device drivers.
Matt Spinler889343f2017-01-30 14:14:11 -0600309sub getBMCFlashNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500310{
Matt Spinler25d60bb2016-10-31 15:16:03 -0500311 my @nodes;
312
313 if ($g_bmcModel eq "AST2500") {
314 my %node = getAST2500BMCSPIFlashNode();
315 push @nodes, { %node };
316 }
317 else {
318 die "ERROR: No BMC SPI flash support yet for BMC model $g_bmcModel\n";
319 }
320
321 return @nodes;
322}
323
324
325#Returns a hash that represents the BMC SPI flash(es) by finding the SPI
326#connections that come from the unit tagged as BMC_CODE. The code also
327#looks in the config file for any additional properties to add. Supports
328#the hardware where the same SPI master unit can be wired to more than 1
329#flash (a chip select line is used to switch between them.) This is
330#specific to the ASPEED AST2500 hardware and device driver.
331#Will look like:
332# fmc {
333# status = "okay"
334# flash@0 {
335# ...
336# };
337# flash@1 {
338# ...
339# };
Matt Spinler889343f2017-01-30 14:14:11 -0600340sub getAST2500BMCSPIFlashNode
Matt Spinler25d60bb2016-10-31 15:16:03 -0500341{
342 my %bmcFlash;
343 my $chipSelect = 0;
344 my $lastUnit = "";
345
Matt Spinler18d5f572016-11-15 15:25:45 -0600346 my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH");
Matt Spinler25d60bb2016-10-31 15:16:03 -0500347
348 if ($connections eq "") {
349 die "ERROR: No BMC SPI flashes found connected to the BMC\n";
350 }
351
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600352 statusOK(\%{$bmcFlash{fmc}});
Matt Spinler25d60bb2016-10-31 15:16:03 -0500353
354 foreach my $spi (@{$connections->{CONN}}) {
355
356 #Looking for spi-masters with a function of 'BMC_CODE'.
357 #It's possible there are multiple flash chips here.
358 if (!$g_targetObj->isBadAttribute($spi->{SOURCE}, "SPI_FUNCTION")) {
359
360 my $function = $g_targetObj->getAttribute($spi->{SOURCE},
361 "SPI_FUNCTION");
362 if ($function eq "BMC_CODE") {
363
364 my $flashName = "flash@".$chipSelect;
365
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500366 $bmcFlash{fmc}{$flashName}{COMMENT} = connectionComment($spi);
Matt Spinler25d60bb2016-10-31 15:16:03 -0500367
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600368 statusOK(\%{$bmcFlash{fmc}{$flashName}});
Matt Spinler25d60bb2016-10-31 15:16:03 -0500369
370 #Add in anything specified in the config file for this chip.
371 addBMCFlashConfigProperties(\%{$bmcFlash{fmc}{$flashName}},
372 $chipSelect);
373
374 #The code currently only supports the config where a chip
375 #select line is used to select between possibly multiple
376 #flash chips attached to the same SPI pins/unit. So we
377 #need to make sure if there are multiple chips found, that
378 #they are off of the same master unit.
379 if ($lastUnit eq "") {
380 $lastUnit = $spi->{SOURCE};
381 }
382 else {
383 if ($lastUnit ne $spi->{SOURCE}) {
384 die "ERROR: Currently only 1 spi-master unit is " .
385 "supported for BMC flash connections."
386 }
387 }
388
389 #Since we don't need anything chip select specific from the
390 #XML, we can just assign our own chip selects.
391 $chipSelect++;
392 }
393 }
394 }
395
396 if ($chipSelect == 0) {
397 die "ERROR: Didn't find any BMC flash chips connected";
398 }
399
400 return %bmcFlash;
401}
402
403
404#Looks in the bmc-flash-config section in the config file for the
405#chip select passed in to add any additional properties to the BMC
406#flash node.
407# $node = hash reference to the flash node
408# $cs = the flash chip select value
Matt Spinler889343f2017-01-30 14:14:11 -0600409sub addBMCFlashConfigProperties
Matt Spinler25d60bb2016-10-31 15:16:03 -0500410{
411 my ($node, $cs) = @_;
412 my $section = "chip-select-$cs";
413
414 if (exists $g_configuration{"bmc-flash-config"}{$section}) {
415 foreach my $key (sort keys $g_configuration{"bmc-flash-config"}{$section}) {
416 $node->{$key} = $g_configuration{"bmc-flash-config"}{$section}{$key};
417 }
418 }
Matt Spinler995f2a22016-09-30 13:07:31 -0500419}
420
421
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500422#Returns an array of hashes representing the other flashes used by the
423#BMC besides the ones that hold the BMC code. This is BMC model specific
424#as different models can have different interfaces.
425#Typically, these are SPI flashes.
Matt Spinler889343f2017-01-30 14:14:11 -0600426sub getOtherFlashNodes
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500427{
428 my @nodes;
429
430 if ($g_bmcModel eq "AST2500") {
431 @nodes = getAST2500SpiFlashNodes();
432 }
433 else {
434 die "ERROR: No SPI flash support yet for BMC model $g_bmcModel\n";
435 }
436
437 return @nodes;
438}
439
440
441#Returns an array of hashes representing the SPI flashes in an
442#AST2500. These are for the SPI1 and SPI2 interfaces in the chip.
443#Each SPI master interface can support multiple flash chips. If
444#no hardware is connected to the interface, the node won't be present.
Matt Spinler889343f2017-01-30 14:14:11 -0600445sub getAST2500SpiFlashNodes
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500446{
447 my @nodes;
448
449 #The AST2500 has 2 SPI master units, 1 and 2.
450 my @units = (1, 2);
451
452 foreach my $unit (@units) {
453
Matt Spinler908e1822017-01-31 14:02:58 -0600454 my ($node, $foundPNOR) = getAST2500SpiMasterNode($unit);
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500455
Matt Spinler908e1822017-01-31 14:02:58 -0600456 if (keys %$node) {
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500457 my %spiNode;
458 my $nodeName = "spi$unit";
Matt Spinler908e1822017-01-31 14:02:58 -0600459 $spiNode{$nodeName} = { %$node };
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500460 push @nodes, { %spiNode };
Matt Spinler908e1822017-01-31 14:02:58 -0600461
462 #Save off the PNOR SPI node name for use by LPC node
463 if ($foundPNOR) {
464 $g_pnorNodeName = $nodeName;
465 }
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500466 }
467 }
468
469 return @nodes;
470}
471
472
473#Returns a hash that represents the device tree node for the SPI1
474#or SPI2 master interface on the AST2500. Each master can support
475#multiple chips by use of a chip select.
476#Will look like:
477# spi1 {
478# status = "okay";
479# flash@0 {
480# ...
481# };
482# };
483#
484# $spiNum = The SPI master unit number to use
Matt Spinler889343f2017-01-30 14:14:11 -0600485sub getAST2500SpiMasterNode
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500486{
487 my $spiNum = shift;
488 my %spiMaster;
489 my $chipSelect = 0;
Matt Spinler908e1822017-01-31 14:02:58 -0600490 my $foundPNOR = 0;
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500491
Matt Spinler18d5f572016-11-15 15:25:45 -0600492 my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH");
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500493
494 if ($connections eq "") {
495 return %spiMaster;
496 }
497
498 #Looking for spi-masters with a chip-unit of $spiNum
499 #It's possible there are multiple flash chips off the master
500 foreach my $spi (@{$connections->{CONN}}) {
501
502 my $unitNum = $g_targetObj->getAttribute($spi->{SOURCE},
503 "CHIP_UNIT");
504 if ($unitNum == $spiNum) {
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600505 statusOK(\%spiMaster);
Matt Spinler2efdcba2016-11-08 15:37:20 -0600506
507 #Add in any pinctrl properties. These would come from the parent
508 #of $spi{SOURCE}, which would be a unit-pingroup-bmc if the
509 #pins for this connection are multi-function.
510 addPinCtrlProps($g_targetObj->getTargetParent($spi->{SOURCE}),
511 \%spiMaster);
512
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500513 my $flashName = "flash@".$chipSelect;
514
515 $spiMaster{$flashName}{COMMENT} = connectionComment($spi);
516
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600517 statusOK(\%{$spiMaster{$flashName}});
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500518
Matt Spinler0eda4882016-11-30 15:20:11 -0600519 #AST2500 PNORs need a label
520 my $function = $g_targetObj->getAttribute($spi->{SOURCE},
521 "SPI_FUNCTION");
522 if ($function eq "PNOR") {
523 $spiMaster{$flashName}{label} = "pnor";
Matt Spinler908e1822017-01-31 14:02:58 -0600524 $foundPNOR = 1;
Matt Spinler0eda4882016-11-30 15:20:11 -0600525 }
526
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500527 $chipSelect++;
528 }
529 }
530
Matt Spinler908e1822017-01-31 14:02:58 -0600531 return (\%spiMaster, $foundPNOR);
532}
533
534
535#Returns a hash that represents the mbox node.
536#This node is used by the LPC mailbox device driver.
537#Only present if the LPC mailbox is enabled in the config file.
538#Node looks like:
539# &mbox {
540# status = "okay";
541# }
542sub getMBoxNode
543{
544 my %node;
545 if (exists $g_configuration{"lpc-host-spi-flash-mailbox"}) {
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600546 statusOK(\%node);
Matt Spinler908e1822017-01-31 14:02:58 -0600547 }
548
549 return %node;
550}
551
552
553#Returns a hash that represents the LPC node.
554#Only present if the LPC mailbox is enabled in the config file.
555#Node looks like:
556# &lpc_ctrl {
557# flash = <&spi1>;
558# memory-region = <&flash_memory>;
559# status = "okay";
560#};
561sub getLPCNode
562{
563 my %node;
564 if (exists $g_configuration{"lpc-host-spi-flash-mailbox"}) {
565
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600566 statusOK(\%node);
Matt Spinler908e1822017-01-31 14:02:58 -0600567
568 #Point to the reserved-memory region label
569 $node{"memory-region"} = "<(ref)" .
570 HOST_SPI_FLASH_MEM_REGION_NODE_LABEL . ">";
571
572 if (not defined $g_pnorNodeName) {
573 die "The PNOR SPI flash node cannot be found but is required " .
574 "if the LPC mailbox is enabled.\n";
575 }
576
577 $node{flash} = "<(ref)$g_pnorNodeName>";
578 }
579
580 return %node;
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500581}
582
583
Matt Spinler995f2a22016-09-30 13:07:31 -0500584#Returns a hash that represents the leds node by finding all of the
585#GPIO connections to LEDs.
586#Node will look like:
587# leds {
588# <ledname> {
589# gpios = &gpio ASPEED_GPIO(x, y) GPIO_ACTIVE_xxx>
590# };
591# <another ledname> {
592# ...
593# }
Matt Spinler889343f2017-01-30 14:14:11 -0600594sub getLEDNode
Matt Spinler995f2a22016-09-30 13:07:31 -0500595{
596 my %leds;
597
Matt Spinlereca7f062016-11-07 09:59:23 -0600598 $leds{compatible} = "gpio-leds";
Matt Spinler995f2a22016-09-30 13:07:31 -0500599
Matt Spinler18d5f572016-11-15 15:25:45 -0600600 my $connections = $g_targetObj->findConnections($g_bmc, "GPIO", "LED");
Matt Spinler995f2a22016-09-30 13:07:31 -0500601
602 if ($connections eq "") {
603 print "WARNING: No LEDs found connected to the BMC\n";
604 return %leds;
605 }
606
607 foreach my $gpio (@{$connections->{CONN}}) {
608 my %ledNode;
609
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500610 $ledNode{COMMENT} = connectionComment($gpio);
Matt Spinler995f2a22016-09-30 13:07:31 -0500611
612 #The node name will be the simplified LED name
613 my $name = $gpio->{DEST_PARENT};
614 $name =~ s/(-\d+$)//; #remove trailing position
615 $name =~ s/.*\///; #remove the front of the path
616
617 #For now only supports ASPEED.
618 if (uc($g_bmcMfgr) ne "ASPEED") {
619 die "ERROR: Unsupported BMC manufacturer $g_bmcMfgr\n";
620 }
621 my $num = $g_targetObj->getAttribute($gpio->{SOURCE}, "PIN_NUM");
622 my $macro = getAspeedGpioMacro($num);
623
624 #If it's active high or low
625 my $state = $g_targetObj->getAttribute($gpio->{DEST_PARENT}, "ON_STATE");
626 my $activeString = getGpioActiveString($state);
627
628 $ledNode{gpios} = "<&gpio $macro $activeString>";
629
630 $leds{$name} = { %ledNode };
631 }
632
633 return %leds;
634}
635
636
637#Returns a either GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW
638# $val = either a 1 or a 0 for active high or low
Matt Spinler889343f2017-01-30 14:14:11 -0600639sub getGpioActiveString
640{
Matt Spinler995f2a22016-09-30 13:07:31 -0500641 my $val = shift;
642
643 if ($val == 0) {
644 return "GPIO_ACTIVE_LOW";
645 }
646
647 return "GPIO_ACTIVE_HIGH";
648}
649
650
651#Turns a GPIO number into something like ASPEED_GPIO(A, 0) for the
652#ASPEED GPIO numbering scheme A[0-7] -> Z[0-7] and then starts at
653#AA[0-7] after that.
654# $num = the GPIO number
Matt Spinler889343f2017-01-30 14:14:11 -0600655sub getAspeedGpioMacro
656{
Matt Spinler995f2a22016-09-30 13:07:31 -0500657 my $num = shift;
658 my $char;
659 my $offset = $num % 8;
660 my $block = int($num / 8);
661
662 #If past Z, wraps to AA, AB, etc
663 if ((ord('A') + $block) > ord('Z')) {
664 #how far past Z?
665 $char = $block - (ord('Z') - ord('A'));
666
667 #Don't let it wrap twice
668 if ($char > (ord('Z') - ord('A') + 1)) {
669 die "ERROR: Invalid PIN_NUM value $num found for GPIO\n";
670 }
671
672 #start back at 'A' again, and convert to a character
673 $char = chr($char + ord('A') - 1);
674
675 #Add in a bonus 'A', to get something like AB
676 $char = "A".$char;
677 }
678 else {
679 $char = ord('A') + $block;
680 $char = chr($char);
681 }
682
683 return "ASPEED_GPIO($char, $offset)";
684}
685
686
Matt Spinler70a80ab2017-02-13 14:31:22 -0600687#Returns a hash that represents the OpenFSI device tree node.
688#This node defines the GPIOs used by FSI.
689#Node will look like:
690# fsi-master {
691# status = "okay";
692# compatible = "ibm,fsi-master-gpio", "ibm,fsi-master";
693# clock-gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>;
694# data-gpios = <&gpio ASPEED_GPIO(E, 0) GPIO_ACTIVE_HIGH>;
695# enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
696# mux-gpios = <&gpio ASPEED_GPIO(A, 6) GPIO_ACTIVE_HIGH>;
697# trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
698# };
699sub getFSINode
700{
701 my %node;
702 my $enabled = 0;
703
704 #For now only supports ASPEED because of the GPIO syntax.
705 if (uc($g_bmcMfgr) ne "ASPEED") {
706 die "ERROR: Unsupported BMC manufacturer $g_bmcMfgr in getFSINode\n";
707 }
708
709 #Check that OpenFSI is enabled in the config file.
710 if (exists $g_configuration{"enable-openfsi"}) {
711 if ($g_configuration{"enable-openfsi"} eq "true") {
712 $enabled = 1;
713 }
714 elsif (($g_configuration{"enable-openfsi"} ne "true") &&
715 ($g_configuration{"enable-openfsi"} ne "false")) {
716 die "Invalid enable-openfsi config file value: " .
717 $g_configuration{"enable-openfsi"} . "\n";
718 }
719 }
720
721 return %node unless ($enabled == 1);
722
723 #In the MRW there is an fsi_bit_bang logical part that connects to the
724 #BMC's 5 FSI related GPIOs. This part then has an FSI master unit that
725 #would connect to the P9's FSI slave (though we don't check that).
726
727 #Find the specific GPIOs by the fsi_bit_bang slave
728 #unit that they're connected to. Some are optional.
729 my %fsiGpios = ("fsi_bit_bang.fsi_clk" =>
730 {
731 name => "clock-gpios",
732 gpio => undef,
733 required => 1
734 },
735 "fsi_bit_bang.fsi_dat" =>
736 {
737 name => "data-gpios",
738 gpio => undef,
739 required => 1
740 },
741 "fsi_bit_bang.fsi_mux" =>
742 {
743 name => "mux-gpios",
744 gpio => undef
745 },
746 "fsi_bit_bang.fsi_enable" =>
747 {
748 name => "enable-gpios",
749 gpio => undef
750 },
751 "fsi_bit_bang.fsi_trans" =>
752 {
753 name => "trans-gpios",
754 gpio => undef
755 }
756 );
757
758 my $connections = $g_targetObj->findConnections($g_bmc, "GPIO");
759 if ($connections eq "") {
760 die "No GPIO connections found in getFSINode\n";
761 }
762
763 for my $gpio (@{$connections->{CONN}}) {
764
765 #Check if the destination's slave unit is in our list.
766 my $slaveUnit = $g_targetObj->getInstanceName($gpio->{DEST});
767
768 if (exists $fsiGpios{$slaveUnit}) {
769 my $num = $g_targetObj->getAttribute($gpio->{SOURCE}, "PIN_NUM");
770 $fsiGpios{$slaveUnit}{gpio} = getAspeedGpioMacro($num);
771 }
772 }
773
774 statusOK(\%node);
775
776 push @{$node{compatible}}, "ibm,fsi-master", "ibm,fsi-master-gpio";
777
778 while (my ($key, $hash) = each(%fsiGpios)) {
779 if (not defined $hash->{gpio}) {
780 if (exists $hash->{required}) {
781 die "Missing connection for FSI GPIO $key\n";
782 }
783 }
784 else {
785 $node{$hash->{name}} = "<&gpio $hash->{gpio} GPIO_ACTIVE_HIGH>";
786 }
787 }
788
789 return %node;
790}
791
792
Matt Spinler995f2a22016-09-30 13:07:31 -0500793#Returns a list of hashes that represent the UART nodes on the BMC by
794#finding the UART connections.
795#Nodes will look like:
796# &uartX {
797# status = "okay"
798# }
Matt Spinler889343f2017-01-30 14:14:11 -0600799sub getUARTNodes
Matt Spinler995f2a22016-09-30 13:07:31 -0500800{
801 my @nodes;
802
Matt Spinler23d47c22016-10-04 12:31:21 -0500803 #Using U750 for legacy MRW reasons
Matt Spinler18d5f572016-11-15 15:25:45 -0600804 my $connections = $g_targetObj->findConnections($g_bmc, "U750");
Matt Spinler995f2a22016-09-30 13:07:31 -0500805
806 if ($connections eq "") {
807 print "WARNING: No UART buses found connected to the BMC\n";
808 return @nodes;
809 }
810
811 foreach my $uart (@{$connections->{CONN}}) {
812 my %node;
813
814 my $num = $g_targetObj->getAttribute($uart->{SOURCE}, "CHIP_UNIT");
815 my $name = "uart$num";
816
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600817 statusOK(\%{$node{$name}});
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500818 $node{$name}{COMMENT} = connectionComment($uart);
Matt Spinler995f2a22016-09-30 13:07:31 -0500819
Matt Spinler2efdcba2016-11-08 15:37:20 -0600820 #Add in any pinctrl properties. These would come from the parent
821 #of $uart{SOURCE}, which would be a unit-pingroup-bmc if the
822 #pins for this connection are multi-function.
823 addPinCtrlProps($g_targetObj->getTargetParent($uart->{SOURCE}),
824 \%{$node{$name}});
825
Matt Spinler995f2a22016-09-30 13:07:31 -0500826 push @nodes, { %node };
827 }
828
Matt Spinler7d381e12016-09-27 14:27:24 -0500829 return @nodes;
830}
831
832
Matt Spinler995f2a22016-09-30 13:07:31 -0500833#Returns a list of hashes that represent the MAC (ethernet) nodes on the BMC
834#by finding the connections of type ETHERNET.
835#Nodes will look like:
836# &macX {
837# ...
838# }
Matt Spinler889343f2017-01-30 14:14:11 -0600839sub getMacNodes
Matt Spinler995f2a22016-09-30 13:07:31 -0500840{
841 my @nodes;
842
Matt Spinler18d5f572016-11-15 15:25:45 -0600843 my $connections = $g_targetObj->findConnections($g_bmc, "ETHERNET");
Matt Spinler995f2a22016-09-30 13:07:31 -0500844
845 if ($connections eq "") {
846 print "WARNING: No ethernet buses found connected to the BMC\n";
847 return @nodes;
848 }
849
850 foreach my $eth (@{$connections->{CONN}}) {
851 my %node;
852
853 my $num = $g_targetObj->getAttribute($eth->{SOURCE}, "CHIP_UNIT");
854 my $ncsi = $g_targetObj->getAttribute($eth->{SOURCE}, "NCSI_MODE");
855 my $hwChecksum = $g_targetObj->getAttribute($eth->{SOURCE},
856 "USE_HW_CHECKSUM");
857
858 my $name = "mac$num";
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600859 statusOK(\%{$node{$name}});
Matt Spinler995f2a22016-09-30 13:07:31 -0500860
861 if ($ncsi == 1) {
Matt Spinler74909132016-10-07 13:52:19 -0500862 $node{$name}{"use-ncsi"} = ZERO_LENGTH_PROPERTY;
Matt Spinler995f2a22016-09-30 13:07:31 -0500863 }
864 if ($hwChecksum == 0) {
Matt Spinler74909132016-10-07 13:52:19 -0500865 $node{$name}{"no-hw-checksum"} = ZERO_LENGTH_PROPERTY;
Matt Spinler995f2a22016-09-30 13:07:31 -0500866 }
867
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500868 $node{$name}{COMMENT} = connectionComment($eth);
Matt Spinler995f2a22016-09-30 13:07:31 -0500869
Matt Spinler2efdcba2016-11-08 15:37:20 -0600870 #Add in any pinctrl properties. These would come from the parent
871 #of $eth{SOURCE}, which would be a unit-pingroup-bmc if the
872 #pins for this connection are multi-function.
873 addPinCtrlProps($g_targetObj->getTargetParent($eth->{SOURCE}),
874 \%{$node{$name}});
875
Matt Spinler995f2a22016-09-30 13:07:31 -0500876 push @nodes, { %node };
877 }
878
879 return @nodes;
880}
881
882
883#Returns a list of hashes that represent the virtual UART nodes
884#Node will look like:
885# &vuart {
886# status = "okay"
887# }
Matt Spinler889343f2017-01-30 14:14:11 -0600888sub getVuartNodes
Matt Spinler7d381e12016-09-27 14:27:24 -0500889{
890 my @nodes;
891 my %node;
892
893 #For now, enable 1 node all the time.
Matt Spinler995f2a22016-09-30 13:07:31 -0500894 #TBD if this needs to be fixed
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600895 statusOK(\%{$node{vuart}});
Matt Spinler7d381e12016-09-27 14:27:24 -0500896
897 push @nodes, { %node };
898
899 return @nodes;
900}
901
Matt Spinler74909132016-10-07 13:52:19 -0500902#Returns a list of hashes that represent the I2C device nodes.
903#There is 1 parent node for each bus, which then have subnodes
904#for each device on that bus. If a bus doesn't have any
905#attached devices, it doesn't need to show up.
906#The nodes will look like:
907# &i2c0 {
908# status = "okay"
909# device1@addr { (addr = 7 bit I2C address)
910# reg = <addr>
911# compatible = ...
912# ...
913# }
914# device2@addr {
915# reg = <addr>
916# ...
917# }
918# }
919# &i2c1 {
920# ...
921# }
Matt Spinler889343f2017-01-30 14:14:11 -0600922sub getI2CNodes
Matt Spinler74909132016-10-07 13:52:19 -0500923{
924 my @nodes;
925 my %busNodes;
926
Matt Spinler18d5f572016-11-15 15:25:45 -0600927 my $connections = $g_targetObj->findConnections($g_bmc, "I2C");
Matt Spinler74909132016-10-07 13:52:19 -0500928
929 if ($connections eq "") {
930 print "WARNING: No I2C buses found connected to the BMC\n";
931 return @nodes;
932 }
933
934 foreach my $i2c (@{$connections->{CONN}}) {
935
936 my %deviceNode, my $deviceName;
937
Matt Spinlerc0dff8a2016-11-02 15:47:30 -0500938 $deviceNode{COMMENT} = connectionComment($i2c);
Matt Spinler74909132016-10-07 13:52:19 -0500939
940 $deviceName = lc $i2c->{DEST_PARENT};
941 $deviceName =~ s/-\d+$//; #remove trailing position
942 $deviceName =~ s/.*\///; #remove the front of the path
943
944 #Get the I2C address
945 my $i2cAddress = $g_targetObj->getAttribute($i2c->{DEST}, "I2C_ADDRESS");
946 $i2cAddress = hex($i2cAddress);
947 if ($i2cAddress == 0) {
948 die "ERROR: Missing I2C address on $i2c->{DEST}\n";
949 }
950
951 #Put it in the format we want to print it in
Deepak Kodihallidaa65832017-02-22 04:36:36 -0600952 $i2cAddress = Util::adjustI2CAddress($i2cAddress);
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600953 addRegProp(\%deviceNode, $i2cAddress);
Matt Spinler74909132016-10-07 13:52:19 -0500954
955 $deviceName = makeNodeName($deviceName, $deviceNode{reg});
956
957 #Get the I2C bus number
958 if ($g_targetObj->isBadAttribute($i2c->{SOURCE},
959 "I2C_PORT")) {
960 die "ERROR: I2C_PORT attribute in $i2c->{DEST_PARENT} " .
961 "is either missing or empty.\n";
962 }
963
964 my $busNum = $g_targetObj->getAttribute($i2c->{SOURCE}, "I2C_PORT");
965 if ($busNum =~ /0x/i) {
966 $busNum = hex($busNum);
967 }
968
969 #Convert the number to the Linux numbering scheme.
Matt Spinler30b461c2016-10-10 16:50:07 -0500970 $busNum += $g_i2cBusAdjust;
Matt Spinler74909132016-10-07 13:52:19 -0500971
972 #Get the compatible property
973 if ($g_targetObj->isBadAttribute($i2c->{DEST_PARENT},
974 "BMC_DT_COMPATIBLE")) {
975 die "ERROR: BMC_DT_COMPATIBLE attribute in $i2c->{DEST_PARENT} " .
976 "is either missing or empty.\n";
977 }
978
979 $deviceNode{compatible} = $g_targetObj->getAttribute(
980 $i2c->{DEST_PARENT},
981 "BMC_DT_COMPATIBLE");
982
983 #Get any other part specific properties, where the property
984 #names are actually defined in the XML.
985 my %props = getPartDefinedDTProperties($i2c->{DEST_PARENT});
986 foreach my $prop (sort keys %props) {
987 $deviceNode{$prop} = $props{$prop};
988 }
989
990 #busNodeName is the hash twice so when we loop
991 #below it doesn't get lost
992 my $busNodeName = "i2c$busNum";
Matt Spinler9ac5cbe2017-01-31 14:33:25 -0600993 statusOK(\%{$busNodes{$busNodeName}{$busNodeName}});
Matt Spinler74909132016-10-07 13:52:19 -0500994 $busNodes{$busNodeName}{$busNodeName}{$deviceName} = { %deviceNode };
Matt Spinler2efdcba2016-11-08 15:37:20 -0600995
996 #Add in any pinctrl properties. These would come from the parent
997 #of $i2c{SOURCE}, which would be a unit-pingroup-bmc if the
998 #pins for this connection are multi-function.
999 addPinCtrlProps($g_targetObj->getTargetParent($i2c->{SOURCE}),
1000 \%{$busNodes{$busNodeName}{$busNodeName}});
Matt Spinler74909132016-10-07 13:52:19 -05001001 }
1002
1003 #Each bus gets its own hash entry in the array
1004 for my $b (sort keys %busNodes) {
1005 push @nodes, { %{$busNodes{$b}} };
1006 }
1007
1008 return @nodes;
1009}
1010
1011
1012#Returns a hash of property names and values that should be stored in
1013#the device tree node for this device. The names of the properties and
1014#the attributes to find their values in are stored in the
1015#BMC_DT_ATTR_NAMES attribute in the chip.
1016# $chip = the chip target
Matt Spinler889343f2017-01-30 14:14:11 -06001017sub getPartDefinedDTProperties
Matt Spinler74909132016-10-07 13:52:19 -05001018{
1019 my $chip = shift;
1020 my %props;
1021
1022 if ($g_targetObj->isBadAttribute($chip, "BMC_DT_ATTR_NAMES")) {
1023 return %props;
1024 }
1025
1026 my $attr = $g_targetObj->getAttribute($chip, "BMC_DT_ATTR_NAMES");
1027 $attr =~ s/\s//g;
1028 my @names = split(',', $attr);
1029
1030 #There can be up to 4 entries in this attribute
1031 for (my $i = 0; $i < scalar @names; $i += 2) {
1032
1033 #$names[$i] holds the name of the attribute.
1034 #$names[$i+1] holds the name of the property to store its value in.
1035 if (($names[$i] ne "NA") && ($names[$i] ne "")) {
1036
1037 my $val = $g_targetObj->getAttribute($chip, $names[$i]);
1038
1039 #if the value is empty, assume it's for a standalone property,
1040 #which gets turned into: some-property;
1041 if ($val eq "") {
1042 $props{$names[$i+1]} = ZERO_LENGTH_PROPERTY;
1043 }
1044 else {
1045 $props{$names[$i+1]} = "<$val>";
1046 }
1047 }
1048 }
1049
1050 return %props;
1051}
1052
1053
Matt Spinler30b461c2016-10-10 16:50:07 -05001054#Sets the global $g_i2cBusAdjust from the configuration file.
Matt Spinler889343f2017-01-30 14:14:11 -06001055sub getI2CBusAdjust
Matt Spinler74909132016-10-07 13:52:19 -05001056{
Matt Spinler30b461c2016-10-10 16:50:07 -05001057 if (exists $g_configuration{"i2c-bus-adjust"}) {
Matt Spinler74909132016-10-07 13:52:19 -05001058
Matt Spinler30b461c2016-10-10 16:50:07 -05001059 $g_i2cBusAdjust = $g_configuration{"i2c-bus-adjust"};
Matt Spinler74909132016-10-07 13:52:19 -05001060
Matt Spinler30b461c2016-10-10 16:50:07 -05001061 if (!looks_like_number($g_i2cBusAdjust)) {
1062 die "ERROR: Invalid i2c-bus-adjust value $g_i2cBusAdjust " .
1063 "found in config file.\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001064 }
1065 }
Matt Spinler30b461c2016-10-10 16:50:07 -05001066 else {
1067 $g_i2cBusAdjust = 0;
1068 print "WARNING: No I2C Bus number adjustment done " .
1069 "for this system.\n";
1070 }
Matt Spinler7d381e12016-09-27 14:27:24 -05001071}
1072
1073
Matt Spinler2efdcba2016-11-08 15:37:20 -06001074
1075#Adds two pinctrl properties to the device node hash passed in,
1076#if specified in the MRW. Pin Control refers to a mechanism for
1077#Linux to know which function of a multi-function pin to configure.
1078#For example, a pin could either be configured to be a GPIO, or
1079#an I2C clock line. The pin function depends on board wiring,
1080#so is known by the MRW.
1081# $target = the target to get the BMC_DT_PINCTRL_FUNCTS attribute from
1082# $node = a hash reference to the device tree node to add the properties to
Matt Spinler889343f2017-01-30 14:14:11 -06001083sub addPinCtrlProps
Matt Spinler2efdcba2016-11-08 15:37:20 -06001084{
1085 my ($target, $node) = @_;
1086
1087 if (!$g_targetObj->isBadAttribute($target, "BMC_DT_PINCTRL_FUNCS")) {
1088 my $attr = $g_targetObj->getAttribute($target,
1089 "BMC_DT_PINCTRL_FUNCS");
1090
1091 my $pinCtrl0Prop = makePinCtrl0PropValue($attr);
1092 if ($pinCtrl0Prop ne "") {
1093 $node->{"pinctrl-names"} = "default";
1094 $node->{"pinctrl-0"} = $pinCtrl0Prop;
1095 }
1096 }
1097}
1098
1099
1100#Constructs the pinctrl-0 property value based on the
1101#BMC_DT_PINCTRL_FUNCS attribute passed in.
1102# $attr = BMC_DT_PINCTRL_FUNCS attribute value, which is an array
Matt Spinler889343f2017-01-30 14:14:11 -06001103sub makePinCtrl0PropValue
Matt Spinler2efdcba2016-11-08 15:37:20 -06001104{
1105 my $attr = shift;
1106 my @entries;
1107 my $value = "";
1108
1109 $attr =~ s/\s//g;
1110 my @funcs = split(',', $attr);
1111 foreach my $func (@funcs) {
1112 if (($func ne "NA") && ($func ne "")) {
1113 push @entries, $func;
1114 }
1115 }
1116
1117 #<&pinctrl_funcA_default &pinctrl_funcB_default ...>
1118 if (scalar @entries) {
1119 $value = "<";
1120 foreach my $entry (@entries) {
1121 $value .= "&pinctrl_".$entry."_default ";
1122 }
1123 $value =~ s/\s$//; #Remove the trailing space
1124 $value .= ">";
1125 }
1126
1127 return $value;
1128}
1129
1130
Matt Spinler7d381e12016-09-27 14:27:24 -05001131#Returns a list of compatible fields for the BMC itself.
Matt Spinler889343f2017-01-30 14:14:11 -06001132sub getBMCCompatibles
Matt Spinler7d381e12016-09-27 14:27:24 -05001133{
1134 my @compats;
1135
Matt Spinler23d47c22016-10-04 12:31:21 -05001136 #1st entry: <system mfgr>,<system name>-bmc
1137 #2nd entry: <bmc mfgr>,<bmc model>
Matt Spinler7d381e12016-09-27 14:27:24 -05001138
Matt Spinler23d47c22016-10-04 12:31:21 -05001139 foreach my $target (sort keys %{ $g_targetObj->getAllTargets() }) {
1140 if ($g_targetObj->getType($target) eq "SYS") {
1141 my $mfgr = $g_targetObj->getAttribute($target, "MANUFACTURER");
1142 push @compats, lc "$mfgr,$g_systemName-bmc";
1143 last;
1144 }
Matt Spinler7d381e12016-09-27 14:27:24 -05001145 }
1146
1147 push @compats, lc($g_bmcMfgr).",".lc($g_bmcModel);
1148
1149 return @compats;
1150}
1151
1152
1153#Returns a string for the system's BMC model property
Matt Spinler889343f2017-01-30 14:14:11 -06001154sub getSystemBMCModel
Matt Spinler7d381e12016-09-27 14:27:24 -05001155{
Matt Spinler995f2a22016-09-30 13:07:31 -05001156 #'<System> BMC'
Matt Spinler7d381e12016-09-27 14:27:24 -05001157 my $sys = lc $g_systemName;
1158 $sys = uc(substr($sys, 0, 1)) . substr($sys, 1);
1159
1160 return $sys . " BMC";
1161}
1162
Matt Spinlerc0dff8a2016-11-02 15:47:30 -05001163#Create the comment that will show up in the device tree
1164#for a connection. In the output, will look like:
1165# // sourceUnit ->
1166# // destChip
1167#
1168# $conn = The connection hash reference
Matt Spinler889343f2017-01-30 14:14:11 -06001169sub connectionComment
Matt Spinlerc0dff8a2016-11-02 15:47:30 -05001170{
1171 my $conn = shift;
1172 my $comment = "$conn->{SOURCE} ->\n$conn->{DEST_PARENT}";
1173 return $comment;
1174}
1175
Matt Spinler7d381e12016-09-27 14:27:24 -05001176
1177#Prints a list of nodes at the same indent level
1178# $f = file handle
1179# $level = indent level (0,1,etc)
1180# @nodes = array of node hashes to print, where the
1181# key for the hash is the name of the node
Matt Spinler889343f2017-01-30 14:14:11 -06001182sub printNodes
Matt Spinler7d381e12016-09-27 14:27:24 -05001183{
1184 my ($f, $level, @nodes) = @_;
1185
1186 foreach my $n (@nodes) {
1187 my %node = %$n;
1188
1189 foreach my $name (sort keys %node) {
1190 my %n = %{ $node{$name} };
1191 printNode($f, $level, $name, %n);
1192 }
1193 }
1194}
1195
1196
1197#Print a single node and its children
1198# $f = file handle
1199# $level = indent level (0,1,etc)
1200# $name = the name of the node - shows up as:
1201# name { ...
1202# %vals = The contents of the node, with the following options:
1203# if the key is:
1204# - 'DTSI_INCLUDE', then value gets turned into a #include
Matt Spinler995f2a22016-09-30 13:07:31 -05001205# - 'COMMENT', then value gets turned into a // comment
Matt Spinler74909132016-10-07 13:52:19 -05001206# - 'ZERO_LENGTH_PROPERTY' then value gets turned into: value;
Matt Spinler7d381e12016-09-27 14:27:24 -05001207#
1208# If the value is:
1209# - a hash - then that hash gets turned into a child node
1210# where the key is the name of the child node
Matt Spinler70a80ab2017-02-13 14:31:22 -06001211# - an array - will print a property list, like: "a", "b"
Matt Spinler889343f2017-01-30 14:14:11 -06001212sub printNode
Matt Spinler7d381e12016-09-27 14:27:24 -05001213{
1214 my ($f, $level, $name, %vals) = @_;
1215 my $include = "";
1216
Matt Spinlerc0dff8a2016-11-02 15:47:30 -05001217 #No reason to print an empty node
1218 if (!keys %vals) {
1219 return;
1220 }
1221
Matt Spinler7d381e12016-09-27 14:27:24 -05001222 if ($level == 0) {
1223 $name = "&".$name;
1224 }
1225
Matt Spinler995f2a22016-09-30 13:07:31 -05001226 print $f "\n";
1227
1228 if (exists $vals{COMMENT}) {
1229 my @lines = split('\n', $vals{COMMENT});
1230 foreach my $l (@lines) {
1231 print $f indent($level) . "// $l\n";
1232 }
1233 }
1234
Matt Spinler6d391252017-01-31 13:46:06 -06001235 #The node can have a label, which looks like:
1236 #label : name {
1237 my $label = "";
1238 if (exists $vals{NODE_LABEL}) {
1239 $label = $vals{NODE_LABEL} . ": ";
1240 }
1241
1242 print $f indent($level) . $label . "$name {\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001243
Matt Spinler74909132016-10-07 13:52:19 -05001244 #First print properties, then includes, then subnodes
1245
1246 #Print Properties
Matt Spinler7d381e12016-09-27 14:27:24 -05001247 foreach my $v (sort keys %vals) {
1248
Matt Spinler995f2a22016-09-30 13:07:31 -05001249 next if ($v eq "COMMENT");
Matt Spinler74909132016-10-07 13:52:19 -05001250 next if ($v eq "DTSI_INCLUDE");
Matt Spinler6d391252017-01-31 13:46:06 -06001251 next if ($v eq "NODE_LABEL");
Matt Spinler74909132016-10-07 13:52:19 -05001252 next if (ref($vals{$v}) eq "HASH");
Matt Spinler995f2a22016-09-30 13:07:31 -05001253
Matt Spinler70a80ab2017-02-13 14:31:22 -06001254 if (ref($vals{$v}) eq "ARRAY") {
1255 printPropertyList($f, $level+1, $v, @{$vals{$v}});
1256 }
1257 elsif ($vals{$v} ne ZERO_LENGTH_PROPERTY) {
Matt Spinler74909132016-10-07 13:52:19 -05001258 printProperty($f, $level+1, $v, $vals{$v});
Matt Spinler7d381e12016-09-27 14:27:24 -05001259 }
Matt Spinler74909132016-10-07 13:52:19 -05001260 else {
1261 printZeroLengthProperty($f, $level+1, $v);
1262 }
1263 }
1264
1265 #Print Includes
1266 foreach my $v (sort keys %vals) {
1267
1268 if ($v eq "DTSI_INCLUDE") {
1269 #print 1 include per line
1270 my @incs = split(',', $vals{$v});
1271 foreach my $i (@incs) {
Matt Spinler41dcb622017-01-31 14:55:19 -06001272 print $f qq(#include "$i"\n);
Matt Spinler74909132016-10-07 13:52:19 -05001273 }
1274 }
1275 }
1276
1277 #Print Nodes
1278 foreach my $v (sort keys %vals) {
1279
1280 if (ref($vals{$v}) eq "HASH") {
Matt Spinler7d381e12016-09-27 14:27:24 -05001281 printNode($f, $level+1, $v, %{$vals{$v}});
1282 }
Matt Spinler7d381e12016-09-27 14:27:24 -05001283 }
1284
1285 print $f indent($level) . "};\n";
1286}
1287
1288
1289#Prints a comma separated list of properties.
1290#e.g. a = "b, c, d";
1291# $f = file handle
1292# $level = indent level (0,1,etc)
1293# $name = name of property
1294# @vals = list of property values
Matt Spinler889343f2017-01-30 14:14:11 -06001295sub printPropertyList
Matt Spinler7d381e12016-09-27 14:27:24 -05001296{
1297 my ($f, $level, $name, @vals) = @_;
1298
1299 print $f indent($level) . "$name = ";
1300
1301 for (my $i = 0;$i < scalar @vals; $i++) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001302 print $f qq("$vals[$i]");
Matt Spinler7d381e12016-09-27 14:27:24 -05001303 if ($i < (scalar(@vals) - 1)) {
1304 print $f ", ";
1305 }
1306 }
1307 print $f ";\n"
1308}
1309
1310
1311#Prints a single property. e.g. a = "b";
1312# $f = file handle
1313# $level = indent level (0,1,etc)
1314# $name = name of property
1315# @vals = property values
Matt Spinler889343f2017-01-30 14:14:11 -06001316sub printProperty
Matt Spinler7d381e12016-09-27 14:27:24 -05001317{
1318 my ($f, $level, $name, $val) = @_;
Matt Spinler30b461c2016-10-10 16:50:07 -05001319 my $quoteChar = qq(");
Matt Spinler23d47c22016-10-04 12:31:21 -05001320
Matt Spinler30b461c2016-10-10 16:50:07 -05001321 $val = convertReference($val);
Matt Spinler23d47c22016-10-04 12:31:21 -05001322
1323 #properties with < > or single word aliases don't need quotes
1324 if (($val =~ /<.*>/) || ($val =~ /^&\w+$/)) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001325 $quoteChar = "";
Matt Spinler23d47c22016-10-04 12:31:21 -05001326 }
1327
Matt Spinler30b461c2016-10-10 16:50:07 -05001328 print $f indent($level) . "$name = $quoteChar$val$quoteChar;\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001329}
1330
1331
Matt Spinler30b461c2016-10-10 16:50:07 -05001332#Prints a zero length property e.g. some-property;
Matt Spinler7d381e12016-09-27 14:27:24 -05001333# $f = file handle
1334# $level = indent level (0,1,etc)
1335# $name = name of property
Matt Spinler889343f2017-01-30 14:14:11 -06001336sub printZeroLengthProperty
Matt Spinler7d381e12016-09-27 14:27:24 -05001337{
1338 my ($f, $level, $name) = @_;
1339 print $f indent($level) . "$name;\n";
1340}
1341
1342
Matt Spinler30b461c2016-10-10 16:50:07 -05001343#Replace '(ref)' with '&'.
Matt Spinler7d381e12016-09-27 14:27:24 -05001344#Needed because Serverwiz doesn't properly escape '&'s in the XML,
Matt Spinler30b461c2016-10-10 16:50:07 -05001345#so the '(ref)' string is used to represent the reference
Matt Spinler7d381e12016-09-27 14:27:24 -05001346#specifier instead of '&'.
Matt Spinler889343f2017-01-30 14:14:11 -06001347sub convertReference
1348{
Matt Spinler7d381e12016-09-27 14:27:24 -05001349 my $val = shift;
Matt Spinler30b461c2016-10-10 16:50:07 -05001350 $val =~ s/\(ref\)/&/g;
Matt Spinler7d381e12016-09-27 14:27:24 -05001351 return $val
1352}
1353
1354
Matt Spinler7d381e12016-09-27 14:27:24 -05001355#Prints the device tree version line.
1356# $f = file handle
Matt Spinler889343f2017-01-30 14:14:11 -06001357sub printVersion
Matt Spinler7d381e12016-09-27 14:27:24 -05001358{
1359 my $f = shift;
1360 print $f VERSION."\n"
1361}
1362
1363
1364#Prints the #include line for pulling in an include file.
Matt Spinler30b461c2016-10-10 16:50:07 -05001365#The files to include come from the configuration file.
Matt Spinler7d381e12016-09-27 14:27:24 -05001366# $f = file handle
Matt Spinler30b461c2016-10-10 16:50:07 -05001367# $type = include type
Matt Spinler889343f2017-01-30 14:14:11 -06001368sub printIncludes
Matt Spinler7d381e12016-09-27 14:27:24 -05001369{
Matt Spinler30b461c2016-10-10 16:50:07 -05001370 my ($f, $type) = @_;
1371 my @includes = getIncludes($type);
Matt Spinler7d381e12016-09-27 14:27:24 -05001372
1373 foreach my $i (@includes) {
1374 #if a .dtsi, gets " ", otherwise < >
1375 if ($i =~ /\.dtsi$/) {
Matt Spinler30b461c2016-10-10 16:50:07 -05001376 $i = qq("$i");
Matt Spinler7d381e12016-09-27 14:27:24 -05001377 }
1378 else {
Matt Spinler30b461c2016-10-10 16:50:07 -05001379 $i = "<$i>";
Matt Spinler7d381e12016-09-27 14:27:24 -05001380 }
Matt Spinler30b461c2016-10-10 16:50:07 -05001381 print $f "#include $i\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001382 }
1383}
1384
1385
Matt Spinler30b461c2016-10-10 16:50:07 -05001386#Returns an array of include files found in the config file
1387#for the type specified.
1388# $type = the include type, which is the section name in the
1389# YAML configuration file.
Matt Spinler889343f2017-01-30 14:14:11 -06001390sub getIncludes
Matt Spinler7d381e12016-09-27 14:27:24 -05001391{
Matt Spinler30b461c2016-10-10 16:50:07 -05001392 my $type = shift;
Matt Spinler7d381e12016-09-27 14:27:24 -05001393 my @includes;
1394
Matt Spinler30b461c2016-10-10 16:50:07 -05001395 #The config file may have a section but no includes
1396 #listed in it, which is OK.
1397 if ((exists $g_configuration{includes}{$type}) &&
1398 (ref($g_configuration{includes}{$type}) eq "ARRAY")) {
Matt Spinler7d381e12016-09-27 14:27:24 -05001399
Matt Spinler30b461c2016-10-10 16:50:07 -05001400 @includes = @{$g_configuration{includes}{$type}};
Matt Spinler7d381e12016-09-27 14:27:24 -05001401 }
1402
1403 return @includes;
1404}
1405
Matt Spinler30b461c2016-10-10 16:50:07 -05001406
Matt Spinler74909132016-10-07 13:52:19 -05001407#Appends the first value of the 'reg' property
1408#passed in to the name passed in to create the
1409#full name for the node
1410# $name = node name that will be appended to
1411# $reg = the reg property values
Matt Spinler889343f2017-01-30 14:14:11 -06001412sub makeNodeName
Matt Spinler74909132016-10-07 13:52:19 -05001413{
1414 my ($name, $reg) = @_;
1415
1416 $reg =~ s/<//g;
1417 $reg =~ s/>//g;
1418 my @vals = split(' ', $reg);
1419
1420 if (scalar @vals > 0) {
1421 $vals[0] =~ s/0x//;
1422 $name .= "@" . lc $vals[0];
1423 }
1424
1425 return $name;
1426}
1427
Matt Spinler7d381e12016-09-27 14:27:24 -05001428
1429#Prints the root node starting bracket.
1430# $f = file handle
Matt Spinler889343f2017-01-30 14:14:11 -06001431sub printRootNodeStart
1432{
Matt Spinler7d381e12016-09-27 14:27:24 -05001433 my $f = shift;
Matt Spinler30b461c2016-10-10 16:50:07 -05001434 print $f qq(/ {\n);
Matt Spinler7d381e12016-09-27 14:27:24 -05001435}
1436
1437
1438#Prints the root node ending bracket.
1439# $f = file handle
1440# $level = indent level (0,1,etc)
Matt Spinler889343f2017-01-30 14:14:11 -06001441sub printRootNodeEnd
1442{
Matt Spinler7d381e12016-09-27 14:27:24 -05001443 my ($f, $level) = @_;
Matt Spinler30b461c2016-10-10 16:50:07 -05001444 print $f indent($level).qq(};\n);
Matt Spinler7d381e12016-09-27 14:27:24 -05001445}
1446
1447
1448#Returns a string that can be used to indent based on the
1449#level passed in. Each level is an additional 4 spaces.
1450# $level = indent level (0,1,etc)
Matt Spinler889343f2017-01-30 14:14:11 -06001451sub indent
1452{
Matt Spinler7d381e12016-09-27 14:27:24 -05001453 my $level = shift;
1454 return ' ' x ($level * 4);
1455}
1456
1457
Matt Spinler9ac5cbe2017-01-31 14:33:25 -06001458#Adds a {status} = "okay" element to the hash passed in.
1459# $node = reference to the hash to add element to
1460sub statusOK
1461{
1462 my $node = shift;
1463 $node->{status} = "okay";
1464}
1465
1466
1467#Adds the {reg} element to the hash passed in using the values
1468#passed in. Resulting value looks like: "<val1 val2 etc>"
1469# $node = reference to the hash to add element to
1470# @values = the values for the property. May be passed in one at
1471# a time and not as an array.
1472sub addRegProp
1473{
1474 my $node = shift;
1475 my @values = @_;
1476
1477 $node->{reg} = "<";
1478 for (my $i = 0; $i < scalar @values; $i++) {
1479 $node->{reg} .= $values[$i];
1480 if ($i < (scalar @values) - 1) {
1481 $node->{reg} .= " ";
1482 }
1483 }
1484 $node->{reg} .= ">";
1485}
1486
1487
Matt Spinler7d381e12016-09-27 14:27:24 -05001488sub printUsage
1489{
Matt Spinler30b461c2016-10-10 16:50:07 -05001490 print "gen_devtree.pl -x [XML filename] -y [yaml config file] " .
1491 "-o [output filename]\n";
Matt Spinler7d381e12016-09-27 14:27:24 -05001492 exit(1);
1493}