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