diff --git a/linux-ramdump-parser-v2/parsers/cpr_info.py b/linux-ramdump-parser-v2/parsers/cpr_info.py new file mode 100755 index 0000000000000000000000000000000000000000..d72b7f1c246c85c1dcdf93e576a00dd2bc03c5fd --- /dev/null +++ b/linux-ramdump-parser-v2/parsers/cpr_info.py @@ -0,0 +1,145 @@ +# Copyright (c) 2014, The Linux Foundation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 and +# only version 2 as published by the Free Software Foundation. +# +# 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. + +import linux_list +from print_out import print_out_str +from parser_util import register_parser, RamParser, cleanupString +from collections import defaultdict + +@register_parser('--cpr-info', 'Print CPR information') +class CPRInfo(RamParser): + def __init__(self, *args): + super(CPRInfo, self).__init__(*args) + self.head = '' + self.cprinfo_fields = ['speed_bin', 'cpr_fuse_revision', 'cpr_fuse_map_match', 'num_fuse_corners', 'num_corners', 'corner'] + self.voltages = ['ceiling_volt', 'open_loop_volt', 'last_volt', 'floor_volt'] + self.corner_info = ['cpr_fuse_target_quot', 'quot_adjust', 'corner_map'] + self.value_list = defaultdict(list) + self.attr_list = defaultdict(list) + self.output = [] + + def print_cpr_target_quot(self): + tmp = '{0:20}'.format('Target quotient') + for i in range(self.attr_list['num_corners']): + a = self.value_list['corner_map'][i] + b = self.value_list['cpr_fuse_target_quot'][a-1] - self.value_list['quot_adjust'][i] + tmp += '{0:10} '.format(b) + tmp += '\n' + self.output.append(tmp) + + def print_cpr_info(self): + tmp = '' + # Print RO_SEL value + num_fuse_corn = self.attr_list['num_fuse_corners'] + if num_fuse_corn is not None: + self.output.append('{:40}{:10d}\n'.format('ro_sel', self.value_list['cpr_fuse_ro_sel'][num_fuse_corn-1])) + + # Print all available RO_SEL values + tmp += '{:40}'.format('cpr_fuse_ro_sel') + for ro_sel in self.value_list['cpr_fuse_ro_sel']: + tmp += '{:10} '.format(ro_sel) + tmp += '\n\n' + self.output.append(tmp) + tmp = '' + + self.output.append('{:20}'.format('Corner')) + for i in range(self.attr_list['num_corners']): + tmp += '{:10} '.format(i + 1) + tmp += '\n' + for volt in self.voltages: + tmp += '{:20}'.format(volt) + for i in self.value_list[volt]: + tmp += '{:10} '.format(i) + tmp += '\n' + self.output.append(tmp) + + def get_cpr(self): + # Return if the cpr_regulator_list is not available + cpr = self.ramdump.addr_lookup('cpr_regulator_list') + if cpr is None: + self.output_file.write("NOTE: 'cpr_regulator_list' list not found to extract cpr information") + return + + head = self.ramdump.read_word(cpr) + self.head = cpr + node_offset = self.ramdump.field_offset('struct cpr_regulator', 'list') + cpr_walker = linux_list.ListWalker(self.ramdump, head, node_offset) + cpr_walker.walk(head, self.cpr_walker) + + def get_cpr_fuse_ro_sel(self, node): + entry_offset = self.ramdump.sibling_field_addr(node, 'struct cpr_regulator', 'list', 'cpr_fuse_ro_sel') + entry_addr = self.ramdump.read_word(entry_offset) + i = 1 + while i <= self.attr_list['num_fuse_corners']: + value = self.ramdump.read_int(self.ramdump.array_index(entry_addr, "int", i)) + self.value_list['cpr_fuse_ro_sel'].append(value) + i += 1 + + def get_cpr_volts(self, node, listing): + i = 1 + num_corn = self.attr_list['num_corners'] + while i <= num_corn: + i += 1 + for entry in listing: + entry_offset = self.ramdump.sibling_field_addr(node, 'struct cpr_regulator', 'list', entry) + entry_addr = self.ramdump.read_word(entry_offset) + i = 1 + while i <= num_corn: + value = self.ramdump.read_int(self.ramdump.array_index(entry_addr, "int", i)) + self.value_list[entry].append(value) + i += 1 + + def get_cpr_attrs(self, node): + for attr in self.cprinfo_fields: + attr_offset = self.ramdump.field_offset('struct cpr_regulator', attr) + if attr_offset is not None: + value = self.ramdump.read_s32(node + attr_offset) + self.attr_list[attr] = value + tmp = '{:40}{:10}\n'.format(attr, value) + self.output.append(tmp) + attr_offset = self.ramdump.field_offset('struct cpr_regulator', 'cpr_fuse_redundant') + if attr_offset is not None: + value = self.ramdump.read_bool(node + attr_offset) + # add an extra line here as this is the last attribute before the corner table + tmp = '{:40} {:10}\n'.format('cpr_fuse_redundant', int(value)) + self.output.append(tmp) + + def cpr_walker(self, node): + if node == self.head: + return + + rdesc_addr = self.ramdump.sibling_field_addr(node, 'struct cpr_regulator', 'list', 'rdesc') + rdesc_ptr = self.ramdump.read_word(rdesc_addr + self.ramdump.field_offset('struct regulator_desc', 'name')) + cpr_name = self.ramdump.read_cstring(rdesc_ptr, 48) + cpr_enable = self.ramdump.read_u32(node + self.ramdump.field_offset('struct cpr_regulator', 'enable')) + vdd_apc_addr = self.ramdump.read_word(self.ramdump.sibling_field_addr(node, 'struct cpr_regulator', 'list', 'vdd_apc')) + vdd_apc_uv = self.ramdump.read_u32(vdd_apc_addr + self.ramdump.field_offset('struct regulator', 'min_uV')) + + self.output.append("{:40}{:10s}\n".format('CPR Regulator', cpr_name)) + self.output.append("{:40}{:10}\n".format('CPR Enabled', cpr_enable)) + self.output.append("{:40}{:10d}\n".format('Current Voltage', vdd_apc_uv)) + self.get_cpr_attrs(node) + self.get_cpr_volts(node, self.voltages) + self.get_cpr_volts(node, self.corner_info) + self.get_cpr_fuse_ro_sel(node) + self.print_cpr_info() + self.print_cpr_target_quot() + # print new line for each regulator struct + self.output.append('\n') + self.attr_list.clear() + self.value_list.clear() + + def parse(self): + self.output_file = self.ramdump.open_file('cprinfo.txt') + self.get_cpr() + for i in self.output: + self.output_file.write(i) + self.output_file.close() diff --git a/linux-ramdump-parser-v2/ramdump.py b/linux-ramdump-parser-v2/ramdump.py index 9bc7127c42cd66cdf46e99f9a8f43edb88ef6ad4..681daa0a5d269fe9c0aa8411d4b9bca637cde49c 100644 --- a/linux-ramdump-parser-v2/ramdump.py +++ b/linux-ramdump-parser-v2/ramdump.py @@ -1130,6 +1130,15 @@ class RamDump(): else: return s[0] + def read_bool(self, address, virtual=True, trace=False, cpu=None): + if trace: + print_out_str('reading {0:x}'.format(address)) + s = self.read_string(address, '<?', virtual, trace, cpu) + if s is None: + return None + else: + return s[0] + # returns a value guaranteed to be 64 bits def read_u64(self, address, virtual=True, trace=False, cpu=None): if trace: @@ -1140,6 +1149,16 @@ class RamDump(): else: return s[0] + # returns a value guaranteed to be 32 bits + def read_s32(self, address, virtual=True, trace=False, cpu=None): + if trace: + print_out_str('reading {0:x}'.format(address)) + s = self.read_string(address, '<i', virtual, trace, cpu) + if s is None: + return None + else: + return s[0] + # returns a value guaranteed to be 32 bits def read_u32(self, address, virtual=True, trace=False, cpu=None): if trace: