1# This file describes eFuses controller for ESP32-S3 chip
2#
3# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
4#
5# SPDX-License-Identifier: GPL-2.0-or-later
6
7import reedsolo
8
9from .mem_definition import EfuseDefineBlocks, EfuseDefineFields, EfuseDefineRegisters
10from ..emulate_efuse_controller_base import EmulateEfuseControllerBase, FatalError
11
12
13class EmulateEfuseController(EmulateEfuseControllerBase):
14    """The class for virtual efuse operation. Using for HOST_TEST."""
15
16    CHIP_NAME = "ESP32-S3"
17    mem = None
18    debug = False
19    Blocks = EfuseDefineBlocks
20    Fields = EfuseDefineFields
21    REGS = EfuseDefineRegisters
22
23    def __init__(self, efuse_file=None, debug=False):
24        super(EmulateEfuseController, self).__init__(efuse_file, debug)
25        self.write_reg(self.REGS.EFUSE_STATUS_REG, 1)
26
27    """ esptool method start >>"""
28
29    def get_major_chip_version(self):
30        return 0
31
32    def get_minor_chip_version(self):
33        return 2
34
35    def get_crystal_freq(self):
36        return 40  # MHz (common for all chips)
37
38    def get_security_info(self):
39        return {
40            "flags": 0,
41            "flash_crypt_cnt": 0,
42            "key_purposes": 0,
43            "chip_id": 0,
44            "api_version": 0,
45        }
46
47    """ << esptool method end """
48
49    def handle_writing_event(self, addr, value):
50        if addr == self.REGS.EFUSE_CMD_REG:
51            if value & self.REGS.EFUSE_PGM_CMD:
52                self.copy_blocks_wr_regs_to_rd_regs(updated_block=(value >> 2) & 0xF)
53                self.clean_blocks_wr_regs()
54                self.check_rd_protection_area()
55                self.write_reg(addr, 0)
56                self.write_reg(self.REGS.EFUSE_STATUS_REG, 1)
57            elif value == self.REGS.EFUSE_READ_CMD:
58                self.write_reg(addr, 0)
59                self.write_reg(self.REGS.EFUSE_STATUS_REG, 1)
60                self.save_to_file()
61
62    def get_bitlen_of_block(self, blk, wr=False):
63        if blk.id == 0:
64            if wr:
65                return 32 * 8
66            else:
67                return 32 * blk.len
68        else:
69            if wr:
70                rs_coding = 32 * 3
71                return 32 * 8 + rs_coding
72            else:
73                return 32 * blk.len
74
75    def handle_coding_scheme(self, blk, data):
76        if blk.id != 0:
77            # CODING_SCHEME RS applied only for all blocks except BLK0.
78            coded_bytes = 12
79            data.pos = coded_bytes * 8
80            plain_data = data.readlist("32*uint:8")[::-1]
81            # takes 32 bytes
82            # apply RS encoding
83            rs = reedsolo.RSCodec(coded_bytes)
84            # 32 byte of data + 12 bytes RS
85            calc_encoded_data = list(rs.encode([x for x in plain_data]))
86            data.pos = 0
87            if calc_encoded_data != data.readlist("44*uint:8")[::-1]:
88                raise FatalError("Error in coding scheme data")
89            data = data[coded_bytes * 8 :]
90        if blk.len < 8:
91            data = data[(8 - blk.len) * 32 :]
92        return data
93