diff options
Diffstat (limited to 'meta-aspeed/recipes-utils/openbmc-gpio/files/ast_gpio_parser.py')
-rw-r--r-- | meta-aspeed/recipes-utils/openbmc-gpio/files/ast_gpio_parser.py | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/meta-aspeed/recipes-utils/openbmc-gpio/files/ast_gpio_parser.py b/meta-aspeed/recipes-utils/openbmc-gpio/files/ast_gpio_parser.py new file mode 100644 index 0000000..acc4c1a --- /dev/null +++ b/meta-aspeed/recipes-utils/openbmc-gpio/files/ast_gpio_parser.py @@ -0,0 +1,204 @@ +#!/usr/bin/python -tt +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import argparse +import csv +import logging +import re +import sys + +FUNC_SYMBOL = 'Function' +AND_SYMBOL = 'And' +OR_SYMBOL = 'Or' +BE_SYMBOL = 'BitsEqual' +BNE_SYMBOL = 'BitsNotEqual' + + +class CsvReader: + ''' + A class for parsing the CSV files containing the pin mapping data. + ''' + def __init__(self, path): + self.path = path + + fileobj = open(path, 'r') + self.reader = csv.reader(fileobj, delimiter=b',', quotechar=b'"') + + def next(self): + try: + line = self.reader.next() + except StopIteration: + return None + return line + + +class Expression(object): + def __init__(self, exp): + self.exp = exp + + def parse(self): + # Strap[4,1:0]=100 + m = re.match('([^\[]+)\[(.+)\](!*=)([01]+)', self.exp) + # ('Strap', '4,1:0', '=', '100') + try: + if len(m.groups()) != 4: + raise + scuname = m.group(1) + if scuname.lower() == 'strap': + scu = 0x70 + elif scuname.startswith('SCU'): + scu = int(scuname[3:], 16) + + bits = [] + for bit in m.group(2).split(','): + if ':' in bit: + # it is a range + s, _, e = bit.partition(':') + ss = int(s) + ee = int(e) + if ss < ee: + assert 0 <= ss and ee <= 31 + bits += range(ss, ee + 1) + else: + assert 0 <= ee and ss <= 31 + bits += range(ee, ss + 1) + else: + bits += [int(bit)] + if m.group(3) == '!=': + cond = BNE_SYMBOL + else: + cond = BE_SYMBOL + value = int(m.group(4), 2) + return '%s(0x%x, %s, 0x%x)' \ + % (cond, scu, sorted(bits, reverse=True), value) + except Exception as e: + logging.exception('Failed to parse expression "%s"', self.exp) + + +class Conditions(object): + def __init__(self, cond): + self.cond = re.sub('\s+', '', cond) + + def _next_condition_pos(self, cur): + for idx in range(cur, len(self.cond)): + c = self.cond[idx] + if c == '&' or c == '|': + return idx + return -1 + + def _get_expression(self, exp): + if exp == '': + return None + return Expression(exp).parse() + + def _parse(self, idx): + next_idx = self._next_condition_pos(idx + 1) + if next_idx == -1: + # end of string + return self._get_expression(self.cond[idx:]) + + prev = self._get_expression(self.cond[idx:next_idx]) + if self.cond[next_idx] == '&': + cond = AND_SYMBOL + else: + cond = OR_SYMBOL + return '%s(%s, %s)' % (cond, prev, self._parse(next_idx + 1)) + + def parse(self): + return self._parse(0) + + +class AstGPIO(object): + def __init__(self, data): + self.data = data + self.undefined_func = 1 + self.pins = {} + self.functions = set() + + def _parse_conditions(self, cond): + return Conditions(cond).parse() + + def _parse_funcs(self, parts): + func_fmt = FUNC_SYMBOL + '(\'{func}\', {cond})' + if len(parts) < 1: + return [] + # Unable to process SIORD + if 'SIORD' in ' '.join(parts): + logging.warning('Unable to process SIORD. Ignore') + return [] + func = parts[0] + if func == '': + # nothing after + return [] + if func == '-': + func = 'UNDEFINED%d' % self.undefined_func + self.undefined_func += 1 + assert func not in self.functions + self.functions.add(func) + if len(parts) == 1: + # just has the function name, the last function + return [func_fmt.format(func=func, cond=None)] + cond = self._parse_conditions(parts[1]) + return [func_fmt.format(func=func, cond=cond)] \ + + self._parse_funcs(parts[2:]) + + def parse(self): + while True: + line = self.data.next() + if line is None: + break + + logging.debug('Parsing line: %s' % line) + + # V21,ROMA24,SCU88[28]=1 & SCU94[1]=0,VPOR6,SCU88[28]=1 & SCU94[1]=1,GPIOR4 + pin = line[0] + if pin == "": + # empty line + continue + funcs = self._parse_funcs(line[1:]) + logging.debug('%s: %s' % (pin, funcs)) + assert pin not in self.pins + self.pins[pin] = funcs + + def print(self, out): + for pin in sorted(self.pins): + if len(self.pins[pin]) == 0: + logging.warning('Pin "%s" has no function defined. Skip' % pin) + continue + out.write(' \'%s\': [\n %s\n ],\n' + % (pin, ',\n '.join(self.pins[pin]))) + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument('data', help='The GPIO data file') + args = ap.parse_args() + + logging.basicConfig(level=logging.INFO, format='%(asctime)s: %(message)s') + + gpio = AstGPIO(CsvReader(args.data)) + gpio.parse() + gpio.print(sys.stdout) + + +rc = main() +sys.exit(rc) |