1# Copyright (c) 2016, Xilinx Inc. Michal Simek 2# Copyright (c) 2017, Xiphos Systems Corp. All rights reserved. 3# 4# SPDX-License-Identifier: GPL-2.0 5 6import re 7import pytest 8import random 9import u_boot_utils 10 11""" 12Note: This test relies on boardenv_* containing configuration values to define 13which SPI Flash areas are available for testing. Without this, this test will 14be automatically skipped. 15For example: 16 17# A list of sections of Flash memory to be tested. 18env__sf_configs = ( 19 { 20 # Where in SPI Flash should the test operate. 21 'offset': 0x00000000, 22 # This value is optional. 23 # If present, specifies the [[bus:]cs] argument used in `sf probe` 24 # If missing, defaults to 0. 25 'id': '0:1', 26 # This value is optional. 27 # If set as a number, specifies the speed of the SPI Flash. 28 # If set as an array of 2, specifies a range for a random speed. 29 # If missing, defaults to 0. 30 'speed': 1000000, 31 # This value is optional. 32 # If present, specifies the size to use for read/write operations. 33 # If missing, the SPI Flash page size is used as a default (based on 34 # the `sf probe` output). 35 'len': 0x10000, 36 # This value is optional. 37 # If present, specifies if the test can write to Flash offset 38 # If missing, defaults to False. 39 'writeable': False, 40 # This value is optional. 41 # If present, specifies the expected CRC32 value of the flash area. 42 # If missing, extra check is ignored. 43 'crc32': 0xCAFECAFE, 44 }, 45) 46""" 47 48def sf_prepare(u_boot_console, env__sf_config): 49 """Check global state of the SPI Flash before running any test. 50 51 Args: 52 u_boot_console: A U-Boot console connection. 53 env__sf_config: The single SPI Flash device configuration on which to 54 run the tests. 55 56 Returns: 57 sf_params: a dictionary of SPI Flash parameters. 58 """ 59 60 sf_params = {} 61 sf_params['ram_base'] = u_boot_utils.find_ram_base(u_boot_console) 62 63 probe_id = env__sf_config.get('id', 0) 64 speed = env__sf_config.get('speed', 0) 65 if isinstance(speed, int): 66 sf_params['speed'] = speed 67 else: 68 assert len(speed) == 2, "If speed is a list, it must have 2 entries" 69 sf_params['speed'] = random.randint(speed[0], speed[1]) 70 71 cmd = 'sf probe %d %d' % (probe_id, sf_params['speed']) 72 73 output = u_boot_console.run_command(cmd) 74 assert 'SF: Detected' in output, 'No Flash device available' 75 76 m = re.search('page size (.+?) Bytes', output) 77 assert m, 'SPI Flash page size not recognized' 78 sf_params['page_size'] = int(m.group(1)) 79 80 m = re.search('erase size (.+?) KiB', output) 81 assert m, 'SPI Flash erase size not recognized' 82 sf_params['erase_size'] = int(m.group(1)) 83 sf_params['erase_size'] *= 1024 84 85 m = re.search('total (.+?) MiB', output) 86 assert m, 'SPI Flash total size not recognized' 87 sf_params['total_size'] = int(m.group(1)) 88 sf_params['total_size'] *= 1024 * 1024 89 90 assert 'offset' in env__sf_config, \ 91 '\'offset\' is required for this test.' 92 sf_params['len'] = env__sf_config.get('len', sf_params['erase_size']) 93 94 assert not env__sf_config['offset'] % sf_params['erase_size'], \ 95 'offset not multiple of erase size.' 96 assert not sf_params['len'] % sf_params['erase_size'], \ 97 'erase length not multiple of erase size.' 98 99 assert not (env__sf_config.get('writeable', False) and 100 'crc32' in env__sf_config), \ 101 'Cannot check crc32 on writeable sections' 102 103 return sf_params 104 105def sf_read(u_boot_console, env__sf_config, sf_params): 106 """Helper function used to read and compute the CRC32 value of a section of 107 SPI Flash memory. 108 109 Args: 110 u_boot_console: A U-Boot console connection. 111 env__sf_config: The single SPI Flash device configuration on which to 112 run the tests. 113 sf_params: SPI Flash parameters. 114 115 Returns: 116 CRC32 value of SPI Flash section 117 """ 118 119 addr = sf_params['ram_base'] 120 offset = env__sf_config['offset'] 121 count = sf_params['len'] 122 pattern = random.randint(0, 0xFF) 123 crc_expected = env__sf_config.get('crc32', None) 124 125 cmd = 'mw.b %08x %02x %x' % (addr, pattern, count) 126 u_boot_console.run_command(cmd) 127 crc_pattern = u_boot_utils.crc32(u_boot_console, addr, count) 128 if crc_expected: 129 assert crc_pattern != crc_expected 130 131 cmd = 'sf read %08x %08x %x' % (addr, offset, count) 132 response = u_boot_console.run_command(cmd) 133 assert 'Read: OK' in response, 'Read operation failed' 134 crc_readback = u_boot_utils.crc32(u_boot_console, addr, count) 135 assert crc_pattern != crc_readback, 'sf read did not update RAM content.' 136 if crc_expected: 137 assert crc_readback == crc_expected 138 139 return crc_readback 140 141def sf_update(u_boot_console, env__sf_config, sf_params): 142 """Helper function used to update a section of SPI Flash memory. 143 144 Args: 145 u_boot_console: A U-Boot console connection. 146 env__sf_config: The single SPI Flash device configuration on which to 147 run the tests. 148 149 Returns: 150 CRC32 value of SPI Flash section 151 """ 152 153 addr = sf_params['ram_base'] 154 offset = env__sf_config['offset'] 155 count = sf_params['len'] 156 pattern = int(random.random() * 0xFF) 157 158 cmd = 'mw.b %08x %02x %x' % (addr, pattern, count) 159 u_boot_console.run_command(cmd) 160 crc_pattern = u_boot_utils.crc32(u_boot_console, addr, count) 161 162 cmd = 'sf update %08x %08x %x' % (addr, offset, count) 163 u_boot_console.run_command(cmd) 164 crc_readback = sf_read(u_boot_console, env__sf_config, sf_params) 165 166 assert crc_readback == crc_pattern 167 168@pytest.mark.buildconfigspec('cmd_sf') 169@pytest.mark.buildconfigspec('cmd_crc32') 170@pytest.mark.buildconfigspec('cmd_memory') 171def test_sf_read(u_boot_console, env__sf_config): 172 sf_params = sf_prepare(u_boot_console, env__sf_config) 173 sf_read(u_boot_console, env__sf_config, sf_params) 174 175@pytest.mark.buildconfigspec('cmd_sf') 176@pytest.mark.buildconfigspec('cmd_crc32') 177@pytest.mark.buildconfigspec('cmd_memory') 178def test_sf_read_twice(u_boot_console, env__sf_config): 179 sf_params = sf_prepare(u_boot_console, env__sf_config) 180 181 crc1 = sf_read(u_boot_console, env__sf_config, sf_params) 182 sf_params['ram_base'] += 0x100 183 crc2 = sf_read(u_boot_console, env__sf_config, sf_params) 184 185 assert crc1 == crc2, 'CRC32 of two successive read operation do not match' 186 187@pytest.mark.buildconfigspec('cmd_sf') 188@pytest.mark.buildconfigspec('cmd_crc32') 189@pytest.mark.buildconfigspec('cmd_memory') 190def test_sf_erase(u_boot_console, env__sf_config): 191 if not env__sf_config.get('writeable', False): 192 pytest.skip('Flash config is tagged as not writeable') 193 194 sf_params = sf_prepare(u_boot_console, env__sf_config) 195 addr = sf_params['ram_base'] 196 offset = env__sf_config['offset'] 197 count = sf_params['len'] 198 199 cmd = 'sf erase %08x %x' % (offset, count) 200 output = u_boot_console.run_command(cmd) 201 assert 'Erased: OK' in output, 'Erase operation failed' 202 203 cmd = 'mw.b %08x ff %x' % (addr, count) 204 u_boot_console.run_command(cmd) 205 crc_ffs = u_boot_utils.crc32(u_boot_console, addr, count) 206 207 crc_read = sf_read(u_boot_console, env__sf_config, sf_params) 208 assert crc_ffs == crc_read, 'Unexpected CRC32 after erase operation.' 209 210@pytest.mark.buildconfigspec('cmd_sf') 211@pytest.mark.buildconfigspec('cmd_crc32') 212@pytest.mark.buildconfigspec('cmd_memory') 213def test_sf_update(u_boot_console, env__sf_config): 214 if not env__sf_config.get('writeable', False): 215 pytest.skip('Flash config is tagged as not writeable') 216 217 sf_params = sf_prepare(u_boot_console, env__sf_config) 218 sf_update(u_boot_console, env__sf_config, sf_params) 219