1*9c5db199SXin Li# Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 3*9c5db199SXin Li# found in the LICENSE file. 4*9c5db199SXin Li 5*9c5db199SXin Li"""A utility to program ChromeOS devices' firmware using servo. 6*9c5db199SXin Li 7*9c5db199SXin LiThis utility expects the DUT to be connected to a servo device. This allows us 8*9c5db199SXin Lito put the DUT into the required state and to actually program the DUT's 9*9c5db199SXin Lifirmware using FTDI, USB and/or serial interfaces provided by servo. 10*9c5db199SXin Li 11*9c5db199SXin LiServo state is preserved across the programming process. 12*9c5db199SXin Li""" 13*9c5db199SXin Li 14*9c5db199SXin Liimport glob 15*9c5db199SXin Liimport logging 16*9c5db199SXin Liimport os 17*9c5db199SXin Liimport re 18*9c5db199SXin Liimport site 19*9c5db199SXin Liimport time 20*9c5db199SXin Liimport xml.etree.ElementTree 21*9c5db199SXin Li 22*9c5db199SXin Lifrom autotest_lib.client.common_lib import error 23*9c5db199SXin Lifrom autotest_lib.server.cros.faft.utils.config import Config as FAFTConfig 24*9c5db199SXin Li 25*9c5db199SXin Li 26*9c5db199SXin Li# Number of seconds for program EC/BIOS to time out. 27*9c5db199SXin LiFIRMWARE_PROGRAM_TIMEOUT_SEC = 1800 28*9c5db199SXin Li 29*9c5db199SXin Liclass ProgrammerError(Exception): 30*9c5db199SXin Li """Local exception class wrapper.""" 31*9c5db199SXin Li pass 32*9c5db199SXin Li 33*9c5db199SXin Li 34*9c5db199SXin Liclass _BaseProgrammer(object): 35*9c5db199SXin Li """Class implementing base programmer services. 36*9c5db199SXin Li 37*9c5db199SXin Li Private attributes: 38*9c5db199SXin Li _servo: a servo object controlling the servo device 39*9c5db199SXin Li _servo_host: a host object running commands like 'flashrom' 40*9c5db199SXin Li _servo_prog_state: a tuple of strings of "<control>:<value>" pairs, 41*9c5db199SXin Li listing servo controls and their required values for 42*9c5db199SXin Li programming 43*9c5db199SXin Li _servo_prog_state_delay: time in second to wait after changing servo 44*9c5db199SXin Li controls for programming. 45*9c5db199SXin Li _servo_saved_state: a list of the same elements as _servo_prog_state, 46*9c5db199SXin Li those which need to be restored after programming 47*9c5db199SXin Li _program_cmd: a string, the shell command to run on the servo host 48*9c5db199SXin Li to actually program the firmware. Dependent on 49*9c5db199SXin Li firmware/hardware type, set by subclasses. 50*9c5db199SXin Li """ 51*9c5db199SXin Li 52*9c5db199SXin Li def __init__(self, servo, req_list, servo_host=None): 53*9c5db199SXin Li """Base constructor. 54*9c5db199SXin Li @param servo: a servo object controlling the servo device 55*9c5db199SXin Li @param req_list: a list of strings, names of the utilities required 56*9c5db199SXin Li to be in the path for the programmer to succeed 57*9c5db199SXin Li @param servo_host: a host object to execute commands. Default to None, 58*9c5db199SXin Li using the host object from the above servo object 59*9c5db199SXin Li """ 60*9c5db199SXin Li self._servo = servo 61*9c5db199SXin Li self._servo_prog_state = () 62*9c5db199SXin Li self._servo_prog_state_delay = 0 63*9c5db199SXin Li self._servo_saved_state = [] 64*9c5db199SXin Li self._program_cmd = '' 65*9c5db199SXin Li self._servo_host = servo_host 66*9c5db199SXin Li if self._servo_host is None: 67*9c5db199SXin Li self._servo_host = self._servo._servo_host 68*9c5db199SXin Li 69*9c5db199SXin Li try: 70*9c5db199SXin Li self._servo_host.run('which %s' % ' '.join(req_list)) 71*9c5db199SXin Li except error.AutoservRunError: 72*9c5db199SXin Li # TODO: We turn this exception into a warn since the fw programmer 73*9c5db199SXin Li # is not working right now, and some systems do not package the 74*9c5db199SXin Li # required utilities its checking for. 75*9c5db199SXin Li # We should reinstate this exception once the programmer is working 76*9c5db199SXin Li # to indicate the missing utilities earlier in the test cycle. 77*9c5db199SXin Li # Bug chromium:371011 filed to track this. 78*9c5db199SXin Li logging.warning("Ignoring exception when verify required bins : %s", 79*9c5db199SXin Li ' '.join(req_list)) 80*9c5db199SXin Li 81*9c5db199SXin Li 82*9c5db199SXin Li def _set_servo_state(self): 83*9c5db199SXin Li """Set servo for programming, while saving the current state.""" 84*9c5db199SXin Li logging.debug("Setting servo state for programming") 85*9c5db199SXin Li for item in self._servo_prog_state: 86*9c5db199SXin Li key, value = item.split(':') 87*9c5db199SXin Li try: 88*9c5db199SXin Li present = self._servo.get(key) 89*9c5db199SXin Li except error.TestFail: 90*9c5db199SXin Li logging.warning('Missing servo control: %s', key) 91*9c5db199SXin Li continue 92*9c5db199SXin Li if present == 'not_applicable': 93*9c5db199SXin Li # control is has no bearing in this servo config so ignore it. 94*9c5db199SXin Li logging.debug('Servo control %s is NA .. skipping', key) 95*9c5db199SXin Li continue 96*9c5db199SXin Li if present != value: 97*9c5db199SXin Li self._servo_saved_state.append('%s:%s' % (key, present)) 98*9c5db199SXin Li self._servo.set(key, value) 99*9c5db199SXin Li time.sleep(self._servo_prog_state_delay) 100*9c5db199SXin Li 101*9c5db199SXin Li 102*9c5db199SXin Li def _restore_servo_state(self): 103*9c5db199SXin Li """Restore previously saved servo state.""" 104*9c5db199SXin Li logging.debug("Restoring servo state after programming") 105*9c5db199SXin Li self._servo_saved_state.reverse() # Do it in the reverse order. 106*9c5db199SXin Li for item in self._servo_saved_state: 107*9c5db199SXin Li key, value = item.split(':') 108*9c5db199SXin Li self._servo.set(key, value) 109*9c5db199SXin Li 110*9c5db199SXin Li 111*9c5db199SXin Li def program(self): 112*9c5db199SXin Li """Program the firmware as configured by a subclass.""" 113*9c5db199SXin Li self._set_servo_state() 114*9c5db199SXin Li try: 115*9c5db199SXin Li logging.debug("Programmer command: %s", self._program_cmd) 116*9c5db199SXin Li self._servo_host.run(self._program_cmd, 117*9c5db199SXin Li timeout=FIRMWARE_PROGRAM_TIMEOUT_SEC) 118*9c5db199SXin Li finally: 119*9c5db199SXin Li self._restore_servo_state() 120*9c5db199SXin Li 121*9c5db199SXin Li 122*9c5db199SXin Liclass FlashromProgrammer(_BaseProgrammer): 123*9c5db199SXin Li """Class for programming AP flashrom.""" 124*9c5db199SXin Li 125*9c5db199SXin Li def __init__(self, servo, keep_ro=False): 126*9c5db199SXin Li """Configure required servo state. 127*9c5db199SXin Li 128*9c5db199SXin Li @param servo: a servo object controlling the servo device 129*9c5db199SXin Li @param keep_ro: True to keep the RO portion unchanged 130*9c5db199SXin Li """ 131*9c5db199SXin Li super(FlashromProgrammer, self).__init__(servo, ['flashrom',]) 132*9c5db199SXin Li self._keep_ro = keep_ro 133*9c5db199SXin Li self._fw_path = None 134*9c5db199SXin Li self.init_section_paths('/tmp') 135*9c5db199SXin Li self._servo_version = self._servo.get_servo_version(active=True) 136*9c5db199SXin Li self._servo_serials = self._servo._server.get_servo_serials() 137*9c5db199SXin Li 138*9c5db199SXin Li 139*9c5db199SXin Li def init_section_paths(self, tmp_path): 140*9c5db199SXin Li """Update section paths to use the tmp directory""" 141*9c5db199SXin Li self._tmp_path = tmp_path 142*9c5db199SXin Li self._fw_main = os.path.join(self._tmp_path, 'fw_main') 143*9c5db199SXin Li self._wp_ro = os.path.join(self._tmp_path, 'wp_ro') 144*9c5db199SXin Li self._ro_vpd = os.path.join(self._tmp_path, 'ro_vpd') 145*9c5db199SXin Li self._rw_vpd = os.path.join(self._tmp_path, 'rw_vpd') 146*9c5db199SXin Li self._gbb = os.path.join(self._tmp_path, 'gbb') 147*9c5db199SXin Li 148*9c5db199SXin Li 149*9c5db199SXin Li def program(self): 150*9c5db199SXin Li """Program the firmware but preserve VPD and HWID.""" 151*9c5db199SXin Li assert self._fw_path is not None 152*9c5db199SXin Li self._set_servo_state() 153*9c5db199SXin Li try: 154*9c5db199SXin Li wp_ro_section = [('WP_RO', self._wp_ro)] 155*9c5db199SXin Li rw_vpd_section = [('RW_VPD', self._rw_vpd)] 156*9c5db199SXin Li ro_vpd_section = [('RO_VPD', self._ro_vpd)] 157*9c5db199SXin Li gbb_section = [('GBB', self._gbb)] 158*9c5db199SXin Li if self._keep_ro: 159*9c5db199SXin Li # Keep the whole RO portion 160*9c5db199SXin Li preserved_sections = wp_ro_section + rw_vpd_section 161*9c5db199SXin Li else: 162*9c5db199SXin Li preserved_sections = ro_vpd_section + rw_vpd_section 163*9c5db199SXin Li 164*9c5db199SXin Li servo_v2_programmer = 'ft2232_spi:type=google-servo-v2' 165*9c5db199SXin Li servo_v3_programmer = 'linux_spi' 166*9c5db199SXin Li servo_v4_with_micro_programmer = 'raiden_debug_spi' 167*9c5db199SXin Li servo_v4_with_ccd_programmer = 'raiden_debug_spi:target=AP' 168*9c5db199SXin Li 169*9c5db199SXin Li if self._servo_version == 'servo_v2': 170*9c5db199SXin Li programmer = servo_v2_programmer 171*9c5db199SXin Li servo_serial = self._servo_serials.get('main') 172*9c5db199SXin Li if servo_serial: 173*9c5db199SXin Li programmer += ',serial=%s' % servo_serial 174*9c5db199SXin Li elif self._servo_version == 'servo_v3': 175*9c5db199SXin Li programmer = servo_v3_programmer 176*9c5db199SXin Li elif 'with_servo_micro' in self._servo_version: 177*9c5db199SXin Li # When a uServo is connected to a DUT with CCD support, the 178*9c5db199SXin Li # firmware programmer will always use the uServo to program. 179*9c5db199SXin Li servo_micro_serial = self._servo_serials.get('servo_micro') 180*9c5db199SXin Li programmer = servo_v4_with_micro_programmer 181*9c5db199SXin Li programmer += ':serial=%s' % servo_micro_serial 182*9c5db199SXin Li elif 'with_ccd' in self._servo_version: 183*9c5db199SXin Li ccd_serial = self._servo_serials.get('ccd') 184*9c5db199SXin Li programmer = servo_v4_with_ccd_programmer 185*9c5db199SXin Li programmer += ',serial=%s' % ccd_serial 186*9c5db199SXin Li else: 187*9c5db199SXin Li raise Exception('Servo version %s is not supported.' % 188*9c5db199SXin Li self._servo_version) 189*9c5db199SXin Li # Save needed sections from current firmware 190*9c5db199SXin Li for section in preserved_sections + gbb_section: 191*9c5db199SXin Li self._servo_host.run(' '.join([ 192*9c5db199SXin Li 'flashrom', '-V', '-p', programmer, '-r', 193*9c5db199SXin Li '-i', '%s:%s' % section]), 194*9c5db199SXin Li timeout=FIRMWARE_PROGRAM_TIMEOUT_SEC) 195*9c5db199SXin Li 196*9c5db199SXin Li # Pack the saved VPD into new firmware 197*9c5db199SXin Li self._servo_host.run('cp %s %s' % (self._fw_path, self._fw_main)) 198*9c5db199SXin Li img_size = self._servo_host.run_output( 199*9c5db199SXin Li "stat -c '%%s' %s" % self._fw_main) 200*9c5db199SXin Li pack_cmd = ['flashrom', 201*9c5db199SXin Li '-p', 'dummy:image=%s,size=%s,emulate=VARIABLE_SIZE' % ( 202*9c5db199SXin Li self._fw_main, img_size), 203*9c5db199SXin Li '-w', self._fw_main] 204*9c5db199SXin Li for section in preserved_sections: 205*9c5db199SXin Li pack_cmd.extend(['-i', '%s:%s' % section]) 206*9c5db199SXin Li self._servo_host.run(' '.join(pack_cmd), 207*9c5db199SXin Li timeout=FIRMWARE_PROGRAM_TIMEOUT_SEC) 208*9c5db199SXin Li 209*9c5db199SXin Li # HWID is inside the RO portion. Don't preserve HWID if we keep RO. 210*9c5db199SXin Li if not self._keep_ro: 211*9c5db199SXin Li # Read original HWID. The output format is: 212*9c5db199SXin Li # hardware_id: RAMBI TEST A_A 0128 213*9c5db199SXin Li gbb_hwid_output = self._servo_host.run_output( 214*9c5db199SXin Li 'futility gbb -g --hwid %s' % self._gbb) 215*9c5db199SXin Li original_hwid = gbb_hwid_output.split(':', 1)[1].strip() 216*9c5db199SXin Li 217*9c5db199SXin Li # Write HWID to new firmware 218*9c5db199SXin Li self._servo_host.run("futility gbb -s --hwid='%s' %s" % 219*9c5db199SXin Li (original_hwid, self._fw_main)) 220*9c5db199SXin Li 221*9c5db199SXin Li # Flash the new firmware 222*9c5db199SXin Li self._servo_host.run(' '.join([ 223*9c5db199SXin Li 'flashrom', '-V', '-p', programmer, 224*9c5db199SXin Li '-w', self._fw_main]), timeout=FIRMWARE_PROGRAM_TIMEOUT_SEC) 225*9c5db199SXin Li finally: 226*9c5db199SXin Li self._servo.get_power_state_controller().reset() 227*9c5db199SXin Li self._restore_servo_state() 228*9c5db199SXin Li 229*9c5db199SXin Li 230*9c5db199SXin Li def prepare_programmer(self, path): 231*9c5db199SXin Li """Prepare programmer for programming. 232*9c5db199SXin Li 233*9c5db199SXin Li @param path: a string, name of the file containing the firmware image. 234*9c5db199SXin Li """ 235*9c5db199SXin Li self._fw_path = path 236*9c5db199SXin Li self.init_section_paths(os.path.dirname(path)) 237*9c5db199SXin Li 238*9c5db199SXin Li # If servo is running with servo v4, there may be two programming 239*9c5db199SXin Li # devices. Determine the programmer based on the active one. 240*9c5db199SXin Li self._servo_version = self._servo.get_servo_version(active=True) 241*9c5db199SXin Li 242*9c5db199SXin Li # CCD takes care holding AP/EC. Don't need the following steps. 243*9c5db199SXin Li if 'with_ccd' not in self._servo_version: 244*9c5db199SXin Li faft_config = FAFTConfig(self._servo.get_board()) 245*9c5db199SXin Li self._servo_prog_state_delay = faft_config.servo_prog_state_delay 246*9c5db199SXin Li self._servo_prog_state = ( 247*9c5db199SXin Li 'spi2_vref:%s' % faft_config.spi_voltage, 248*9c5db199SXin Li 'spi2_buf_en:on', 249*9c5db199SXin Li 'spi2_buf_on_flex_en:on', 250*9c5db199SXin Li 'spi_hold:off', 251*9c5db199SXin Li 'cold_reset:on', 252*9c5db199SXin Li 'usbpd_reset:on', 253*9c5db199SXin Li ) 254*9c5db199SXin Li 255*9c5db199SXin Li 256*9c5db199SXin Liclass FlashECProgrammer(_BaseProgrammer): 257*9c5db199SXin Li """Class for programming AP flashrom.""" 258*9c5db199SXin Li 259*9c5db199SXin Li def __init__(self, servo, host=None, ec_chip=None): 260*9c5db199SXin Li """Configure required servo state. 261*9c5db199SXin Li 262*9c5db199SXin Li @param servo: a servo object controlling the servo device 263*9c5db199SXin Li @param host: a host object to execute commands. Default to None, 264*9c5db199SXin Li using the host object from the above servo object, i.e. 265*9c5db199SXin Li a servo host. A CrOS host object can be passed here 266*9c5db199SXin Li such that it executes commands on the CrOS device. 267*9c5db199SXin Li @param ec_chip: a string of EC chip. Default to None, using the 268*9c5db199SXin Li EC chip name reported by servo, the primary EC. 269*9c5db199SXin Li Can pass a different chip name, for the case of 270*9c5db199SXin Li the base EC. 271*9c5db199SXin Li 272*9c5db199SXin Li """ 273*9c5db199SXin Li super(FlashECProgrammer, self).__init__(servo, ['flash_ec'], host) 274*9c5db199SXin Li self._servo_version = self._servo.get_servo_version() 275*9c5db199SXin Li self._ec_chip = ec_chip 276*9c5db199SXin Li 277*9c5db199SXin Li def prepare_programmer(self, image): 278*9c5db199SXin Li """Prepare programmer for programming. 279*9c5db199SXin Li 280*9c5db199SXin Li @param image: string with the location of the image file 281*9c5db199SXin Li """ 282*9c5db199SXin Li if self._ec_chip is None: 283*9c5db199SXin Li self._ec_chip = self._servo.get('ec_chip') 284*9c5db199SXin Li 285*9c5db199SXin Li # If servo is running with servo v4, there may be two programming 286*9c5db199SXin Li # devices. Determine the programmer based on the active one. 287*9c5db199SXin Li self._servo_version = self._servo.get_servo_version(active=True) 288*9c5db199SXin Li 289*9c5db199SXin Li # Get the port of servod. flash_ec may use it to talk to servod. 290*9c5db199SXin Li port = self._servo._servo_host.servo_port 291*9c5db199SXin Li self._program_cmd = ('flash_ec --chip=%s --image=%s --port=%d' % 292*9c5db199SXin Li (self._ec_chip, image, port)) 293*9c5db199SXin Li if self._ec_chip == 'stm32': 294*9c5db199SXin Li self._program_cmd += ' --bitbang_rate=57600' 295*9c5db199SXin Li self._program_cmd += ' --verify' 296*9c5db199SXin Li self._program_cmd += ' --verbose' 297*9c5db199SXin Li 298*9c5db199SXin Li 299*9c5db199SXin Liclass ProgrammerV2(object): 300*9c5db199SXin Li """Main programmer class which provides programmer for BIOS and EC with 301*9c5db199SXin Li servo V2.""" 302*9c5db199SXin Li 303*9c5db199SXin Li def __init__(self, servo): 304*9c5db199SXin Li self._servo = servo 305*9c5db199SXin Li self._valid_boards = self._get_valid_v2_boards() 306*9c5db199SXin Li self._bios_programmer = self._factory_bios(self._servo) 307*9c5db199SXin Li self._ec_programmer = self._factory_ec(self._servo) 308*9c5db199SXin Li 309*9c5db199SXin Li 310*9c5db199SXin Li @staticmethod 311*9c5db199SXin Li def _get_valid_v2_boards(): 312*9c5db199SXin Li """Greps servod config files to look for valid v2 boards. 313*9c5db199SXin Li 314*9c5db199SXin Li @return A list of valid board names. 315*9c5db199SXin Li """ 316*9c5db199SXin Li site_packages_paths = site.getsitepackages() 317*9c5db199SXin Li SERVOD_CONFIG_DATA_DIR = None 318*9c5db199SXin Li for p in site_packages_paths: 319*9c5db199SXin Li servo_data_path = os.path.join(p, 'servo', 'data') 320*9c5db199SXin Li if os.path.exists(servo_data_path): 321*9c5db199SXin Li SERVOD_CONFIG_DATA_DIR = servo_data_path 322*9c5db199SXin Li break 323*9c5db199SXin Li if not SERVOD_CONFIG_DATA_DIR: 324*9c5db199SXin Li raise ProgrammerError( 325*9c5db199SXin Li 'Unable to locate data directory of Python servo module') 326*9c5db199SXin Li SERVOFLEX_V2_R0_P50_CONFIG = 'servoflex_v2_r0_p50.xml' 327*9c5db199SXin Li SERVO_CONFIG_GLOB = 'servo_*_overlay.xml' 328*9c5db199SXin Li SERVO_CONFIG_REGEXP = 'servo_(?P<board>.+)_overlay.xml' 329*9c5db199SXin Li 330*9c5db199SXin Li def is_v2_compatible_board(board_config_path): 331*9c5db199SXin Li """Check if the given board config file is v2-compatible. 332*9c5db199SXin Li 333*9c5db199SXin Li @param board_config_path: Path to a board config XML file. 334*9c5db199SXin Li 335*9c5db199SXin Li @return True if the board is v2-compatible; False otherwise. 336*9c5db199SXin Li """ 337*9c5db199SXin Li configs = [] 338*9c5db199SXin Li def get_all_includes(config_path): 339*9c5db199SXin Li """Get all included XML config names in the given config file. 340*9c5db199SXin Li 341*9c5db199SXin Li @param config_path: Path to a servo config file. 342*9c5db199SXin Li """ 343*9c5db199SXin Li root = xml.etree.ElementTree.parse(config_path).getroot() 344*9c5db199SXin Li for element in root.findall('include'): 345*9c5db199SXin Li include_name = element.find('name').text 346*9c5db199SXin Li configs.append(include_name) 347*9c5db199SXin Li get_all_includes(os.path.join( 348*9c5db199SXin Li SERVOD_CONFIG_DATA_DIR, include_name)) 349*9c5db199SXin Li 350*9c5db199SXin Li get_all_includes(board_config_path) 351*9c5db199SXin Li return True if SERVOFLEX_V2_R0_P50_CONFIG in configs else False 352*9c5db199SXin Li 353*9c5db199SXin Li result = [] 354*9c5db199SXin Li board_overlays = glob.glob( 355*9c5db199SXin Li os.path.join(SERVOD_CONFIG_DATA_DIR, SERVO_CONFIG_GLOB)) 356*9c5db199SXin Li for overlay_path in board_overlays: 357*9c5db199SXin Li if is_v2_compatible_board(overlay_path): 358*9c5db199SXin Li result.append(re.search(SERVO_CONFIG_REGEXP, 359*9c5db199SXin Li overlay_path).group('board')) 360*9c5db199SXin Li return result 361*9c5db199SXin Li 362*9c5db199SXin Li 363*9c5db199SXin Li def _get_flashrom_programmer(self, servo): 364*9c5db199SXin Li """Gets a proper flashrom programmer. 365*9c5db199SXin Li 366*9c5db199SXin Li @param servo: A servo object. 367*9c5db199SXin Li 368*9c5db199SXin Li @return A programmer for flashrom. 369*9c5db199SXin Li """ 370*9c5db199SXin Li return FlashromProgrammer(servo) 371*9c5db199SXin Li 372*9c5db199SXin Li 373*9c5db199SXin Li def _factory_bios(self, servo): 374*9c5db199SXin Li """Instantiates and returns (bios, ec) programmers for the board. 375*9c5db199SXin Li 376*9c5db199SXin Li @param servo: A servo object. 377*9c5db199SXin Li 378*9c5db199SXin Li @return A programmer for ec. If the programmer is not supported 379*9c5db199SXin Li for the board, None will be returned. 380*9c5db199SXin Li """ 381*9c5db199SXin Li _bios_prog = None 382*9c5db199SXin Li _board = servo.get_board() 383*9c5db199SXin Li 384*9c5db199SXin Li logging.debug('Setting up BIOS programmer for board: %s', _board) 385*9c5db199SXin Li if _board in self._valid_boards: 386*9c5db199SXin Li _bios_prog = self._get_flashrom_programmer(servo) 387*9c5db199SXin Li else: 388*9c5db199SXin Li logging.warning('No BIOS programmer found for board: %s', _board) 389*9c5db199SXin Li 390*9c5db199SXin Li return _bios_prog 391*9c5db199SXin Li 392*9c5db199SXin Li 393*9c5db199SXin Li def _factory_ec(self, servo): 394*9c5db199SXin Li """Instantiates and returns ec programmer for the board. 395*9c5db199SXin Li 396*9c5db199SXin Li @param servo: A servo object. 397*9c5db199SXin Li 398*9c5db199SXin Li @return A programmer for ec. If the programmer is not supported 399*9c5db199SXin Li for the board, None will be returned. 400*9c5db199SXin Li """ 401*9c5db199SXin Li _ec_prog = None 402*9c5db199SXin Li _board = servo.get_board() 403*9c5db199SXin Li 404*9c5db199SXin Li logging.debug('Setting up EC programmer for board: %s', _board) 405*9c5db199SXin Li if _board in self._valid_boards: 406*9c5db199SXin Li _ec_prog = FlashECProgrammer(servo) 407*9c5db199SXin Li else: 408*9c5db199SXin Li logging.warning('No EC programmer found for board: %s', _board) 409*9c5db199SXin Li 410*9c5db199SXin Li return _ec_prog 411*9c5db199SXin Li 412*9c5db199SXin Li 413*9c5db199SXin Li def program_bios(self, image): 414*9c5db199SXin Li """Programs the DUT with provide bios image. 415*9c5db199SXin Li 416*9c5db199SXin Li @param image: (required) location of bios image file. 417*9c5db199SXin Li 418*9c5db199SXin Li """ 419*9c5db199SXin Li self._bios_programmer.prepare_programmer(image) 420*9c5db199SXin Li self._bios_programmer.program() 421*9c5db199SXin Li 422*9c5db199SXin Li 423*9c5db199SXin Li def program_ec(self, image): 424*9c5db199SXin Li """Programs the DUT with provide ec image. 425*9c5db199SXin Li 426*9c5db199SXin Li @param image: (required) location of ec image file. 427*9c5db199SXin Li 428*9c5db199SXin Li """ 429*9c5db199SXin Li self._ec_programmer.prepare_programmer(image) 430*9c5db199SXin Li self._ec_programmer.program() 431*9c5db199SXin Li 432*9c5db199SXin Li 433*9c5db199SXin Liclass ProgrammerV2RwOnly(ProgrammerV2): 434*9c5db199SXin Li """Main programmer class which provides programmer for only updating the RW 435*9c5db199SXin Li portion of BIOS with servo V2. 436*9c5db199SXin Li 437*9c5db199SXin Li It does nothing on EC, as EC software sync on the next boot will 438*9c5db199SXin Li automatically overwrite the EC RW portion, using the EC RW image inside 439*9c5db199SXin Li the BIOS RW image. 440*9c5db199SXin Li 441*9c5db199SXin Li """ 442*9c5db199SXin Li 443*9c5db199SXin Li def _get_flashrom_programmer(self, servo): 444*9c5db199SXin Li """Gets a proper flashrom programmer. 445*9c5db199SXin Li 446*9c5db199SXin Li @param servo: A servo object. 447*9c5db199SXin Li 448*9c5db199SXin Li @return A programmer for flashrom. 449*9c5db199SXin Li """ 450*9c5db199SXin Li return FlashromProgrammer(servo, keep_ro=True) 451*9c5db199SXin Li 452*9c5db199SXin Li 453*9c5db199SXin Li def program_ec(self, image): 454*9c5db199SXin Li """Programs the DUT with provide ec image. 455*9c5db199SXin Li 456*9c5db199SXin Li @param image: (required) location of ec image file. 457*9c5db199SXin Li 458*9c5db199SXin Li """ 459*9c5db199SXin Li # Do nothing. EC software sync will update the EC RW. 460*9c5db199SXin Li pass 461*9c5db199SXin Li 462*9c5db199SXin Li 463*9c5db199SXin Liclass ProgrammerV3(object): 464*9c5db199SXin Li """Main programmer class which provides programmer for BIOS and EC with 465*9c5db199SXin Li servo V3. 466*9c5db199SXin Li 467*9c5db199SXin Li Different from programmer for servo v2, programmer for servo v3 does not 468*9c5db199SXin Li try to validate if the board can use servo V3 to update firmware. As long as 469*9c5db199SXin Li the servod process running in beagblebone with given board, the program will 470*9c5db199SXin Li attempt to flash bios and ec. 471*9c5db199SXin Li 472*9c5db199SXin Li """ 473*9c5db199SXin Li 474*9c5db199SXin Li def __init__(self, servo): 475*9c5db199SXin Li self._servo = servo 476*9c5db199SXin Li self._bios_programmer = FlashromProgrammer(servo) 477*9c5db199SXin Li self._ec_programmer = FlashECProgrammer(servo) 478*9c5db199SXin Li 479*9c5db199SXin Li 480*9c5db199SXin Li def program_bios(self, image): 481*9c5db199SXin Li """Programs the DUT with provide bios image. 482*9c5db199SXin Li 483*9c5db199SXin Li @param image: (required) location of bios image file. 484*9c5db199SXin Li 485*9c5db199SXin Li """ 486*9c5db199SXin Li self._bios_programmer.prepare_programmer(image) 487*9c5db199SXin Li self._bios_programmer.program() 488*9c5db199SXin Li 489*9c5db199SXin Li 490*9c5db199SXin Li def program_ec(self, image): 491*9c5db199SXin Li """Programs the DUT with provide ec image. 492*9c5db199SXin Li 493*9c5db199SXin Li @param image: (required) location of ec image file. 494*9c5db199SXin Li 495*9c5db199SXin Li """ 496*9c5db199SXin Li self._ec_programmer.prepare_programmer(image) 497*9c5db199SXin Li self._ec_programmer.program() 498*9c5db199SXin Li 499*9c5db199SXin Li 500*9c5db199SXin Liclass ProgrammerV3RwOnly(ProgrammerV3): 501*9c5db199SXin Li """Main programmer class which provides programmer for only updating the RW 502*9c5db199SXin Li portion of BIOS with servo V3. 503*9c5db199SXin Li 504*9c5db199SXin Li It does nothing on EC, as EC software sync on the next boot will 505*9c5db199SXin Li automatically overwrite the EC RW portion, using the EC RW image inside 506*9c5db199SXin Li the BIOS RW image. 507*9c5db199SXin Li 508*9c5db199SXin Li """ 509*9c5db199SXin Li 510*9c5db199SXin Li def __init__(self, servo): 511*9c5db199SXin Li self._servo = servo 512*9c5db199SXin Li self._bios_programmer = FlashromProgrammer(servo, keep_ro=True) 513*9c5db199SXin Li 514*9c5db199SXin Li 515*9c5db199SXin Li def program_ec(self, image): 516*9c5db199SXin Li """Programs the DUT with provide ec image. 517*9c5db199SXin Li 518*9c5db199SXin Li @param image: (required) location of ec image file. 519*9c5db199SXin Li 520*9c5db199SXin Li """ 521*9c5db199SXin Li # Do nothing. EC software sync will update the EC RW. 522*9c5db199SXin Li pass 523