sunxi-tools/soc_info.h
Andre Przywara 34c3150898 fel: introduce get_next_soc()
At the moment we can search for a specific SoC in our supported SoC
table by looking for its SoC ID, but we cannot otherwise enumerate all
supported SoCs.

Add a get_next_soc() function that allows iterating over our (internal)
table: The first call will take NULL as an argument, subsequent calls
pass in the pointer returned by the previous call. When we reach the end
of the list, the function returns NULL.

Signed-off-by: Andre Przywara <osp@andrep.de>
2023-10-25 19:55:02 +02:00

149 lines
6.2 KiB
C

/*
* Copyright (C) 2015 Siarhei Siamashka <siarhei.siamashka@gmail.com>
* Copyright (C) 2016 Bernhard Nortmann <bernhard.nortmann@web.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SUNXI_TOOLS_SOC_INFO_H
#define _SUNXI_TOOLS_SOC_INFO_H
#include <stdbool.h>
#include <stdint.h>
/* SoC version information, as retrieved by the FEL protocol */
struct aw_fel_version {
char signature[8];
uint32_t soc_id; /* 0x00162300 */
uint32_t unknown_0a; /* 1 */
uint16_t protocol; /* 1 */
uint8_t unknown_12; /* 0x44 */
uint8_t unknown_13; /* 0x08 */
uint32_t scratchpad; /* 0x7e00 */
uint32_t pad[2]; /* unused */
} __attribute__((packed));
/*
* Buffer for a SoC name string. We want at least 6 + 1 characters, to store
* the hexadecimal ID "0xABCD" for unknown SoCs, plus the terminating NUL.
*/
typedef char soc_name_t[8];
/*
* The 'sram_swap_buffers' structure is used to describe information about
* pairwise memory regions in SRAM, the content of which needs to be exchanged
* before calling the U-Boot SPL code and then exchanged again before returning
* control back to the FEL code from the BROM.
*/
typedef struct {
uint32_t buf1; /* BROM buffer */
uint32_t buf2; /* backup storage location */
uint32_t size; /* buffer size */
} sram_swap_buffers;
/*
* Contains information on the watchdog peripheral, to enable reset
*/
typedef struct {
/* Register that needs to be written to */
uint32_t reg_mode;
/* Value to write to trigger a reset */
uint32_t reg_mode_value;
} watchdog_info;
/*
* sunxi sid sections
*/
typedef struct {
const char *name;
uint32_t offset;
uint32_t size_bits;
} sid_section;
#define SID_SECTION(_name, _offset, _size_bits) { \
.name = _name, \
.offset = _offset, \
.size_bits = _size_bits, \
}
/*
* Each SoC variant may have its own list of memory buffers to be exchanged
* and the information about the placement of the thunk code, which handles
* the transition of execution from the BROM FEL code to the U-Boot SPL and
* back.
*
* Note: the entries in the 'swap_buffers' tables need to be sorted by 'buf1'
* addresses. And the 'buf1' addresses are the BROM data buffers, while 'buf2'
* addresses are the intended backup locations.
*
* Also for performance reasons, we optionally want to have MMU enabled with
* optimal section attributes configured (the code from the BROM should use
* I-cache, writing data to the DRAM area should use write combining). The
* reason is that the BROM FEL protocol implementation moves data using the
* CPU somewhere on the performance critical path when transferring data over
* USB. The older SoC variants (A10/A13/A20/A31/A23) already have MMU enabled
* and we only need to adjust section attributes. The BROM in newer SoC variants
* (A33/A83T/H3) doesn't enable MMU any more, so we need to find some 16K of
* spare space in SRAM to place the translation table there and specify it as
* the 'mmu_tt_addr' field in the 'soc_sram_info' structure. The 'mmu_tt_addr'
* address must be 16K aligned.
*
* If an SoC has the "secure boot" fuse burned, it will enter FEL mode in
* non-secure state, so with the SCR.NS bit set. Since in this mode the
* secure/non-secure state restrictions are actually observed, we suffer
* from several restrictions:
* - No access to the SID information (both via memory mapped and "register").
* - No access to secure SRAM (SRAM A2 on H3/A64/H5).
* - No access to the secure side of the GIC, so it can't be configured to
* be accessible from non-secure world.
* - No RMR trigger on ARMv8 cores to bring the core into AArch64.
* However it has been found out that a simple "smc" call will immediately
* return from monitor mode, but with the NS bit cleared, so access to all
* secure peripherals is suddenly possible.
* The 'needs_smc_workaround_if_zero_word_at_addr' field can be used to
* have a check for this condition (reading from restricted addresses
* typically returns zero) and then activate the SMC workaround if needed.
*/
typedef struct {
uint32_t soc_id; /* ID of the SoC */
const char *name; /* human-readable SoC name string */
uint32_t spl_addr; /* SPL load address */
uint32_t scratch_addr; /* A safe place to upload & run code */
uint32_t thunk_addr; /* Address of the thunk code */
uint32_t thunk_size; /* Maximal size of the thunk code */
bool needs_l2en; /* Set the L2EN bit */
uint32_t mmu_tt_addr; /* MMU translation table address */
uint32_t sid_base; /* base address for SID registers */
uint32_t sid_offset; /* offset for SID_KEY[0-3], "root key" */
const sid_section *sid_sections; /* sid memory maps */
uint32_t rvbar_reg; /* MMIO address of RVBARADDR0_L register */
uint32_t rvbar_reg_alt;/* alternative MMIO address of RVBARADDR0_L register */
uint32_t ver_reg; /* MMIO address of "Version Register" */
const watchdog_info *watchdog; /* Used for reset */
bool sid_fix; /* Use SID workaround (read via register) */
/* Use I$ workaround (disable I$ before first write to prevent stale thunk */
bool icache_fix;
/* Use SMC workaround (enter secure mode) if can't read from this address */
uint32_t needs_smc_workaround_if_zero_word_at_addr;
uint32_t sram_size; /* Usable contiguous SRAM at spl_addr */
sram_swap_buffers *swap_buffers;
} soc_info_t;
void get_soc_name_from_id(soc_name_t buffer, uint32_t soc_id);
soc_info_t *get_soc_info_from_id(uint32_t soc_id);
soc_info_t *get_soc_info_from_version(struct aw_fel_version *buf);
const soc_info_t *get_next_soc(const soc_info_t *prev);
#endif /* _SUNXI_TOOLS_SOC_INFO_H */