diff options
Diffstat (limited to 'common/recipes-utils/openbmc-gpio/files/openbmc_gpio_table.py')
-rw-r--r-- | common/recipes-utils/openbmc-gpio/files/openbmc_gpio_table.py | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_table.py b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_table.py new file mode 100644 index 0000000..dda8a98 --- /dev/null +++ b/common/recipes-utils/openbmc-gpio/files/openbmc_gpio_table.py @@ -0,0 +1,269 @@ +# 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 + +from soc_gpio import soc_get_register + +import logging +import os +import sys + + +class NotSmartEnoughException(Exception): + '''There are few cases the code cannot make good decision on how to configure + the registers automatically. In such cases, this exception is thrown. + ''' + pass + + +class ConfigUnknownFunction(Exception): + '''Unknown function to configure exception''' + pass + + +class BitsEqual(object): + def __init__(self, register, bits, value): + self.register = register + self.bits = bits + self.value = value + + def __str__(self): + return '%s[%s]==0x%x' \ + % (str(soc_get_register(self.register)), self.bits, self.value) + + def get_registers(self): + return set([self.register]) + + def check(self): + return soc_get_register(self.register).bits_value(self.bits) \ + == self.value + + def satisfy(self, **kwargs): + if BitsEqual.check(self): + return + reg = soc_get_register(self.register) + value = self.value + for bit in sorted(self.bits): + if value & 0x1 == 0x1: + reg.set_bit(bit, **kwargs) + else: + reg.clear_bit(bit, **kwargs) + value >>= 1 + + def unsatisfy(self, **kwargs): + if not BitsEqual.check(self): + return + if len(self.bits) > 1: + raise NotSmartEnoughException('Not able to unsatisfy ' + 'multi-bits equal') + bit = self.bits[0] + reg = soc_get_register(self.register) + value = self.value + if value & 0x1 == 0x1: + reg.clear_bit(bit, **kwargs) + else: + reg.set_bit(bit, **kwargs) + + +class BitsNotEqual(BitsEqual): + def __str__(self): + return '%s[%s]!=0x%x' \ + % (str(soc_get_register(self.register)), self.bits, self.value) + + def check(self): + return not BitsEqual.check(self) + + def satisfy(self, **kwargs): + BitsEqual.unsatisfy(self, **kwargs) + + def unsatisfy(self, **kwargs): + BitsEqual.satisfy(self, **kwargs) + + +class AndOrBase(object): + def __init__(self, left, right): + self.left = left + self.right = right + + def get_registers(self): + return self.left.get_registers() | self.right.get_registers() + + def check(self): + raise Exception('This method must be implemented in subclass') + + +class And(AndOrBase): + def __str__(self): + return 'AND(%s, %s)' % (str(self.left), str(self.right)) + + def check(self): + return self.left.check() and self.right.check() + + def satisfy(self, **kwargs): + if self.check(): + return + self.left.satisfy(**kwargs) + self.right.satisfy(**kwargs) + + def unsatisfy(self, **kwargs): + if not self.check(): + return + raise NotSmartEnoughException('Not able to unsatisfy an AND condition') + + +class Or(AndOrBase): + def __str__(self): + return 'OR(%s, %s)' % (str(self.left), str(self.right)) + + def check(self): + return self.left.check() or self.right.check() + + def satisfy(self, **kwargs): + if self.check(): + return + raise NotSmartEnoughException('Not able to satisfy an OR condition') + + def unsatisfy(self, **kwargs): + if not self.check(): + return + self.left.unsatisfy(**kwargs) + self.right.unsatisfy(**kwargs) + + +class Function(object): + def __init__(self, name, condition=None): + self.name = name + self.condition = condition + + def __str__(self): + return 'Function(\'%s\', %s)' % (self.name, str(self.condition)) + + +class SocGPIOTable(object): + def __init__(self, gpio_table): + self.soc_gpio_table = gpio_table + self.registers = set([]) # all HW registers used for GPIO control + self.functions = {} + + self._parse_gpio_table() + self._sync_from_hw() + + def _parse_gpio_table(self): + # first get list of registers based on the SoC GPIO table + for pin, funcs in self.soc_gpio_table.iteritems(): + for func in funcs: + assert func.name not in self.functions + self.functions[func.name] = pin + if func.condition is not None: + self.registers |= func.condition.get_registers() + + def _sync_from_hw(self): + # for each register, create an object and read the value from HW + for reg in self.registers: + soc_get_register(reg).read(refresh=True) + + def write_to_hw(self): + for reg in self.registers: + soc_get_register(reg).write() + + def config_function(self, func_name, write_through=True): + logging.debug('Configure function "%s"' % func_name) + if func_name not in self.functions: + # The function is not multi-function pin + raise ConfigUnknownFunction('Unknown function "%s" ' % func_name) + funcs = self.soc_gpio_table[self.functions[func_name]] + for func in funcs: + cond = func.condition + if func.name == func_name: + # this is the function we want to configure. + # if the condition is None, we are good to go, + # otherwiset, satisfy the condition + if cond is not None: + cond.satisfy(write_through=write_through) + break + else: + # this is not the funciton we want to configure. + # have to make this condition unsatisfied, so that we can go + # to the next function + assert cond is not None + cond.unsatisfy(write_through=write_through) + + def _get_one_pin(self, pin, refresh): + if refresh: + self._sync_from_hw() + funcs = self.soc_gpio_table[pin] + active_func = None + all_funcs = [] + for func in funcs: + cond = func.condition + all_funcs.append('%s:%s' % (func.name, str(cond))) + if active_func is None and (cond is None or cond.check()): + active_func = func.name + + if active_func is None: + logging.error('Pin "%s" has no function set up. ' + 'All possibile functions are %s.' + % (pin, ', '.join(all_funcs))) + return ('', '') + else: + desc = '%s => %s, functions: %s' \ + % (pin, active_func, ', '.join(all_funcs)) + return (active_func, desc) + + def dump_pin(self, pin, out=sys.stdout, refresh=False): + if pin not in self.soc_gpio_table: + raise Exception('"%s" is not a valid pin' % pin) + + _, desc = self._get_one_pin(pin, refresh) + out.write('%s\n' % desc) + + def dump_function(self, func_name, out=sys.stdout, refresh=False): + if func_name not in self.functions: + raise Exception('"%s" is not a valid function name' % func_name) + pin = self.functions[func_name] + self.dump_pin(pin, out=out, refresh=refresh) + + def dump_functions(self, out=sys.stdout, refresh=False): + if refresh: + self._sync_from_hw() + + for pin in self.soc_gpio_table: + self.dump_pin(pin, out=out, refresh=False) + + def get_active_functions(self, refresh=False): + if refresh: + self._sync_from_hw() + + all = [] + for pin in self.soc_gpio_table: + active, _ = self._get_one_pin(pin, False) + all.append(active) + return all + + +GPIO_INPUT = 'input' +GPIO_OUT_HIGH = 'high' +GPIO_OUT_LOW = 'low' + +class BoardGPIO(object): + def __init__(self, gpio, shadow, value=GPIO_INPUT): + self.gpio = gpio + self.shadow = shadow + self.value = value |