| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1 | #!/usr/bin/env perl | 
 | 2 |  | 
 | 3 | #Generates a BMC device tree syntax file from the machine | 
 | 4 | #readable workbook. | 
 | 5 |  | 
 | 6 | use strict; | 
 | 7 | use XML::Simple; | 
 | 8 | use mrw::Targets; | 
 | 9 | use Getopt::Long; | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 10 | use YAML::Tiny qw(LoadFile); | 
 | 11 | use Scalar::Util qw(looks_like_number); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 12 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 13 | use constant { | 
 | 14 |     VERSION => "/dts-v1/;", | 
 | 15 |     ZERO_LENGTH_PROPERTY => "zero_length_property", | 
 | 16 |     PRE_ROOT_INCLUDES => "pre-root-node", | 
 | 17 |     ROOT_INCLUDES => "root-node", | 
 | 18 |     POST_ROOT_INCLUDES => "post-root-node" | 
 | 19 | }; | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 20 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 21 |  | 
 | 22 | my $serverwizFile; | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 23 | my $configFile; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 24 | my $outputFile; | 
 | 25 | my $debug; | 
 | 26 |  | 
 | 27 | GetOptions("x=s" => \$serverwizFile, | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 28 |            "y=s" => \$configFile, | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 29 |            "o=s" => \$outputFile, | 
 | 30 |            "d" => \$debug) | 
 | 31 | or printUsage(); | 
 | 32 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 33 | if ((not defined $serverwizFile) || (not defined $outputFile) || | 
 | 34 |     (not defined $configFile)) { | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 35 |     printUsage(); | 
 | 36 | } | 
 | 37 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 38 | my %g_configuration = %{ LoadFile($configFile) }; | 
 | 39 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 40 | my $g_targetObj = Targets->new; | 
 | 41 | $g_targetObj->loadXML($serverwizFile); | 
 | 42 |  | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 43 | my ($g_bmc, $g_bmcModel, $g_bmcMfgr, $g_systemName); | 
 | 44 | setGlobalAttributes(); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 45 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 46 | my $g_i2cBusAdjust = 0; | 
 | 47 | getI2CBusAdjust(); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 48 |  | 
 | 49 | open (my $f, ">$outputFile") or die "Could not open $outputFile\n"; | 
 | 50 |  | 
 | 51 | printVersion($f); | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 52 | printIncludes($f, PRE_ROOT_INCLUDES); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 53 | printRootNodeStart($f); | 
 | 54 |  | 
 | 55 | printPropertyList($f, 1, "model", getSystemBMCModel()); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 56 | printPropertyList($f, 1, "compatible", getBMCCompatibles()); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 57 |  | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 58 | printNode($f, 1, "aliases", getAliases()); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 59 | printNode($f, 1, "chosen", getChosen()); | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 60 | printNode($f, 1, "memory", getBmcMemory()); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 61 |  | 
| Matt Spinler | 25d60bb | 2016-10-31 15:16:03 -0500 | [diff] [blame] | 62 | printNodes($f, 1, getBMCFlashNodes()); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 63 |  | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 64 | printNodes($f, 1, getOtherFlashNodes()); | 
 | 65 |  | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 66 | printNode($f, 1, "leds", getLEDNode()); | 
 | 67 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 68 | printIncludes($f, ROOT_INCLUDES); | 
 | 69 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 70 | printRootNodeEnd($f, 0); | 
 | 71 |  | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 72 | printNodes($f, 0, getI2CNodes()); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 73 | printNodes($f, 0, getMacNodes()); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 74 | printNodes($f, 0, getUARTNodes()); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 75 | printNodes($f, 0, getVuartNodes()); | 
 | 76 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 77 | printIncludes($f, POST_ROOT_INCLUDES); | 
 | 78 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 79 | close $f; | 
 | 80 | exit 0; | 
 | 81 |  | 
 | 82 |  | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 83 | #Finds the values for these globals: | 
 | 84 | # $g_bmc, $g_bmcModel, $g_bmcMfgr, $g_systemName | 
 | 85 | sub setGlobalAttributes() | 
 | 86 | { | 
 | 87 |     $g_bmc = getBMCTarget(); | 
 | 88 |     if (length($g_bmc) == 0) { | 
 | 89 |         die "Unable to find a BMC in this system\n"; | 
 | 90 |     } | 
 | 91 |  | 
 | 92 |     if ($g_targetObj->isBadAttribute($g_bmc, "MODEL")) { | 
 | 93 |         die "The MODEL attribute on $g_bmc is missing or empty.\n"; | 
 | 94 |     } | 
 | 95 |     $g_bmcModel = $g_targetObj->getAttribute($g_bmc, "MODEL"); | 
 | 96 |  | 
 | 97 |     if ($g_targetObj->isBadAttribute($g_bmc, "MANUFACTURER")) { | 
 | 98 |         die "The MANUFACTURER attribute on $g_bmc is missing or empty.\n"; | 
 | 99 |     } | 
 | 100 |     $g_bmcMfgr = $g_targetObj->getAttribute($g_bmc, "MANUFACTURER"); | 
 | 101 |  | 
 | 102 |     $g_systemName = $g_targetObj->getSystemName(); | 
 | 103 |     if (length($g_systemName) == 0) { | 
 | 104 |         die "The SYSTEM_NAME attribute is not set on the system target.\n"; | 
 | 105 |     } | 
 | 106 | } | 
 | 107 |  | 
 | 108 |  | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 109 | #Returns a hash that represents the 'aliases' node. | 
 | 110 | #Will look like: | 
 | 111 | #  aliases { | 
 | 112 | #    name1 = &val1; | 
 | 113 | #    name2 = &val2; | 
 | 114 | #    ... | 
 | 115 | #  } | 
 | 116 | sub getAliases() | 
 | 117 | { | 
 | 118 |     my %aliases; | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 119 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 120 |     #Get the info from the config file | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 121 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 122 |     if ((not exists $g_configuration{aliases}) || | 
 | 123 |         (keys %{$g_configuration{aliases}} == 0)) { | 
 | 124 |         print "WARNING:  Missing or empty 'aliases' section in config file.\n"; | 
 | 125 |         return %aliases; | 
 | 126 |     } | 
 | 127 |     %aliases = %{ $g_configuration{aliases} }; | 
 | 128 |  | 
 | 129 |     #add a & reference if one is missing | 
 | 130 |     foreach my $a (keys %aliases) { | 
 | 131 |         if (($aliases{$a} !~ /^&/) && ($aliases{$a} !~ /^\(ref\)/)) { | 
 | 132 |             $aliases{$a} = "(ref)$aliases{$a}"; | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 133 |         } | 
 | 134 |     } | 
 | 135 |  | 
 | 136 |     return %aliases; | 
 | 137 | } | 
 | 138 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 139 |  | 
 | 140 | #Return a hash that represents the 'chosen' node | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 141 | #Will look like: | 
 | 142 | #   chosen { | 
 | 143 | #      stdout-path = ... | 
 | 144 | #      bootargs = ... | 
 | 145 | #   } | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 146 | sub getChosen() | 
 | 147 | { | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 148 |     my %chosen; | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 149 |     my @allowed = qw(bootargs stdin-path stdout-path); | 
 | 150 |  | 
 | 151 |     #Get the info from the config file | 
 | 152 |  | 
 | 153 |     if (not exists $g_configuration{chosen}) { | 
 | 154 |         die "ERROR:  Missing 'chosen' section in config file.\n"; | 
 | 155 |     } | 
 | 156 |     %chosen = %{ $g_configuration{chosen} }; | 
 | 157 |  | 
 | 158 |     #Check for allowed entries.  Empty is OK. | 
 | 159 |     foreach my $key (keys %chosen) { | 
 | 160 |         my $found = 0; | 
 | 161 |         foreach my $good (@allowed) { | 
 | 162 |             if ($key eq $good) { | 
 | 163 |                 $found = 1; | 
 | 164 |             } | 
 | 165 |         } | 
 | 166 |  | 
 | 167 |         if ($found == 0) { | 
 | 168 |             die "Invalid entry $key in 'chosen' section in config file\n"; | 
 | 169 |         } | 
 | 170 |     } | 
 | 171 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 172 |     return %chosen; | 
 | 173 | } | 
 | 174 |  | 
 | 175 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 176 | #Return a hash that represents the 'memory' node. | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 177 | #Will look like: | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 178 | #  memory { | 
 | 179 | #     reg = < base size > | 
 | 180 | #  } | 
 | 181 | sub getBmcMemory() | 
 | 182 | { | 
 | 183 |     my %memory; | 
 | 184 |  | 
 | 185 |     #Get the info from the config file | 
 | 186 |  | 
 | 187 |     if (not exists $g_configuration{memory}) { | 
 | 188 |         die "ERROR:  Missing 'memory' section in config file.\n"; | 
 | 189 |     } | 
 | 190 |  | 
 | 191 |     if ((not exists $g_configuration{memory}{base}) || | 
 | 192 |         ($g_configuration{memory}{base} !~ /0x/)) { | 
 | 193 |         die "ERROR:  The base entry in the memory section in the config " . | 
 | 194 |             "file is either missing or invalid.\n"; | 
 | 195 |     } | 
 | 196 |  | 
 | 197 |     if ((not exists $g_configuration{memory}{size}) || | 
 | 198 |         ($g_configuration{memory}{size} !~ /0x/)) { | 
 | 199 |         die "ERROR:  The size entry in the memory section in the config " . | 
 | 200 |             "file is either missing or invalid.\n"; | 
 | 201 |     } | 
 | 202 |  | 
 | 203 |     #Future: could do more validation on the actual values | 
 | 204 |  | 
 | 205 |     $memory{reg} = "<$g_configuration{memory}{base} " . | 
 | 206 |                    "$g_configuration{memory}{size}>"; | 
 | 207 |  | 
 | 208 |     return %memory; | 
 | 209 | } | 
 | 210 |  | 
 | 211 |  | 
| Matt Spinler | 25d60bb | 2016-10-31 15:16:03 -0500 | [diff] [blame] | 212 | #Returns an array of hashes representing the device tree nodes for | 
 | 213 | #the BMC flash.  These nodes are BMC model specific because different | 
 | 214 | #models can have different device drivers. | 
 | 215 | sub getBMCFlashNodes() | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 216 | { | 
| Matt Spinler | 25d60bb | 2016-10-31 15:16:03 -0500 | [diff] [blame] | 217 |     my @nodes; | 
 | 218 |  | 
 | 219 |     if ($g_bmcModel eq "AST2500") { | 
 | 220 |         my %node = getAST2500BMCSPIFlashNode(); | 
 | 221 |         push @nodes, { %node }; | 
 | 222 |     } | 
 | 223 |     else { | 
 | 224 |         die "ERROR:  No BMC SPI flash support yet for BMC model $g_bmcModel\n"; | 
 | 225 |     } | 
 | 226 |  | 
 | 227 |     return @nodes; | 
 | 228 | } | 
 | 229 |  | 
 | 230 |  | 
 | 231 | #Returns a hash that represents the BMC SPI flash(es) by finding the SPI | 
 | 232 | #connections that come from the unit tagged as BMC_CODE.  The code also | 
 | 233 | #looks in the config file for any additional properties to add.  Supports | 
 | 234 | #the hardware where the same SPI master unit can be wired to more than 1 | 
 | 235 | #flash (a chip select line is used to switch between them.)  This is | 
 | 236 | #specific to the ASPEED AST2500 hardware and device driver. | 
 | 237 | #Will look like: | 
 | 238 | #  fmc { | 
 | 239 | #    status = "okay" | 
 | 240 | #    flash@0 { | 
 | 241 | #       ... | 
 | 242 | #    }; | 
 | 243 | #    flash@1 { | 
 | 244 | #       ... | 
 | 245 | #    }; | 
 | 246 | sub getAST2500BMCSPIFlashNode() | 
 | 247 | { | 
 | 248 |     my %bmcFlash; | 
 | 249 |     my $chipSelect = 0; | 
 | 250 |     my $lastUnit = ""; | 
 | 251 |  | 
| Matt Spinler | 18d5f57 | 2016-11-15 15:25:45 -0600 | [diff] [blame] | 252 |     my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH"); | 
| Matt Spinler | 25d60bb | 2016-10-31 15:16:03 -0500 | [diff] [blame] | 253 |  | 
 | 254 |     if ($connections eq "") { | 
 | 255 |         die "ERROR:  No BMC SPI flashes found connected to the BMC\n"; | 
 | 256 |     } | 
 | 257 |  | 
 | 258 |     $bmcFlash{fmc}{status} = "okay"; | 
 | 259 |  | 
 | 260 |     foreach my $spi (@{$connections->{CONN}}) { | 
 | 261 |  | 
 | 262 |         #Looking for spi-masters with a function of 'BMC_CODE'. | 
 | 263 |         #It's possible there are multiple flash chips here. | 
 | 264 |         if (!$g_targetObj->isBadAttribute($spi->{SOURCE}, "SPI_FUNCTION")) { | 
 | 265 |  | 
 | 266 |             my $function = $g_targetObj->getAttribute($spi->{SOURCE}, | 
 | 267 |                                                       "SPI_FUNCTION"); | 
 | 268 |             if ($function eq "BMC_CODE") { | 
 | 269 |  | 
 | 270 |                 my $flashName = "flash@".$chipSelect; | 
 | 271 |  | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 272 |                 $bmcFlash{fmc}{$flashName}{COMMENT} = connectionComment($spi); | 
| Matt Spinler | 25d60bb | 2016-10-31 15:16:03 -0500 | [diff] [blame] | 273 |  | 
 | 274 |                 $bmcFlash{fmc}{$flashName}{status} = "okay"; | 
 | 275 |  | 
 | 276 |                 #Add in anything specified in the config file for this chip. | 
 | 277 |                 addBMCFlashConfigProperties(\%{$bmcFlash{fmc}{$flashName}}, | 
 | 278 |                                             $chipSelect); | 
 | 279 |  | 
 | 280 |                 #The code currently only supports the config where a chip | 
 | 281 |                 #select line is used to select between possibly multiple | 
 | 282 |                 #flash chips attached to the same SPI pins/unit.  So we | 
 | 283 |                 #need to make sure if there are multiple chips found, that | 
 | 284 |                 #they are off of the same master unit. | 
 | 285 |                 if ($lastUnit eq "") { | 
 | 286 |                     $lastUnit = $spi->{SOURCE}; | 
 | 287 |                 } | 
 | 288 |                 else { | 
 | 289 |                     if ($lastUnit ne $spi->{SOURCE}) { | 
 | 290 |                         die "ERROR:  Currently only 1 spi-master unit is " . | 
 | 291 |                             "supported for BMC flash connections." | 
 | 292 |                     } | 
 | 293 |                 } | 
 | 294 |  | 
 | 295 |                 #Since we don't need anything chip select specific from the | 
 | 296 |                 #XML, we can just assign our own chip selects. | 
 | 297 |                 $chipSelect++; | 
 | 298 |             } | 
 | 299 |         } | 
 | 300 |     } | 
 | 301 |  | 
 | 302 |     if ($chipSelect == 0) { | 
 | 303 |         die "ERROR:  Didn't find any BMC flash chips connected"; | 
 | 304 |     } | 
 | 305 |  | 
 | 306 |     return %bmcFlash; | 
 | 307 | } | 
 | 308 |  | 
 | 309 |  | 
 | 310 | #Looks in the bmc-flash-config section in the config file for the | 
 | 311 | #chip select passed in to add any additional properties to the BMC | 
 | 312 | #flash node. | 
 | 313 | #  $node = hash reference to the flash node | 
 | 314 | #  $cs = the flash chip select value | 
 | 315 | sub addBMCFlashConfigProperties() | 
 | 316 | { | 
 | 317 |     my ($node, $cs) = @_; | 
 | 318 |     my $section = "chip-select-$cs"; | 
 | 319 |  | 
 | 320 |     if (exists $g_configuration{"bmc-flash-config"}{$section}) { | 
 | 321 |         foreach my $key (sort keys $g_configuration{"bmc-flash-config"}{$section}) { | 
 | 322 |             $node->{$key} = $g_configuration{"bmc-flash-config"}{$section}{$key}; | 
 | 323 |         } | 
 | 324 |     } | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 325 | } | 
 | 326 |  | 
 | 327 |  | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 328 | #Returns an array of hashes representing the other flashes used by the | 
 | 329 | #BMC besides the ones that hold the BMC code.  This is BMC model specific | 
 | 330 | #as different models can have different interfaces. | 
 | 331 | #Typically, these are SPI flashes. | 
 | 332 | sub getOtherFlashNodes() | 
 | 333 | { | 
 | 334 |     my @nodes; | 
 | 335 |  | 
 | 336 |     if ($g_bmcModel eq "AST2500") { | 
 | 337 |         @nodes = getAST2500SpiFlashNodes(); | 
 | 338 |     } | 
 | 339 |     else { | 
 | 340 |         die "ERROR:  No SPI flash support yet for BMC model $g_bmcModel\n"; | 
 | 341 |     } | 
 | 342 |  | 
 | 343 |     return @nodes; | 
 | 344 | } | 
 | 345 |  | 
 | 346 |  | 
 | 347 | #Returns an array of hashes representing the SPI flashes in an | 
 | 348 | #AST2500.  These are for the SPI1 and SPI2 interfaces in the chip. | 
 | 349 | #Each SPI master interface can support multiple flash chips.  If | 
 | 350 | #no hardware is connected to the interface, the node won't be present. | 
 | 351 | sub getAST2500SpiFlashNodes() | 
 | 352 | { | 
 | 353 |     my @nodes; | 
 | 354 |  | 
 | 355 |     #The AST2500 has 2 SPI master units, 1 and 2. | 
 | 356 |     my @units = (1, 2); | 
 | 357 |  | 
 | 358 |     foreach my $unit (@units) { | 
 | 359 |  | 
 | 360 |         my %node = getAST2500SpiMasterNode($unit); | 
 | 361 |  | 
 | 362 |         if (keys %node) { | 
 | 363 |             my %spiNode; | 
 | 364 |             my $nodeName = "spi$unit"; | 
 | 365 |             $spiNode{$nodeName} = { %node }; | 
 | 366 |             push @nodes, { %spiNode }; | 
 | 367 |         } | 
 | 368 |     } | 
 | 369 |  | 
 | 370 |     return @nodes; | 
 | 371 | } | 
 | 372 |  | 
 | 373 |  | 
 | 374 | #Returns a hash that represents the device tree node for the SPI1 | 
 | 375 | #or SPI2 master interface on the AST2500.  Each master can support | 
 | 376 | #multiple chips by use of a chip select. | 
 | 377 | #Will look like: | 
 | 378 | #  spi1 { | 
 | 379 | #    status = "okay"; | 
 | 380 | #    flash@0 { | 
 | 381 | #       ... | 
 | 382 | #    }; | 
 | 383 | #  }; | 
 | 384 | # | 
 | 385 | #  $spiNum = The SPI master unit number to use | 
 | 386 | sub getAST2500SpiMasterNode() | 
 | 387 | { | 
 | 388 |     my $spiNum = shift; | 
 | 389 |     my %spiMaster; | 
 | 390 |     my $chipSelect = 0; | 
 | 391 |  | 
| Matt Spinler | 18d5f57 | 2016-11-15 15:25:45 -0600 | [diff] [blame] | 392 |     my $connections = $g_targetObj->findConnections($g_bmc, "SPI", "FLASH"); | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 393 |  | 
 | 394 |     if ($connections eq "") { | 
 | 395 |         return %spiMaster; | 
 | 396 |     } | 
 | 397 |  | 
 | 398 |     #Looking for spi-masters with a chip-unit of $spiNum | 
 | 399 |     #It's possible there are multiple flash chips off the master | 
 | 400 |     foreach my $spi (@{$connections->{CONN}}) { | 
 | 401 |  | 
 | 402 |         my $unitNum = $g_targetObj->getAttribute($spi->{SOURCE}, | 
 | 403 |                                                  "CHIP_UNIT"); | 
 | 404 |         if ($unitNum == $spiNum) { | 
 | 405 |             $spiMaster{status} = "okay"; | 
| Matt Spinler | 2efdcba | 2016-11-08 15:37:20 -0600 | [diff] [blame] | 406 |  | 
 | 407 |             #Add in any pinctrl properties.  These would come from the parent | 
 | 408 |             #of $spi{SOURCE}, which would be a unit-pingroup-bmc if the | 
 | 409 |             #pins for this connection are multi-function. | 
 | 410 |             addPinCtrlProps($g_targetObj->getTargetParent($spi->{SOURCE}), | 
 | 411 |                             \%spiMaster); | 
 | 412 |  | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 413 |             my $flashName = "flash@".$chipSelect; | 
 | 414 |  | 
 | 415 |             $spiMaster{$flashName}{COMMENT} = connectionComment($spi); | 
 | 416 |  | 
 | 417 |             $spiMaster{$flashName}{status} = "okay"; | 
 | 418 |  | 
 | 419 |             $chipSelect++; | 
 | 420 |         } | 
 | 421 |     } | 
 | 422 |  | 
 | 423 |     return %spiMaster; | 
 | 424 | } | 
 | 425 |  | 
 | 426 |  | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 427 | #Returns a hash that represents the leds node by finding all of the | 
 | 428 | #GPIO connections to LEDs. | 
 | 429 | #Node will look like: | 
 | 430 | #   leds { | 
 | 431 | #       <ledname> { | 
 | 432 | #          gpios =  &gpio ASPEED_GPIO(x, y) GPIO_ACTIVE_xxx> | 
 | 433 | #       }; | 
 | 434 | #       <another ledname> { | 
 | 435 | #       ... | 
 | 436 | #   } | 
 | 437 | sub getLEDNode() | 
 | 438 | { | 
 | 439 |     my %leds; | 
 | 440 |  | 
| Matt Spinler | eca7f06 | 2016-11-07 09:59:23 -0600 | [diff] [blame] | 441 |     $leds{compatible} = "gpio-leds"; | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 442 |  | 
| Matt Spinler | 18d5f57 | 2016-11-15 15:25:45 -0600 | [diff] [blame] | 443 |     my $connections = $g_targetObj->findConnections($g_bmc, "GPIO", "LED"); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 444 |  | 
 | 445 |     if ($connections eq "") { | 
 | 446 |         print "WARNING:  No LEDs found connected to the BMC\n"; | 
 | 447 |         return %leds; | 
 | 448 |     } | 
 | 449 |  | 
 | 450 |     foreach my $gpio (@{$connections->{CONN}}) { | 
 | 451 |         my %ledNode; | 
 | 452 |  | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 453 |         $ledNode{COMMENT} = connectionComment($gpio); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 454 |  | 
 | 455 |         #The node name will be the simplified LED name | 
 | 456 |         my $name = $gpio->{DEST_PARENT}; | 
 | 457 |         $name =~ s/(-\d+$)//; #remove trailing position | 
 | 458 |         $name =~ s/.*\///;    #remove the front of the path | 
 | 459 |  | 
 | 460 |         #For now only supports ASPEED. | 
 | 461 |         if (uc($g_bmcMfgr) ne "ASPEED") { | 
 | 462 |             die "ERROR:  Unsupported BMC manufacturer $g_bmcMfgr\n"; | 
 | 463 |         } | 
 | 464 |         my $num = $g_targetObj->getAttribute($gpio->{SOURCE}, "PIN_NUM"); | 
 | 465 |         my $macro = getAspeedGpioMacro($num); | 
 | 466 |  | 
 | 467 |         #If it's active high or low | 
 | 468 |         my $state = $g_targetObj->getAttribute($gpio->{DEST_PARENT}, "ON_STATE"); | 
 | 469 |         my $activeString = getGpioActiveString($state); | 
 | 470 |  | 
 | 471 |         $ledNode{gpios} = "<&gpio $macro $activeString>"; | 
 | 472 |  | 
 | 473 |         $leds{$name} = { %ledNode }; | 
 | 474 |     } | 
 | 475 |  | 
 | 476 |     return %leds; | 
 | 477 | } | 
 | 478 |  | 
 | 479 |  | 
 | 480 | #Returns a either GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW | 
 | 481 | #  $val = either a 1 or a 0 for active high or low | 
 | 482 | sub getGpioActiveString() { | 
 | 483 |     my $val = shift; | 
 | 484 |  | 
 | 485 |     if ($val == 0) { | 
 | 486 |        return "GPIO_ACTIVE_LOW"; | 
 | 487 |     } | 
 | 488 |  | 
 | 489 |     return "GPIO_ACTIVE_HIGH"; | 
 | 490 | } | 
 | 491 |  | 
 | 492 |  | 
 | 493 | #Turns a GPIO number into something like ASPEED_GPIO(A, 0) for the | 
 | 494 | #ASPEED GPIO numbering scheme A[0-7] -> Z[0-7] and then starts at | 
 | 495 | #AA[0-7] after that. | 
 | 496 | #  $num = the GPIO number | 
 | 497 | sub getAspeedGpioMacro() { | 
 | 498 |     my $num = shift; | 
 | 499 |     my $char; | 
 | 500 |     my $offset = $num % 8; | 
 | 501 |     my $block = int($num / 8); | 
 | 502 |  | 
 | 503 |     #If past Z, wraps to AA, AB, etc | 
 | 504 |     if ((ord('A') + $block) > ord('Z')) { | 
 | 505 |         #how far past Z? | 
 | 506 |         $char = $block - (ord('Z') - ord('A')); | 
 | 507 |  | 
 | 508 |         #Don't let it wrap twice | 
 | 509 |         if ($char > (ord('Z') - ord('A') + 1)) { | 
 | 510 |             die "ERROR: Invalid PIN_NUM value $num found for GPIO\n"; | 
 | 511 |         } | 
 | 512 |  | 
 | 513 |         #start back at 'A' again, and convert to a character | 
 | 514 |         $char = chr($char + ord('A') - 1); | 
 | 515 |  | 
 | 516 |         #Add in a bonus 'A', to get something like AB | 
 | 517 |         $char = "A".$char; | 
 | 518 |     } | 
 | 519 |     else { | 
 | 520 |         $char = ord('A') + $block; | 
 | 521 |         $char = chr($char); | 
 | 522 |     } | 
 | 523 |  | 
 | 524 |     return "ASPEED_GPIO($char, $offset)"; | 
 | 525 | } | 
 | 526 |  | 
 | 527 |  | 
 | 528 | #Returns a list of hashes that represent the UART nodes on the BMC by | 
 | 529 | #finding the UART connections. | 
 | 530 | #Nodes will look like: | 
 | 531 | #  &uartX { | 
 | 532 | #     status = "okay" | 
 | 533 | #  } | 
 | 534 | sub getUARTNodes() | 
 | 535 | { | 
 | 536 |     my @nodes; | 
 | 537 |  | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 538 |     #Using U750 for legacy MRW reasons | 
| Matt Spinler | 18d5f57 | 2016-11-15 15:25:45 -0600 | [diff] [blame] | 539 |     my $connections = $g_targetObj->findConnections($g_bmc, "U750"); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 540 |  | 
 | 541 |     if ($connections eq "") { | 
 | 542 |         print "WARNING:  No UART buses found connected to the BMC\n"; | 
 | 543 |         return @nodes; | 
 | 544 |     } | 
 | 545 |  | 
 | 546 |     foreach my $uart (@{$connections->{CONN}}) { | 
 | 547 |         my %node; | 
 | 548 |  | 
 | 549 |         my $num = $g_targetObj->getAttribute($uart->{SOURCE}, "CHIP_UNIT"); | 
 | 550 |         my $name = "uart$num"; | 
 | 551 |  | 
 | 552 |         $node{$name}{status} = "okay"; | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 553 |         $node{$name}{COMMENT} = connectionComment($uart); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 554 |  | 
| Matt Spinler | 2efdcba | 2016-11-08 15:37:20 -0600 | [diff] [blame] | 555 |         #Add in any pinctrl properties.  These would come from the parent | 
 | 556 |         #of $uart{SOURCE}, which would be a unit-pingroup-bmc if the | 
 | 557 |         #pins for this connection are multi-function. | 
 | 558 |         addPinCtrlProps($g_targetObj->getTargetParent($uart->{SOURCE}), | 
 | 559 |                         \%{$node{$name}}); | 
 | 560 |  | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 561 |         push @nodes, { %node }; | 
 | 562 |     } | 
 | 563 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 564 |     return @nodes; | 
 | 565 | } | 
 | 566 |  | 
 | 567 |  | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 568 | #Returns a list of hashes that represent the MAC (ethernet) nodes on the BMC | 
 | 569 | #by finding the connections of type ETHERNET. | 
 | 570 | #Nodes will look like: | 
 | 571 | #  &macX { | 
 | 572 | #    ... | 
 | 573 | #  } | 
 | 574 | sub getMacNodes() | 
 | 575 | { | 
 | 576 |     my @nodes; | 
 | 577 |  | 
| Matt Spinler | 18d5f57 | 2016-11-15 15:25:45 -0600 | [diff] [blame] | 578 |     my $connections = $g_targetObj->findConnections($g_bmc, "ETHERNET"); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 579 |  | 
 | 580 |     if ($connections eq "") { | 
 | 581 |         print "WARNING:  No ethernet buses found connected to the BMC\n"; | 
 | 582 |         return @nodes; | 
 | 583 |     } | 
 | 584 |  | 
 | 585 |     foreach my $eth (@{$connections->{CONN}}) { | 
 | 586 |         my %node; | 
 | 587 |  | 
 | 588 |         my $num = $g_targetObj->getAttribute($eth->{SOURCE}, "CHIP_UNIT"); | 
 | 589 |         my $ncsi = $g_targetObj->getAttribute($eth->{SOURCE}, "NCSI_MODE"); | 
 | 590 |         my $hwChecksum = $g_targetObj->getAttribute($eth->{SOURCE}, | 
 | 591 |                                                   "USE_HW_CHECKSUM"); | 
 | 592 |  | 
 | 593 |         my $name = "mac$num"; | 
 | 594 |         $node{$name}{status} = "okay"; | 
 | 595 |  | 
 | 596 |         if ($ncsi == 1) { | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 597 |             $node{$name}{"use-ncsi"} = ZERO_LENGTH_PROPERTY; | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 598 |         } | 
 | 599 |         if ($hwChecksum == 0) { | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 600 |             $node{$name}{"no-hw-checksum"} = ZERO_LENGTH_PROPERTY; | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 601 |         } | 
 | 602 |  | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 603 |         $node{$name}{COMMENT} = connectionComment($eth); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 604 |  | 
| Matt Spinler | 2efdcba | 2016-11-08 15:37:20 -0600 | [diff] [blame] | 605 |         #Add in any pinctrl properties.  These would come from the parent | 
 | 606 |         #of $eth{SOURCE}, which would be a unit-pingroup-bmc if the | 
 | 607 |         #pins for this connection are multi-function. | 
 | 608 |         addPinCtrlProps($g_targetObj->getTargetParent($eth->{SOURCE}), | 
 | 609 |                         \%{$node{$name}}); | 
 | 610 |  | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 611 |         push @nodes, { %node }; | 
 | 612 |     } | 
 | 613 |  | 
 | 614 |     return @nodes; | 
 | 615 | } | 
 | 616 |  | 
 | 617 |  | 
 | 618 | #Returns a list of hashes that represent the virtual UART nodes | 
 | 619 | #Node will look like: | 
 | 620 | #  &vuart { | 
 | 621 | #   status = "okay" | 
 | 622 | #  } | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 623 | sub getVuartNodes() | 
 | 624 | { | 
 | 625 |     my @nodes; | 
 | 626 |     my %node; | 
 | 627 |  | 
 | 628 |     #For now, enable 1 node all the time. | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 629 |     #TBD if this needs to be fixed | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 630 |     $node{vuart}{status} = "okay"; | 
 | 631 |  | 
 | 632 |     push @nodes, { %node }; | 
 | 633 |  | 
 | 634 |     return @nodes; | 
 | 635 | } | 
 | 636 |  | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 637 | #Returns a list of hashes that represent the I2C device nodes. | 
 | 638 | #There is 1 parent node for each bus, which then have subnodes | 
 | 639 | #for each device on that bus.  If a bus doesn't have any | 
 | 640 | #attached devices, it doesn't need to show up. | 
 | 641 | #The nodes will look like: | 
 | 642 | #  &i2c0 { | 
 | 643 | #     status = "okay" | 
 | 644 | #     device1@addr { (addr = 7 bit I2C address) | 
 | 645 | #       reg = <addr> | 
 | 646 | #       compatible = ... | 
 | 647 | #       ... | 
 | 648 | #     } | 
 | 649 | #     device2@addr { | 
 | 650 | #       reg = <addr> | 
 | 651 | #       ... | 
 | 652 | #     } | 
 | 653 | #  } | 
 | 654 | #  &i2c1 { | 
 | 655 | #  ... | 
 | 656 | #  } | 
 | 657 | sub getI2CNodes() | 
 | 658 | { | 
 | 659 |     my @nodes; | 
 | 660 |     my %busNodes; | 
 | 661 |  | 
| Matt Spinler | 18d5f57 | 2016-11-15 15:25:45 -0600 | [diff] [blame] | 662 |     my $connections = $g_targetObj->findConnections($g_bmc, "I2C"); | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 663 |  | 
 | 664 |     if ($connections eq "") { | 
 | 665 |         print "WARNING:  No I2C buses found connected to the BMC\n"; | 
 | 666 |         return @nodes; | 
 | 667 |     } | 
 | 668 |  | 
 | 669 |     foreach my $i2c (@{$connections->{CONN}}) { | 
 | 670 |  | 
 | 671 |         my %deviceNode, my $deviceName; | 
 | 672 |  | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 673 |         $deviceNode{COMMENT} = connectionComment($i2c); | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 674 |  | 
 | 675 |         $deviceName = lc $i2c->{DEST_PARENT}; | 
 | 676 |         $deviceName =~ s/-\d+$//; #remove trailing position | 
 | 677 |         $deviceName =~ s/.*\///;  #remove the front of the path | 
 | 678 |  | 
 | 679 |         #Get the I2C address | 
 | 680 |         my $i2cAddress = $g_targetObj->getAttribute($i2c->{DEST}, "I2C_ADDRESS"); | 
 | 681 |         $i2cAddress = hex($i2cAddress); | 
 | 682 |         if ($i2cAddress == 0) { | 
 | 683 |             die "ERROR: Missing I2C address on $i2c->{DEST}\n"; | 
 | 684 |         } | 
 | 685 |  | 
 | 686 |         #Put it in the format we want to print it in | 
 | 687 |         $i2cAddress = adjustI2CAddress($i2cAddress); | 
 | 688 |         $deviceNode{reg} = "<$i2cAddress>"; | 
 | 689 |  | 
 | 690 |         $deviceName = makeNodeName($deviceName, $deviceNode{reg}); | 
 | 691 |  | 
 | 692 |         #Get the I2C bus number | 
 | 693 |         if ($g_targetObj->isBadAttribute($i2c->{SOURCE}, | 
 | 694 |                                          "I2C_PORT")) { | 
 | 695 |             die "ERROR: I2C_PORT attribute in $i2c->{DEST_PARENT} " . | 
 | 696 |                 "is either missing or empty.\n"; | 
 | 697 |         } | 
 | 698 |  | 
 | 699 |         my $busNum = $g_targetObj->getAttribute($i2c->{SOURCE}, "I2C_PORT"); | 
 | 700 |         if ($busNum =~ /0x/i) { | 
 | 701 |             $busNum = hex($busNum); | 
 | 702 |         } | 
 | 703 |  | 
 | 704 |         #Convert the number to the Linux numbering scheme. | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 705 |         $busNum += $g_i2cBusAdjust; | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 706 |  | 
 | 707 |         #Get the compatible property | 
 | 708 |         if ($g_targetObj->isBadAttribute($i2c->{DEST_PARENT}, | 
 | 709 |                                          "BMC_DT_COMPATIBLE")) { | 
 | 710 |             die "ERROR: BMC_DT_COMPATIBLE attribute in $i2c->{DEST_PARENT} " . | 
 | 711 |                 "is either missing or empty.\n"; | 
 | 712 |         } | 
 | 713 |  | 
 | 714 |         $deviceNode{compatible} = $g_targetObj->getAttribute( | 
 | 715 |                                                     $i2c->{DEST_PARENT}, | 
 | 716 |                                                     "BMC_DT_COMPATIBLE"); | 
 | 717 |  | 
 | 718 |         #Get any other part specific properties, where the property | 
 | 719 |         #names are actually defined in the XML. | 
 | 720 |         my %props = getPartDefinedDTProperties($i2c->{DEST_PARENT}); | 
 | 721 |         foreach my $prop (sort keys %props) { | 
 | 722 |             $deviceNode{$prop} = $props{$prop}; | 
 | 723 |         } | 
 | 724 |  | 
 | 725 |         #busNodeName is the hash twice so when we loop | 
 | 726 |         #below it doesn't get lost | 
 | 727 |         my $busNodeName = "i2c$busNum"; | 
 | 728 |         $busNodes{$busNodeName}{$busNodeName}{status} = "okay"; | 
 | 729 |         $busNodes{$busNodeName}{$busNodeName}{$deviceName} = { %deviceNode }; | 
| Matt Spinler | 2efdcba | 2016-11-08 15:37:20 -0600 | [diff] [blame] | 730 |  | 
 | 731 |         #Add in any pinctrl properties.  These would come from the parent | 
 | 732 |         #of $i2c{SOURCE}, which would be a unit-pingroup-bmc if the | 
 | 733 |         #pins for this connection are multi-function. | 
 | 734 |         addPinCtrlProps($g_targetObj->getTargetParent($i2c->{SOURCE}), | 
 | 735 |                         \%{$busNodes{$busNodeName}{$busNodeName}}); | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 736 |     } | 
 | 737 |  | 
 | 738 |     #Each bus gets its own hash entry in the array | 
 | 739 |     for my $b (sort keys %busNodes) { | 
 | 740 |         push @nodes, { %{$busNodes{$b}} }; | 
 | 741 |     } | 
 | 742 |  | 
 | 743 |     return @nodes; | 
 | 744 | } | 
 | 745 |  | 
 | 746 |  | 
 | 747 | #Returns a hash of property names and values that should be stored in | 
 | 748 | #the device tree node for this device. The names of the properties and | 
 | 749 | #the attributes to find their values in are stored in the | 
 | 750 | #BMC_DT_ATTR_NAMES attribute in the chip. | 
 | 751 | #  $chip = the chip target | 
 | 752 | sub getPartDefinedDTProperties() | 
 | 753 | { | 
 | 754 |     my $chip = shift; | 
 | 755 |     my %props; | 
 | 756 |  | 
 | 757 |     if ($g_targetObj->isBadAttribute($chip, "BMC_DT_ATTR_NAMES")) { | 
 | 758 |         return %props; | 
 | 759 |     } | 
 | 760 |  | 
 | 761 |     my $attr = $g_targetObj->getAttribute($chip, "BMC_DT_ATTR_NAMES"); | 
 | 762 |     $attr =~ s/\s//g; | 
 | 763 |     my @names = split(',', $attr); | 
 | 764 |  | 
 | 765 |     #There can be up to 4 entries in this attribute | 
 | 766 |     for (my $i = 0; $i < scalar @names; $i += 2) { | 
 | 767 |  | 
 | 768 |         #$names[$i] holds the name of the attribute. | 
 | 769 |         #$names[$i+1] holds the name of the property to store its value in. | 
 | 770 |         if (($names[$i] ne "NA") && ($names[$i] ne "")) { | 
 | 771 |  | 
 | 772 |             my $val = $g_targetObj->getAttribute($chip, $names[$i]); | 
 | 773 |  | 
 | 774 |             #if the value is empty, assume it's for a standalone property, | 
 | 775 |             #which gets turned into: some-property; | 
 | 776 |             if ($val eq "") { | 
 | 777 |                 $props{$names[$i+1]} = ZERO_LENGTH_PROPERTY; | 
 | 778 |             } | 
 | 779 |             else { | 
 | 780 |                 $props{$names[$i+1]} = "<$val>"; | 
 | 781 |             } | 
 | 782 |         } | 
 | 783 |     } | 
 | 784 |  | 
 | 785 |     return %props; | 
 | 786 | } | 
 | 787 |  | 
 | 788 |  | 
 | 789 | #Convert the MRW I2C address into the format the dts needs | 
 | 790 | #  $addr = the I2C Address | 
 | 791 | sub adjustI2CAddress() | 
 | 792 | { | 
 | 793 |     my $addr = shift; | 
 | 794 |  | 
 | 795 |     #MRW holds the 8 bit value.  We need the 7 bit one. | 
 | 796 |     my $addr = $addr >> 1; | 
 | 797 |     $addr = sprintf("0x%X", $addr); | 
 | 798 |     $addr = lc $addr; | 
 | 799 |  | 
 | 800 |     return $addr; | 
 | 801 | } | 
 | 802 |  | 
 | 803 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 804 | #Sets the global $g_i2cBusAdjust from the configuration file. | 
 | 805 | sub getI2CBusAdjust() | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 806 | { | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 807 |     if (exists $g_configuration{"i2c-bus-adjust"}) { | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 808 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 809 |         $g_i2cBusAdjust = $g_configuration{"i2c-bus-adjust"}; | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 810 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 811 |         if (!looks_like_number($g_i2cBusAdjust)) { | 
 | 812 |             die "ERROR:  Invalid i2c-bus-adjust value $g_i2cBusAdjust " . | 
 | 813 |                 "found in config file.\n"; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 814 |         } | 
 | 815 |     } | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 816 |     else { | 
 | 817 |         $g_i2cBusAdjust = 0; | 
 | 818 |         print "WARNING: No I2C Bus number adjustment done " . | 
 | 819 |               "for this system.\n"; | 
 | 820 |     } | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 821 | } | 
 | 822 |  | 
 | 823 |  | 
| Matt Spinler | 2efdcba | 2016-11-08 15:37:20 -0600 | [diff] [blame] | 824 |  | 
 | 825 | #Adds two pinctrl properties to the device node hash passed in, | 
 | 826 | #if specified in the MRW.  Pin Control refers to a mechanism for | 
 | 827 | #Linux to know which function of a multi-function pin to configure. | 
 | 828 | #For example, a pin could either be configured to be a GPIO, or | 
 | 829 | #an I2C clock line.  The pin function depends on board wiring, | 
 | 830 | #so is known by the MRW. | 
 | 831 | #  $target = the target to get the BMC_DT_PINCTRL_FUNCTS attribute from | 
 | 832 | #  $node = a hash reference to the device tree node to add the properties to | 
 | 833 | sub addPinCtrlProps() | 
 | 834 | { | 
 | 835 |     my ($target, $node) = @_; | 
 | 836 |  | 
 | 837 |     if (!$g_targetObj->isBadAttribute($target, "BMC_DT_PINCTRL_FUNCS")) { | 
 | 838 |         my $attr = $g_targetObj->getAttribute($target, | 
 | 839 |                                               "BMC_DT_PINCTRL_FUNCS"); | 
 | 840 |  | 
 | 841 |         my $pinCtrl0Prop = makePinCtrl0PropValue($attr); | 
 | 842 |         if ($pinCtrl0Prop ne "") { | 
 | 843 |             $node->{"pinctrl-names"} = "default"; | 
 | 844 |             $node->{"pinctrl-0"} = $pinCtrl0Prop; | 
 | 845 |         } | 
 | 846 |     } | 
 | 847 | } | 
 | 848 |  | 
 | 849 |  | 
 | 850 | #Constructs the pinctrl-0 property value based on the | 
 | 851 | #BMC_DT_PINCTRL_FUNCS attribute passed in. | 
 | 852 | #  $attr = BMC_DT_PINCTRL_FUNCS attribute value, which is an array | 
 | 853 | sub makePinCtrl0PropValue() | 
 | 854 | { | 
 | 855 |     my $attr = shift; | 
 | 856 |     my @entries; | 
 | 857 |     my $value = ""; | 
 | 858 |  | 
 | 859 |     $attr =~ s/\s//g; | 
 | 860 |     my @funcs = split(',', $attr); | 
 | 861 |     foreach my $func (@funcs) { | 
 | 862 |         if (($func ne "NA") && ($func ne "")) { | 
 | 863 |             push @entries, $func; | 
 | 864 |         } | 
 | 865 |     } | 
 | 866 |  | 
 | 867 |     #<&pinctrl_funcA_default &pinctrl_funcB_default ...> | 
 | 868 |     if (scalar @entries) { | 
 | 869 |         $value = "<"; | 
 | 870 |         foreach my $entry (@entries) { | 
 | 871 |             $value .= "&pinctrl_".$entry."_default "; | 
 | 872 |         } | 
 | 873 |         $value =~ s/\s$//; #Remove the trailing space | 
 | 874 |         $value .= ">"; | 
 | 875 |     } | 
 | 876 |  | 
 | 877 |     return $value; | 
 | 878 | } | 
 | 879 |  | 
 | 880 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 881 | #Returns a list of compatible fields for the BMC itself. | 
 | 882 | sub getBMCCompatibles() | 
 | 883 | { | 
 | 884 |     my @compats; | 
 | 885 |  | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 886 |     #1st entry:  <system mfgr>,<system name>-bmc | 
 | 887 |     #2nd entry:  <bmc mfgr>,<bmc model> | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 888 |  | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 889 |     foreach my $target (sort keys %{ $g_targetObj->getAllTargets() }) { | 
 | 890 |         if ($g_targetObj->getType($target) eq "SYS") { | 
 | 891 |            my $mfgr = $g_targetObj->getAttribute($target, "MANUFACTURER"); | 
 | 892 |            push @compats, lc "$mfgr,$g_systemName-bmc"; | 
 | 893 |            last; | 
 | 894 |         } | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 895 |     } | 
 | 896 |  | 
 | 897 |     push @compats, lc($g_bmcMfgr).",".lc($g_bmcModel); | 
 | 898 |  | 
 | 899 |     return @compats; | 
 | 900 | } | 
 | 901 |  | 
 | 902 |  | 
 | 903 | #Returns a string for the system's BMC model property | 
 | 904 | sub getSystemBMCModel() | 
 | 905 | { | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 906 |     #'<System> BMC' | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 907 |     my $sys = lc $g_systemName; | 
 | 908 |     $sys = uc(substr($sys, 0, 1)) . substr($sys, 1); | 
 | 909 |  | 
 | 910 |     return $sys . " BMC"; | 
 | 911 | } | 
 | 912 |  | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 913 | #Create the comment that will show up in the device tree | 
 | 914 | #for a connection.  In the output, will look like: | 
 | 915 | # // sourceUnit -> | 
 | 916 | # // destChip | 
 | 917 | # | 
 | 918 | #  $conn = The connection hash reference | 
 | 919 | sub connectionComment() | 
 | 920 | { | 
 | 921 |     my $conn = shift; | 
 | 922 |     my $comment = "$conn->{SOURCE} ->\n$conn->{DEST_PARENT}"; | 
 | 923 |     return $comment; | 
 | 924 | } | 
 | 925 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 926 |  | 
 | 927 | #Prints a list of nodes at the same indent level | 
 | 928 | #  $f = file handle | 
 | 929 | #  $level = indent level (0,1,etc) | 
 | 930 | #  @nodes = array of node hashes to print, where the | 
 | 931 | #  key for the hash is the name of the node | 
 | 932 | sub printNodes() | 
 | 933 | { | 
 | 934 |     my ($f, $level, @nodes) = @_; | 
 | 935 |  | 
 | 936 |     foreach my $n (@nodes) { | 
 | 937 |         my %node = %$n; | 
 | 938 |  | 
 | 939 |         foreach my $name (sort keys %node) { | 
 | 940 |             my %n = %{ $node{$name} }; | 
 | 941 |             printNode($f, $level, $name, %n); | 
 | 942 |         } | 
 | 943 |     } | 
 | 944 | } | 
 | 945 |  | 
 | 946 |  | 
 | 947 | #Print a single node and its children | 
 | 948 | #  $f = file handle | 
 | 949 | #  $level = indent level (0,1,etc) | 
 | 950 | #  $name = the name of the node - shows up as: | 
 | 951 | #     name { ... | 
 | 952 | #  %vals = The contents of the node, with the following options: | 
 | 953 | #     if the key is: | 
 | 954 | #     - 'DTSI_INCLUDE', then value gets turned into a #include | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 955 | #     - 'COMMENT', then value gets turned into a // comment | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 956 | #     - 'ZERO_LENGTH_PROPERTY' then value gets turned into:  value; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 957 | # | 
 | 958 | #     If the value is: | 
 | 959 | #     - a hash - then that hash gets turned into a child node | 
 | 960 | #       where the key is the name of the child node | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 961 | #     - an array of hashes indicates an array of child nodes | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 962 | sub printNode() | 
 | 963 | { | 
 | 964 |     my ($f, $level, $name, %vals) = @_; | 
 | 965 |     my $include = ""; | 
 | 966 |  | 
| Matt Spinler | c0dff8a | 2016-11-02 15:47:30 -0500 | [diff] [blame] | 967 |     #No reason to print an empty node | 
 | 968 |     if (!keys %vals) { | 
 | 969 |         return; | 
 | 970 |     } | 
 | 971 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 972 |     if ($level == 0) { | 
 | 973 |         $name = "&".$name; | 
 | 974 |     } | 
 | 975 |  | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 976 |     print $f "\n"; | 
 | 977 |  | 
 | 978 |     if (exists $vals{COMMENT}) { | 
 | 979 |         my @lines = split('\n', $vals{COMMENT}); | 
 | 980 |         foreach my $l (@lines) { | 
 | 981 |             print $f indent($level) . "// $l\n"; | 
 | 982 |         } | 
 | 983 |     } | 
 | 984 |  | 
 | 985 |     print $f indent($level) . "$name {\n"; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 986 |  | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 987 |     #First print properties, then includes, then subnodes | 
 | 988 |  | 
 | 989 |     #Print Properties | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 990 |     foreach my $v (sort keys %vals) { | 
 | 991 |  | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 992 |         next if ($v eq "COMMENT"); | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 993 |         next if ($v eq "DTSI_INCLUDE"); | 
 | 994 |         next if (ref($vals{$v}) eq "HASH"); | 
 | 995 |         next if (ref($vals{$v}) eq "ARRAY"); | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 996 |  | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 997 |         if ($vals{$v} ne ZERO_LENGTH_PROPERTY) { | 
 | 998 |             printProperty($f, $level+1, $v, $vals{$v}); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 999 |         } | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 1000 |         else { | 
 | 1001 |             printZeroLengthProperty($f, $level+1, $v); | 
 | 1002 |         } | 
 | 1003 |     } | 
 | 1004 |  | 
 | 1005 |     #Print Includes | 
 | 1006 |     foreach my $v (sort keys %vals) { | 
 | 1007 |  | 
 | 1008 |         if ($v eq "DTSI_INCLUDE") { | 
 | 1009 |             #print 1 include per line | 
 | 1010 |             my @incs = split(',', $vals{$v}); | 
 | 1011 |             foreach my $i (@incs) { | 
 | 1012 |                 print $f qq(#include "$i";\n); | 
 | 1013 |             } | 
 | 1014 |         } | 
 | 1015 |     } | 
 | 1016 |  | 
 | 1017 |     #Print Nodes | 
 | 1018 |     foreach my $v (sort keys %vals) { | 
 | 1019 |  | 
 | 1020 |         if (ref($vals{$v}) eq "HASH") { | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1021 |             printNode($f, $level+1, $v, %{$vals{$v}}); | 
 | 1022 |         } | 
| Matt Spinler | 995f2a2 | 2016-09-30 13:07:31 -0500 | [diff] [blame] | 1023 |         #An array of nested nodes | 
 | 1024 |         elsif (ref($vals{$v}) eq "ARRAY") { | 
 | 1025 |             my @array = @{$vals{$v}}; | 
 | 1026 |             &printNodes($f, $level+1, @array); | 
 | 1027 |         } | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1028 |     } | 
 | 1029 |  | 
 | 1030 |     print $f indent($level) . "};\n"; | 
 | 1031 | } | 
 | 1032 |  | 
 | 1033 |  | 
 | 1034 | #Prints a comma separated list of properties. | 
 | 1035 | #e.g.  a = "b, c, d"; | 
 | 1036 | #  $f = file handle | 
 | 1037 | #  $level = indent level (0,1,etc) | 
 | 1038 | #  $name = name of property | 
 | 1039 | #  @vals = list of property values | 
 | 1040 | sub printPropertyList() | 
 | 1041 | { | 
 | 1042 |     my ($f, $level, $name, @vals) = @_; | 
 | 1043 |  | 
 | 1044 |     print $f indent($level) . "$name = "; | 
 | 1045 |  | 
 | 1046 |     for (my $i = 0;$i < scalar @vals; $i++) { | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1047 |         print $f qq("$vals[$i]"); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1048 |         if ($i < (scalar(@vals) - 1)) { | 
 | 1049 |             print $f ", "; | 
 | 1050 |         } | 
 | 1051 |     } | 
 | 1052 |     print $f ";\n" | 
 | 1053 | } | 
 | 1054 |  | 
 | 1055 |  | 
 | 1056 | #Prints a single property.  e.g. a = "b"; | 
 | 1057 | #  $f = file handle | 
 | 1058 | #  $level = indent level (0,1,etc) | 
 | 1059 | #  $name = name of property | 
 | 1060 | #  @vals = property values | 
 | 1061 | sub printProperty() | 
 | 1062 | { | 
 | 1063 |     my ($f, $level, $name, $val) = @_; | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1064 |     my $quoteChar = qq("); | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 1065 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1066 |     $val = convertReference($val); | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 1067 |  | 
 | 1068 |     #properties with < > or single word aliases don't need quotes | 
 | 1069 |     if (($val =~ /<.*>/) || ($val =~ /^&\w+$/)) { | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1070 |         $quoteChar = ""; | 
| Matt Spinler | 23d47c2 | 2016-10-04 12:31:21 -0500 | [diff] [blame] | 1071 |     } | 
 | 1072 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1073 |     print $f indent($level) . "$name = $quoteChar$val$quoteChar;\n"; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1074 | } | 
 | 1075 |  | 
 | 1076 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1077 | #Prints a zero length property e.g. some-property; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1078 | #  $f = file handle | 
 | 1079 | #  $level = indent level (0,1,etc) | 
 | 1080 | #  $name = name of property | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1081 | sub printZeroLengthProperty() | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1082 | { | 
 | 1083 |     my ($f, $level, $name) = @_; | 
 | 1084 |     print $f indent($level) . "$name;\n"; | 
 | 1085 | } | 
 | 1086 |  | 
 | 1087 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1088 | #Replace '(ref)' with '&'. | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1089 | #Needed because Serverwiz doesn't properly escape '&'s in the XML, | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1090 | #so the '(ref)' string is used to represent the reference | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1091 | #specifier instead of '&'. | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1092 | sub convertReference() { | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1093 |     my $val = shift; | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1094 |     $val =~ s/\(ref\)/&/g; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1095 |     return $val | 
 | 1096 | } | 
 | 1097 |  | 
 | 1098 |  | 
 | 1099 | #Returns the target for the BMC chip. | 
 | 1100 | #Not worrying about multiple BMC systems for now. | 
 | 1101 | sub getBMCTarget() | 
 | 1102 | { | 
 | 1103 |     foreach my $target (sort keys %{ $g_targetObj->getAllTargets() }) | 
 | 1104 |     { | 
 | 1105 |         if ($g_targetObj->getType($target) eq "BMC") { | 
 | 1106 |            return $target; | 
 | 1107 |         } | 
 | 1108 |     } | 
 | 1109 |     return ""; | 
 | 1110 | } | 
 | 1111 |  | 
 | 1112 |  | 
 | 1113 | #Prints the device tree version line. | 
 | 1114 | #  $f = file handle | 
 | 1115 | sub printVersion() | 
 | 1116 | { | 
 | 1117 |     my $f = shift; | 
 | 1118 |     print $f VERSION."\n" | 
 | 1119 | } | 
 | 1120 |  | 
 | 1121 |  | 
 | 1122 | #Prints the #include line for pulling in an include file. | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1123 | #The files to include come from the configuration file. | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1124 | #  $f = file handle | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1125 | #  $type = include type | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1126 | sub printIncludes() | 
 | 1127 | { | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1128 |     my ($f, $type) = @_; | 
 | 1129 |     my @includes = getIncludes($type); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1130 |  | 
 | 1131 |     foreach my $i (@includes) { | 
 | 1132 |         #if a .dtsi, gets " ", otherwise < > | 
 | 1133 |         if ($i =~ /\.dtsi$/) { | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1134 |             $i = qq("$i"); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1135 |         } | 
 | 1136 |         else { | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1137 |             $i = "<$i>"; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1138 |         } | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1139 |         print $f "#include $i\n"; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1140 |     } | 
 | 1141 | } | 
 | 1142 |  | 
 | 1143 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1144 | #Returns an array of include files found in the config file | 
 | 1145 | #for the type specified. | 
 | 1146 | # $type = the include type, which is the section name in the | 
 | 1147 | #         YAML configuration file. | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1148 | sub getIncludes() | 
 | 1149 | { | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1150 |     my $type = shift; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1151 |     my @includes; | 
 | 1152 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1153 |     #The config file may have a section but no includes | 
 | 1154 |     #listed in it, which is OK. | 
 | 1155 |     if ((exists $g_configuration{includes}{$type}) && | 
 | 1156 |         (ref($g_configuration{includes}{$type}) eq "ARRAY")) { | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1157 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1158 |         @includes = @{$g_configuration{includes}{$type}}; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1159 |     } | 
 | 1160 |  | 
 | 1161 |     return @includes; | 
 | 1162 | } | 
 | 1163 |  | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1164 |  | 
| Matt Spinler | 7490913 | 2016-10-07 13:52:19 -0500 | [diff] [blame] | 1165 | #Appends the first value of the 'reg' property | 
 | 1166 | #passed in to the name passed in to create the | 
 | 1167 | #full name for the node | 
 | 1168 | #  $name = node name that will be appended to | 
 | 1169 | #  $reg = the reg property values | 
 | 1170 | sub makeNodeName() | 
 | 1171 | { | 
 | 1172 |     my ($name, $reg) = @_; | 
 | 1173 |  | 
 | 1174 |     $reg =~ s/<//g; | 
 | 1175 |     $reg =~ s/>//g; | 
 | 1176 |     my @vals = split(' ', $reg); | 
 | 1177 |  | 
 | 1178 |     if (scalar @vals > 0) { | 
 | 1179 |         $vals[0] =~ s/0x//; | 
 | 1180 |         $name .= "@" . lc $vals[0]; | 
 | 1181 |     } | 
 | 1182 |  | 
 | 1183 |     return $name; | 
 | 1184 | } | 
 | 1185 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1186 |  | 
 | 1187 | #Prints the root node starting bracket. | 
 | 1188 | #  $f = file handle | 
 | 1189 | sub printRootNodeStart() { | 
 | 1190 |     my $f = shift; | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1191 |     print $f qq(/ {\n); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1192 | } | 
 | 1193 |  | 
 | 1194 |  | 
 | 1195 | #Prints the root node ending bracket. | 
 | 1196 | #  $f = file handle | 
 | 1197 | #  $level = indent level (0,1,etc) | 
 | 1198 | sub printRootNodeEnd() { | 
 | 1199 |     my ($f, $level) = @_; | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1200 |     print $f indent($level).qq(};\n); | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1201 | } | 
 | 1202 |  | 
 | 1203 |  | 
 | 1204 | #Returns a string that can be used to indent based on the | 
 | 1205 | #level passed in.  Each level is an additional 4 spaces. | 
 | 1206 | #  $level = indent level (0,1,etc) | 
 | 1207 | sub indent() { | 
 | 1208 |     my $level = shift; | 
 | 1209 |     return ' ' x ($level * 4); | 
 | 1210 | } | 
 | 1211 |  | 
 | 1212 |  | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1213 | sub printUsage | 
 | 1214 | { | 
| Matt Spinler | 30b461c | 2016-10-10 16:50:07 -0500 | [diff] [blame] | 1215 |     print "gen_devtree.pl -x [XML filename] -y [yaml config file] " . | 
 | 1216 |           "-o [output filename]\n"; | 
| Matt Spinler | 7d381e1 | 2016-09-27 14:27:24 -0500 | [diff] [blame] | 1217 |     exit(1); | 
 | 1218 | } |