195bec10aSVikas Gupta // SPDX-License-Identifier: BSD-2-Clause
295bec10aSVikas Gupta /*
395bec10aSVikas Gupta * Copyright 2019 Broadcom.
495bec10aSVikas Gupta */
595bec10aSVikas Gupta
695bec10aSVikas Gupta #include <crc32.h>
795bec10aSVikas Gupta #include <drivers/bcm/bnxt.h>
89b726349SSheetal Tigadoli #include <mm/core_mmu.h>
995bec10aSVikas Gupta #include <stdint.h>
1095bec10aSVikas Gupta #include <stdlib.h>
1195bec10aSVikas Gupta #include <string.h>
12*6d777f26SJorge Ramirez-Ortiz #include <util.h>
1395bec10aSVikas Gupta
1495bec10aSVikas Gupta /*
1595bec10aSVikas Gupta * These macros are the offsets where images reside on sec mem
1695bec10aSVikas Gupta */
1795bec10aSVikas Gupta #define BNXT_BUFFER_SEC_MEM 0x8ae00000
1895bec10aSVikas Gupta #define BNXT_FW_SEC_MEM_SRC BNXT_BUFFER_SEC_MEM
1995bec10aSVikas Gupta #define BNXT_FW_SEC_MEM_CFG (BNXT_BUFFER_SEC_MEM + 0x100000)
20ccf6a7e7STony Poon #define TEMP_MEM (BNXT_BUFFER_SEC_MEM + 0x180000)
2195bec10aSVikas Gupta
2295bec10aSVikas Gupta #define BNXT_CRASH_SEC_MEM 0x8b000000
2395bec10aSVikas Gupta #define BNXT_CRASH_LEN 0x2000000
2495bec10aSVikas Gupta
2595bec10aSVikas Gupta #define BNXT_CONFIG_NS3_DEST 0x03a00000
2695bec10aSVikas Gupta #define BNXT_BSPD_CFG_OFFSET 0x51b0
2795bec10aSVikas Gupta #define BNXT_CONFIG_NS3_BSPD_DEST (BNXT_CONFIG_NS3_DEST + \
2895bec10aSVikas Gupta BNXT_BSPD_CFG_OFFSET)
2995bec10aSVikas Gupta #define BNXT_BSPD_CFG_SIZE 0x200
3095bec10aSVikas Gupta
3195bec10aSVikas Gupta #define BNXT_CRASH_DUMP_INFO_NS3_BASE 0x3a5ff00
3295bec10aSVikas Gupta
3395bec10aSVikas Gupta #define SZ_1K 0x400
3495bec10aSVikas Gupta
3595bec10aSVikas Gupta #define BUFFER_PADDING SZ_1K
3695bec10aSVikas Gupta
3795bec10aSVikas Gupta #define INC_SRC_ADDR 1
3895bec10aSVikas Gupta
3995bec10aSVikas Gupta #define EOF -1
4095bec10aSVikas Gupta
4195bec10aSVikas Gupta #define BCM_BNXT_FASTBOOT_MASK 0x3u
4295bec10aSVikas Gupta #define BCM_BNXT_FASTBOOT_TYPE_1 1
4395bec10aSVikas Gupta
4495bec10aSVikas Gupta #define ADDR_IS_4BYTE_ALIGNED(addr) IS_ALIGNED(addr, 4)
4595bec10aSVikas Gupta
4695bec10aSVikas Gupta #define SECTION_IS_LOADABLE(section_ptr) \
4795bec10aSVikas Gupta ((section_ptr)->flags_src_offset & SECTION_FLAGS_IS_LOADABLE)
4895bec10aSVikas Gupta #define SECTION_IS_ZIPPED(section_ptr) \
4995bec10aSVikas Gupta ((section_ptr)->flags_src_offset & SECTION_FLAGS_IS_ZIPPED)
5095bec10aSVikas Gupta #define SECTION_IS_TOBE_COPIED(section_ptr) \
5195bec10aSVikas Gupta ((section_ptr)->flags_src_offset & \
5295bec10aSVikas Gupta (SECTION_FLAGS_IS_EXEC_INSTR | SECTION_FLAGS_IS_DATA))
5395bec10aSVikas Gupta #define SECTION_IS_TOBE_ZEROED(section_ptr) \
5495bec10aSVikas Gupta ((section_ptr)->flags_src_offset & SECTION_FLAGS_IS_BSS)
5595bec10aSVikas Gupta #define SECTION_IS_4BYTE_ALIGNED(section_ptr) \
5695bec10aSVikas Gupta ADDR_IS_4BYTE_ALIGNED((section_ptr)->dest_addr)
5795bec10aSVikas Gupta
5895bec10aSVikas Gupta #define SECTION_SRC_OFFSET(section_ptr) \
5995bec10aSVikas Gupta ((section_ptr)->flags_src_offset & SECTION_SRC_OFFFSET_MASK)
6095bec10aSVikas Gupta
6195bec10aSVikas Gupta /* -------------------------------------------------------------------------- */
6295bec10aSVikas Gupta
6395bec10aSVikas Gupta /* Section header for each image block */
6495bec10aSVikas Gupta struct ape_section_hdr_s {
6595bec10aSVikas Gupta /* Destination address that this section is to be copied to */
6695bec10aSVikas Gupta uint32_t dest_addr;
6795bec10aSVikas Gupta
6895bec10aSVikas Gupta /*
6995bec10aSVikas Gupta * bit[0:23] source offset address that this image copy from
7095bec10aSVikas Gupta * bit[24:31] flags
7195bec10aSVikas Gupta */
7295bec10aSVikas Gupta uint32_t flags_src_offset;
7395bec10aSVikas Gupta #define SECTION_FLAGS_MASK 0xff000000
7495bec10aSVikas Gupta /* Session is compressed (zipped) */
7595bec10aSVikas Gupta #define SECTION_FLAGS_IS_ZIPPED 0x01000000
7695bec10aSVikas Gupta /* Session contains CRC */
7795bec10aSVikas Gupta #define SECTION_FLAGS_IS_CRC 0x02000000
7895bec10aSVikas Gupta /* Session contains executable code (e.g. .text) */
7995bec10aSVikas Gupta #define SECTION_FLAGS_IS_EXEC_INSTR 0x04000000
8095bec10aSVikas Gupta /* Session contains initialized data (e.g. .data) */
8195bec10aSVikas Gupta #define SECTION_FLAGS_IS_DATA 0x08000000
8295bec10aSVikas Gupta /* Session contains zero initialized data (e.g. .bss) */
8395bec10aSVikas Gupta #define SECTION_FLAGS_IS_BSS 0x10000000
8495bec10aSVikas Gupta /* Loadable section mask */
8595bec10aSVikas Gupta #define SECTION_FLAGS_IS_LOADABLE (SECTION_FLAGS_IS_EXEC_INSTR | \
8695bec10aSVikas Gupta SECTION_FLAGS_IS_DATA | \
8795bec10aSVikas Gupta SECTION_FLAGS_IS_BSS)
8895bec10aSVikas Gupta #define SECTION_SRC_OFFFSET_MASK 0x00ffffff
8995bec10aSVikas Gupta
9095bec10aSVikas Gupta /* Original image length, dword (4byte) length */
9195bec10aSVikas Gupta uint32_t org_data_len;
9295bec10aSVikas Gupta
9395bec10aSVikas Gupta /* Compressed image length (if FlAGS_IS_ZIPPED is set) */
9495bec10aSVikas Gupta uint32_t zip_data_len;
9595bec10aSVikas Gupta
9695bec10aSVikas Gupta /*
9795bec10aSVikas Gupta * checksum value for this image block, if FLAGS_IS_CRC then
9895bec10aSVikas Gupta * this is CRC checksum; otherwise it is a simple summation
9995bec10aSVikas Gupta */
10095bec10aSVikas Gupta uint32_t checksum;
10195bec10aSVikas Gupta };
10295bec10aSVikas Gupta
10395bec10aSVikas Gupta struct version_s {
10495bec10aSVikas Gupta uint8_t version[16]; /* Null-terminated file version string */
10595bec10aSVikas Gupta };
10695bec10aSVikas Gupta
10795bec10aSVikas Gupta struct ver_ext_offset_s {
10895bec10aSVikas Gupta uint8_t version[12]; /* Null-terminated file version string */
10995bec10aSVikas Gupta uint32_t ext_hdr_offset;
11095bec10aSVikas Gupta };
11195bec10aSVikas Gupta
11295bec10aSVikas Gupta union version_and_offset_u {
11395bec10aSVikas Gupta struct version_s version1;
11495bec10aSVikas Gupta struct ver_ext_offset_s version2;
11595bec10aSVikas Gupta };
11695bec10aSVikas Gupta
11795bec10aSVikas Gupta struct ape_bin_hdr_s {
11895bec10aSVikas Gupta /* APE binary header signature; expects APE_BIN_HDR_SIGNATURE */
11995bec10aSVikas Gupta uint32_t signature;
12095bec10aSVikas Gupta #define APE_BIN_HDR_SIGNATURE 0x1a4d4342 /* "BCM"+0x1a */
12195bec10aSVikas Gupta /* Reserved for ChiMP's use */
12295bec10aSVikas Gupta uint8_t flags;
12395bec10aSVikas Gupta uint8_t code_type;
12495bec10aSVikas Gupta uint8_t device;
12595bec10aSVikas Gupta uint8_t media;
12695bec10aSVikas Gupta union version_and_offset_u ver;
12795bec10aSVikas Gupta uint8_t build;
12895bec10aSVikas Gupta uint8_t revision;
12995bec10aSVikas Gupta uint8_t minor_ver;
13095bec10aSVikas Gupta uint8_t major_ver;
13195bec10aSVikas Gupta uint32_t entry_address;
13295bec10aSVikas Gupta uint8_t reserved;
13395bec10aSVikas Gupta uint8_t header_dword_size;
13495bec10aSVikas Gupta uint8_t num_total_sections;
13595bec10aSVikas Gupta uint8_t num_loadable_sections;
13695bec10aSVikas Gupta uint32_t checksum;
13795bec10aSVikas Gupta } __packed __aligned(1);
13895bec10aSVikas Gupta
13995bec10aSVikas Gupta #define APE_BIN_HDR_SIZE sizeof(struct ape_bin_hdr_s)
14095bec10aSVikas Gupta #define APE_SECTION_HDR_SIZE sizeof(struct ape_section_hdr_s)
14195bec10aSVikas Gupta
14295bec10aSVikas Gupta /* MAX number of image sections that will be accepted */
14395bec10aSVikas Gupta #define APE_IMG_MAX_SECTIONS 16
14495bec10aSVikas Gupta
14595bec10aSVikas Gupta #define APE_IMG_LOAD_DEBUG 0
14695bec10aSVikas Gupta
14795bec10aSVikas Gupta /* -------------------------------------------------------------------------- */
14895bec10aSVikas Gupta
14995bec10aSVikas Gupta struct ape_mem_region_s {
15095bec10aSVikas Gupta uint32_t c_base; /* ChiMP's view of address */
15195bec10aSVikas Gupta uint32_t h_base; /* Host's view of address */
15295bec10aSVikas Gupta uint32_t size; /* Size in bytes */
15395bec10aSVikas Gupta };
15495bec10aSVikas Gupta
15595bec10aSVikas Gupta /* Memory map into various scratchpad memories */
15695bec10aSVikas Gupta static struct ape_mem_region_s ape_mem_regions[] = {
15795bec10aSVikas Gupta /* CHIMP scratchpad */
15895bec10aSVikas Gupta {0x00100000, 0x03100000, 1024 * SZ_1K},
15995bec10aSVikas Gupta
16095bec10aSVikas Gupta /* APE scratchpad */
16195bec10aSVikas Gupta {0x61000000, 0x03300000, 1152 * SZ_1K},
16295bec10aSVikas Gupta
16395bec10aSVikas Gupta /* BONO scratchpad */
16495bec10aSVikas Gupta {0x61600000, 0x03a00000, 512 * SZ_1K},
16595bec10aSVikas Gupta
16695bec10aSVikas Gupta /* KONG scratchpad */
16795bec10aSVikas Gupta {0x61400000, 0x03800000, 512 * SZ_1K},
16895bec10aSVikas Gupta
16995bec10aSVikas Gupta /* Keep this last!! */
17095bec10aSVikas Gupta {0, 0, 0}
17195bec10aSVikas Gupta };
17295bec10aSVikas Gupta
17395bec10aSVikas Gupta /* Nitro crash address configuration related macros */
17495bec10aSVikas Gupta #define BNXT_CRASH_INFO_SIGNATURE 0x20524444
17595bec10aSVikas Gupta #define BNXT_CRASH_INFO_VALID 0x1
17695bec10aSVikas Gupta #define MAX_CRASH_ADDR_ITEM 8
17795bec10aSVikas Gupta
17895bec10aSVikas Gupta struct nitro_crash_addr_item {
17995bec10aSVikas Gupta uint32_t info;
18095bec10aSVikas Gupta uint32_t size;
18195bec10aSVikas Gupta uint32_t addr_hi;
18295bec10aSVikas Gupta uint32_t addr_lo;
18395bec10aSVikas Gupta };
18495bec10aSVikas Gupta
18595bec10aSVikas Gupta struct nitro_crash_addr_info {
18695bec10aSVikas Gupta /* CRC of the struct content, starting at next field. */
18795bec10aSVikas Gupta uint32_t crc;
18895bec10aSVikas Gupta uint32_t signature;
18995bec10aSVikas Gupta uint32_t version;
19095bec10aSVikas Gupta struct nitro_crash_addr_item table[MAX_CRASH_ADDR_ITEM];
19195bec10aSVikas Gupta };
19295bec10aSVikas Gupta
memcpy32_helper(uintptr_t src,uintptr_t dst,uint32_t entries,int inc_src_addr)19395bec10aSVikas Gupta static inline void memcpy32_helper(uintptr_t src,
19495bec10aSVikas Gupta uintptr_t dst,
19595bec10aSVikas Gupta uint32_t entries,
19695bec10aSVikas Gupta int inc_src_addr)
19795bec10aSVikas Gupta {
19895bec10aSVikas Gupta uint32_t copied_entries = 0;
19995bec10aSVikas Gupta
20095bec10aSVikas Gupta while (entries) {
20195bec10aSVikas Gupta copied_entries = bnxt_write32_multiple(dst, src, entries,
20295bec10aSVikas Gupta inc_src_addr);
20395bec10aSVikas Gupta
20495bec10aSVikas Gupta if (copied_entries < entries) {
20595bec10aSVikas Gupta dst += copied_entries * sizeof(uint32_t);
20695bec10aSVikas Gupta src += (inc_src_addr) ?
20795bec10aSVikas Gupta (copied_entries * sizeof(uint32_t)) : 0;
20895bec10aSVikas Gupta entries -= copied_entries;
20995bec10aSVikas Gupta } else {
21095bec10aSVikas Gupta entries = 0;
21195bec10aSVikas Gupta }
21295bec10aSVikas Gupta }
21395bec10aSVikas Gupta }
21495bec10aSVikas Gupta
ape_host_view_addr_get(uint32_t bnxt_view_addr,uint32_t size)21595bec10aSVikas Gupta static uint32_t ape_host_view_addr_get(uint32_t bnxt_view_addr, uint32_t size)
21695bec10aSVikas Gupta {
21795bec10aSVikas Gupta struct ape_mem_region_s *region = ape_mem_regions;
21895bec10aSVikas Gupta uint32_t addr = 0;
21995bec10aSVikas Gupta
22095bec10aSVikas Gupta for (; region->size != 0; region++) {
22195bec10aSVikas Gupta if (bnxt_view_addr < region->c_base)
22295bec10aSVikas Gupta continue;
22395bec10aSVikas Gupta
22495bec10aSVikas Gupta if (bnxt_view_addr >= (region->c_base + region->size))
22595bec10aSVikas Gupta continue;
22695bec10aSVikas Gupta
22795bec10aSVikas Gupta if (size > (region->c_base + region->size - bnxt_view_addr)) {
22895bec10aSVikas Gupta EMSG("ERROR: 0x%x + 0x%x spans memory boundary",
22995bec10aSVikas Gupta bnxt_view_addr, size);
23095bec10aSVikas Gupta break;
23195bec10aSVikas Gupta }
23295bec10aSVikas Gupta
23395bec10aSVikas Gupta addr = bnxt_view_addr - region->c_base;
23495bec10aSVikas Gupta addr += region->h_base;
23595bec10aSVikas Gupta break;
23695bec10aSVikas Gupta }
23795bec10aSVikas Gupta
23895bec10aSVikas Gupta return addr;
23995bec10aSVikas Gupta }
24095bec10aSVikas Gupta
ape_hdr_crc_calc(const struct ape_bin_hdr_s * hdr)24195bec10aSVikas Gupta static uint32_t ape_hdr_crc_calc(const struct ape_bin_hdr_s *hdr)
24295bec10aSVikas Gupta {
24395bec10aSVikas Gupta uint32_t crc = 0;
24495bec10aSVikas Gupta uint32_t dummy = 0;
24595bec10aSVikas Gupta
24695bec10aSVikas Gupta /* Compute the CRC up to, but not including, the checksum field */
24795bec10aSVikas Gupta crc = CRC32(CRC32_INIT_VAL,
24895bec10aSVikas Gupta (const char *)hdr,
24995bec10aSVikas Gupta (uintptr_t)(&hdr->checksum) - (uintptr_t)hdr);
25095bec10aSVikas Gupta
25195bec10aSVikas Gupta /* Compute the CRC with the checksum field zeroed out */
25295bec10aSVikas Gupta crc = CRC32(~crc, (const char *)&dummy, sizeof(uint32_t));
25395bec10aSVikas Gupta
25495bec10aSVikas Gupta /*
25595bec10aSVikas Gupta * Compute the remainder part of the image header, i.e., the
25695bec10aSVikas Gupta * section headers
25795bec10aSVikas Gupta */
25895bec10aSVikas Gupta crc = CRC32(~crc,
25995bec10aSVikas Gupta (const char *)((uintptr_t)hdr + APE_BIN_HDR_SIZE),
26095bec10aSVikas Gupta hdr->num_total_sections * APE_SECTION_HDR_SIZE);
26195bec10aSVikas Gupta
26295bec10aSVikas Gupta return crc;
26395bec10aSVikas Gupta }
26495bec10aSVikas Gupta
ape_bin_hdr_valid(const struct ape_bin_hdr_s * hdr)26595bec10aSVikas Gupta static int ape_bin_hdr_valid(const struct ape_bin_hdr_s *hdr)
26695bec10aSVikas Gupta {
26795bec10aSVikas Gupta uint32_t checksum = 0;
26895bec10aSVikas Gupta
26995bec10aSVikas Gupta if (!hdr) {
27095bec10aSVikas Gupta EMSG("ERROR: no APE image header");
27195bec10aSVikas Gupta return BNXT_FAILURE;
27295bec10aSVikas Gupta }
27395bec10aSVikas Gupta
27495bec10aSVikas Gupta if (hdr->signature != APE_BIN_HDR_SIGNATURE) {
27595bec10aSVikas Gupta EMSG("ERROR: bad APE image signature");
27695bec10aSVikas Gupta return BNXT_FAILURE;
27795bec10aSVikas Gupta }
27895bec10aSVikas Gupta
27995bec10aSVikas Gupta if (hdr->num_total_sections > APE_IMG_MAX_SECTIONS) {
28095bec10aSVikas Gupta EMSG("ERROR: too many sections in APE image");
28195bec10aSVikas Gupta return BNXT_FAILURE;
28295bec10aSVikas Gupta }
28395bec10aSVikas Gupta
28495bec10aSVikas Gupta checksum = ape_hdr_crc_calc(hdr);
28595bec10aSVikas Gupta if (hdr->checksum != checksum) {
28695bec10aSVikas Gupta EMSG("ERROR: bad APE header checksum (exp: %x, act: %x)",
28795bec10aSVikas Gupta hdr->checksum, checksum);
28895bec10aSVikas Gupta return BNXT_FAILURE;
28995bec10aSVikas Gupta }
29095bec10aSVikas Gupta
29195bec10aSVikas Gupta return BNXT_SUCCESS;
29295bec10aSVikas Gupta }
29395bec10aSVikas Gupta
get_char(uint8_t * inbuf,size_t * inbuf_idx,size_t inbuf_size)29495bec10aSVikas Gupta static int get_char(uint8_t *inbuf, size_t *inbuf_idx, size_t inbuf_size)
29595bec10aSVikas Gupta {
29695bec10aSVikas Gupta int c = 0;
29795bec10aSVikas Gupta
29895bec10aSVikas Gupta if (*inbuf_idx >= inbuf_size)
29995bec10aSVikas Gupta return EOF;
30095bec10aSVikas Gupta
30195bec10aSVikas Gupta c = inbuf[*inbuf_idx];
30295bec10aSVikas Gupta *inbuf_idx += 1;
30395bec10aSVikas Gupta
30495bec10aSVikas Gupta return c;
30595bec10aSVikas Gupta }
30695bec10aSVikas Gupta
put_char(uint8_t * outbuf,size_t * outbuf_idx,size_t outbuf_size,uint8_t ch)30795bec10aSVikas Gupta static void put_char(uint8_t *outbuf,
30895bec10aSVikas Gupta size_t *outbuf_idx,
30995bec10aSVikas Gupta size_t outbuf_size,
31095bec10aSVikas Gupta uint8_t ch)
31195bec10aSVikas Gupta {
31295bec10aSVikas Gupta if (*outbuf_idx >= outbuf_size)
31395bec10aSVikas Gupta return;
31495bec10aSVikas Gupta
31595bec10aSVikas Gupta outbuf[*outbuf_idx] = ch;
31695bec10aSVikas Gupta *outbuf_idx += 1;
31795bec10aSVikas Gupta }
31895bec10aSVikas Gupta
ape_section_uncompress(uint8_t * inbuf,size_t inbuf_size,uint8_t * outbuf,size_t outbuf_size)31995bec10aSVikas Gupta static size_t ape_section_uncompress(uint8_t *inbuf,
32095bec10aSVikas Gupta size_t inbuf_size,
32195bec10aSVikas Gupta uint8_t *outbuf,
32295bec10aSVikas Gupta size_t outbuf_size)
32395bec10aSVikas Gupta {
32495bec10aSVikas Gupta int i = 0, j = 0, k = 0, r = 0, c = 0;
32595bec10aSVikas Gupta uint32_t flags = 0;
32695bec10aSVikas Gupta size_t exp_size = 0, codesize = 0;
32795bec10aSVikas Gupta size_t inbuf_idx = 0, outbuf_idx = 0;
32895bec10aSVikas Gupta #define CODE_8U_MASK 0xff00u /* 8 code units count mask (8 bits) */
32995bec10aSVikas Gupta #define CODE_END_MASK 0x100u /* End of code units mask */
33095bec10aSVikas Gupta #define CODE_IS_UNENCODED_MASK 1 /* Unencoded code unit mask */
33195bec10aSVikas Gupta #define CODE_POS_MASK 0xe0u /* Encoded unit position mask and */
33295bec10aSVikas Gupta #define CODE_POS_SHIFT 3 /* Bit shift */
33395bec10aSVikas Gupta #define CODE_LEN_MASK 0x1fu /* Encoded unit length mask */
33495bec10aSVikas Gupta #define NS 2048 /* Size of ring buffer */
33595bec10aSVikas Gupta #define F 34 /* Upper limit for match_length */
33695bec10aSVikas Gupta #define THRESHOLD 2 /* Encode string into position and
33795bec10aSVikas Gupta * length, if match_length is
33895bec10aSVikas Gupta * greater than this.
33995bec10aSVikas Gupta */
34095bec10aSVikas Gupta /*
34195bec10aSVikas Gupta * Ring buffer of size NS, with an extra F-1 bytes to facilitate
34295bec10aSVikas Gupta * string comparisons.
34395bec10aSVikas Gupta */
34495bec10aSVikas Gupta uint8_t text_buf[NS + F - 1];
34595bec10aSVikas Gupta
34695bec10aSVikas Gupta inbuf_idx = 0;
34795bec10aSVikas Gupta outbuf_idx = 0;
34895bec10aSVikas Gupta
34995bec10aSVikas Gupta for (i = 0; i < NS - F; i++)
35095bec10aSVikas Gupta text_buf[i] = ' ';
35195bec10aSVikas Gupta
35295bec10aSVikas Gupta r = NS - F;
35395bec10aSVikas Gupta
35495bec10aSVikas Gupta for (;;) {
35595bec10aSVikas Gupta if (((flags >>= 1) & CODE_END_MASK) == 0) {
35695bec10aSVikas Gupta c = get_char(inbuf, &inbuf_idx, inbuf_size);
35795bec10aSVikas Gupta if (c == EOF)
35895bec10aSVikas Gupta break;
35995bec10aSVikas Gupta ++exp_size;
36095bec10aSVikas Gupta
36195bec10aSVikas Gupta if (exp_size > inbuf_size)
36295bec10aSVikas Gupta break;
36395bec10aSVikas Gupta
36495bec10aSVikas Gupta /* Use higher byte cleverly to count to eight */
36595bec10aSVikas Gupta flags = c | CODE_8U_MASK;
36695bec10aSVikas Gupta }
36795bec10aSVikas Gupta
36895bec10aSVikas Gupta if (flags & CODE_IS_UNENCODED_MASK) {
36995bec10aSVikas Gupta /* Not encoded; simply copy the unit */
37095bec10aSVikas Gupta c = get_char(inbuf, &inbuf_idx, inbuf_size);
37195bec10aSVikas Gupta if (c == EOF)
37295bec10aSVikas Gupta break;
37395bec10aSVikas Gupta
37495bec10aSVikas Gupta ++exp_size;
37595bec10aSVikas Gupta if (exp_size > inbuf_size)
37695bec10aSVikas Gupta break;
37795bec10aSVikas Gupta
37895bec10aSVikas Gupta put_char(outbuf, &outbuf_idx, outbuf_size, c);
37995bec10aSVikas Gupta text_buf[r++] = c;
38095bec10aSVikas Gupta r &= (NS - 1);
38195bec10aSVikas Gupta ++codesize;
38295bec10aSVikas Gupta } else {
38395bec10aSVikas Gupta /* Encoded; get the position and length & duplicate */
38495bec10aSVikas Gupta i = get_char(inbuf, &inbuf_idx, inbuf_size);
38595bec10aSVikas Gupta if (i == EOF)
38695bec10aSVikas Gupta break;
38795bec10aSVikas Gupta
38895bec10aSVikas Gupta ++exp_size;
38995bec10aSVikas Gupta if (exp_size > inbuf_size)
39095bec10aSVikas Gupta break;
39195bec10aSVikas Gupta
39295bec10aSVikas Gupta j = get_char(inbuf, &inbuf_idx, inbuf_size);
39395bec10aSVikas Gupta if (j == EOF)
39495bec10aSVikas Gupta break;
39595bec10aSVikas Gupta
39695bec10aSVikas Gupta ++exp_size;
39795bec10aSVikas Gupta if (exp_size > inbuf_size)
39895bec10aSVikas Gupta break;
39995bec10aSVikas Gupta
40095bec10aSVikas Gupta i |= ((j & CODE_POS_MASK) << CODE_POS_SHIFT);
40195bec10aSVikas Gupta j = ((j & CODE_LEN_MASK) + THRESHOLD);
40295bec10aSVikas Gupta
40395bec10aSVikas Gupta for (k = 0; k <= j; k++) {
40495bec10aSVikas Gupta c = text_buf[((i + k) & (NS - 1))];
40595bec10aSVikas Gupta put_char(outbuf, &outbuf_idx, outbuf_size, c);
40695bec10aSVikas Gupta text_buf[r++] = c;
40795bec10aSVikas Gupta r &= (NS - 1);
40895bec10aSVikas Gupta ++codesize;
40995bec10aSVikas Gupta }
41095bec10aSVikas Gupta }
41195bec10aSVikas Gupta }
41295bec10aSVikas Gupta
41395bec10aSVikas Gupta return codesize;
41495bec10aSVikas Gupta }
41595bec10aSVikas Gupta
ape_section_copy(struct ape_bin_hdr_s * bin_hdr,struct ape_section_hdr_s * section)41695bec10aSVikas Gupta static int ape_section_copy(struct ape_bin_hdr_s *bin_hdr,
41795bec10aSVikas Gupta struct ape_section_hdr_s *section)
41895bec10aSVikas Gupta {
41995bec10aSVikas Gupta uintptr_t src = 0;
42095bec10aSVikas Gupta uintptr_t dst = 0;
42195bec10aSVikas Gupta uint32_t checksum = 0;
42295bec10aSVikas Gupta uint32_t i = 0;
42395bec10aSVikas Gupta size_t size = 0;
42495bec10aSVikas Gupta uint8_t *section_data = NULL;
42595bec10aSVikas Gupta size_t work_buff_size = 0;
42695bec10aSVikas Gupta void *work_buff = NULL;
42795bec10aSVikas Gupta int rc = BNXT_FAILURE;
42895bec10aSVikas Gupta
42995bec10aSVikas Gupta if (SECTION_IS_ZIPPED(section)) {
43095bec10aSVikas Gupta work_buff_size = section->org_data_len + BUFFER_PADDING;
431c2e4eb43SAnton Rybakov work_buff = (void *)phys_to_virt(TEMP_MEM, MEM_AREA_RAM_SEC,
432c2e4eb43SAnton Rybakov work_buff_size);
43395bec10aSVikas Gupta if (!work_buff) {
43495bec10aSVikas Gupta EMSG("ERROR: buffer allocation");
43595bec10aSVikas Gupta return BNXT_FAILURE;
43695bec10aSVikas Gupta }
43795bec10aSVikas Gupta
43895bec10aSVikas Gupta section_data = (uint8_t *)((uintptr_t)bin_hdr +
43995bec10aSVikas Gupta SECTION_SRC_OFFSET(section));
44095bec10aSVikas Gupta size = ape_section_uncompress(section_data,
44195bec10aSVikas Gupta section->zip_data_len,
44295bec10aSVikas Gupta work_buff,
44395bec10aSVikas Gupta work_buff_size);
44495bec10aSVikas Gupta if (size >= work_buff_size) {
44595bec10aSVikas Gupta EMSG("ERROR: section uncompress");
44695bec10aSVikas Gupta goto ape_section_copy_exit;
44795bec10aSVikas Gupta }
44895bec10aSVikas Gupta if (size < section->org_data_len) {
44995bec10aSVikas Gupta EMSG("ERROR: decompressed data size mismatch ");
45095bec10aSVikas Gupta EMSG("(exp: %d, act: %ld)",
45195bec10aSVikas Gupta section->org_data_len, size);
45295bec10aSVikas Gupta goto ape_section_copy_exit;
45395bec10aSVikas Gupta }
45495bec10aSVikas Gupta src = (uintptr_t)work_buff;
45595bec10aSVikas Gupta } else {
45695bec10aSVikas Gupta src = (uintptr_t)bin_hdr + SECTION_SRC_OFFSET(section);
45795bec10aSVikas Gupta }
45895bec10aSVikas Gupta
45995bec10aSVikas Gupta size = section->org_data_len;
46095bec10aSVikas Gupta
46195bec10aSVikas Gupta if (section->flags_src_offset & SECTION_FLAGS_IS_CRC) {
46295bec10aSVikas Gupta checksum = CRC32(CRC32_INIT_VAL, (const char *)src, size);
46395bec10aSVikas Gupta } else {
46495bec10aSVikas Gupta checksum = 0;
46595bec10aSVikas Gupta for (i = 0; i < size / sizeof(uint32_t); i++)
46695bec10aSVikas Gupta checksum += ((uint32_t *)src)[i];
46795bec10aSVikas Gupta }
46895bec10aSVikas Gupta if (checksum != section->checksum) {
46995bec10aSVikas Gupta EMSG("ERROR: checksum mismatch (exp: %x, act: %x)",
47095bec10aSVikas Gupta section->checksum, checksum);
47195bec10aSVikas Gupta goto ape_section_copy_exit;
47295bec10aSVikas Gupta }
47395bec10aSVikas Gupta
47495bec10aSVikas Gupta dst = ape_host_view_addr_get(section->dest_addr, size);
47595bec10aSVikas Gupta if (dst == 0) {
47695bec10aSVikas Gupta EMSG("ERROR: ChiMP-to-host address conversion of %x",
47795bec10aSVikas Gupta section->dest_addr);
47895bec10aSVikas Gupta goto ape_section_copy_exit;
47995bec10aSVikas Gupta }
48095bec10aSVikas Gupta
48195bec10aSVikas Gupta /* Copy the section */
48295bec10aSVikas Gupta size = size / sizeof(uint32_t);
48395bec10aSVikas Gupta memcpy32_helper(src, dst, size, INC_SRC_ADDR);
48495bec10aSVikas Gupta
48595bec10aSVikas Gupta rc = BNXT_SUCCESS;
48695bec10aSVikas Gupta
48795bec10aSVikas Gupta ape_section_copy_exit:
48895bec10aSVikas Gupta return rc;
48995bec10aSVikas Gupta }
49095bec10aSVikas Gupta
ape_section_zero(struct ape_section_hdr_s * section)49195bec10aSVikas Gupta static int ape_section_zero(struct ape_section_hdr_s *section)
49295bec10aSVikas Gupta {
49395bec10aSVikas Gupta uint32_t dst = 0;
49495bec10aSVikas Gupta uint32_t size = section->org_data_len;
49595bec10aSVikas Gupta uint32_t zero = 0;
49695bec10aSVikas Gupta
49795bec10aSVikas Gupta if (section->org_data_len == 0)
49895bec10aSVikas Gupta return BNXT_SUCCESS;
49995bec10aSVikas Gupta
50095bec10aSVikas Gupta /* Convert ChiMP's view of the address in the image to the host view */
50195bec10aSVikas Gupta dst = ape_host_view_addr_get(section->dest_addr, size);
50295bec10aSVikas Gupta if (dst == 0) {
50395bec10aSVikas Gupta EMSG("ERROR: ChiMP-to-host address conversion of %x",
50495bec10aSVikas Gupta section->dest_addr);
50595bec10aSVikas Gupta return BNXT_FAILURE;
50695bec10aSVikas Gupta }
50795bec10aSVikas Gupta
50895bec10aSVikas Gupta /*
50995bec10aSVikas Gupta * Zero the section; we simply copy zeros and do not increment the
51095bec10aSVikas Gupta * source buffer address.
51195bec10aSVikas Gupta */
51295bec10aSVikas Gupta size = size / sizeof(uint32_t);
51395bec10aSVikas Gupta memcpy32_helper((uintptr_t)&zero, dst, size, !INC_SRC_ADDR);
51495bec10aSVikas Gupta
51595bec10aSVikas Gupta return BNXT_SUCCESS;
51695bec10aSVikas Gupta }
51795bec10aSVikas Gupta
bnxt_load(vaddr_t img_buffer)51895bec10aSVikas Gupta static int bnxt_load(vaddr_t img_buffer)
51995bec10aSVikas Gupta {
52095bec10aSVikas Gupta struct ape_bin_hdr_s *bin_hdr = NULL;
52195bec10aSVikas Gupta struct ape_section_hdr_s *section = NULL;
52295bec10aSVikas Gupta int sidx = 0;
52395bec10aSVikas Gupta int rc = BNXT_SUCCESS;
52495bec10aSVikas Gupta
52595bec10aSVikas Gupta bin_hdr = (struct ape_bin_hdr_s *)img_buffer;
52695bec10aSVikas Gupta section = (struct ape_section_hdr_s *)(img_buffer +
52795bec10aSVikas Gupta APE_BIN_HDR_SIZE);
52895bec10aSVikas Gupta
52995bec10aSVikas Gupta if (ape_bin_hdr_valid(bin_hdr) != BNXT_SUCCESS)
53095bec10aSVikas Gupta return BNXT_FAILURE;
53195bec10aSVikas Gupta
53295bec10aSVikas Gupta for (sidx = 0; sidx < bin_hdr->num_total_sections; sidx++, section++) {
53395bec10aSVikas Gupta if (!SECTION_IS_LOADABLE(section))
53495bec10aSVikas Gupta continue;
53595bec10aSVikas Gupta
53695bec10aSVikas Gupta if (!ADDR_IS_4BYTE_ALIGNED(section->dest_addr)) {
53795bec10aSVikas Gupta EMSG("ERROR: unaligned section dest address 0x%x",
53895bec10aSVikas Gupta section->dest_addr);
53995bec10aSVikas Gupta rc = BNXT_FAILURE;
54095bec10aSVikas Gupta break;
54195bec10aSVikas Gupta }
54295bec10aSVikas Gupta
54395bec10aSVikas Gupta if (!ADDR_IS_4BYTE_ALIGNED(SECTION_SRC_OFFSET(section))) {
54495bec10aSVikas Gupta EMSG("ERROR: unaligned section src offset (0x%x)",
54595bec10aSVikas Gupta SECTION_SRC_OFFSET(section));
54695bec10aSVikas Gupta rc = BNXT_FAILURE;
54795bec10aSVikas Gupta break;
54895bec10aSVikas Gupta }
54995bec10aSVikas Gupta
55095bec10aSVikas Gupta if (section->org_data_len % sizeof(uint32_t)) {
55195bec10aSVikas Gupta EMSG("ERROR: section size (%d) not divisible by 4",
55295bec10aSVikas Gupta section->org_data_len);
55395bec10aSVikas Gupta rc = BNXT_FAILURE;
55495bec10aSVikas Gupta break;
55595bec10aSVikas Gupta }
55695bec10aSVikas Gupta
55795bec10aSVikas Gupta if (SECTION_IS_TOBE_COPIED(section)) {
55895bec10aSVikas Gupta rc = ape_section_copy(bin_hdr, section);
55995bec10aSVikas Gupta if (rc != BNXT_SUCCESS)
56095bec10aSVikas Gupta break;
56195bec10aSVikas Gupta } else if (SECTION_IS_TOBE_ZEROED(section)) {
56295bec10aSVikas Gupta rc = ape_section_zero(section);
56395bec10aSVikas Gupta if (rc != BNXT_SUCCESS)
56495bec10aSVikas Gupta break;
56595bec10aSVikas Gupta }
56695bec10aSVikas Gupta }
56795bec10aSVikas Gupta
56895bec10aSVikas Gupta /* Set up boot mode and take BNXT out of reset */
56995bec10aSVikas Gupta if (rc == BNXT_SUCCESS) {
57095bec10aSVikas Gupta bnxt_fastboot((bin_hdr->entry_address &
57195bec10aSVikas Gupta ~BCM_BNXT_FASTBOOT_MASK) |
57295bec10aSVikas Gupta BCM_BNXT_FASTBOOT_TYPE_1);
57395bec10aSVikas Gupta }
57495bec10aSVikas Gupta
57595bec10aSVikas Gupta return rc;
57695bec10aSVikas Gupta }
57795bec10aSVikas Gupta
bnxt_crash_config(uintptr_t info_dst,uint32_t crash_area_start,uint32_t crash_len)57895bec10aSVikas Gupta static TEE_Result bnxt_crash_config(uintptr_t info_dst,
57995bec10aSVikas Gupta uint32_t crash_area_start,
58095bec10aSVikas Gupta uint32_t crash_len)
58195bec10aSVikas Gupta {
58295bec10aSVikas Gupta struct nitro_crash_addr_item *item = NULL;
58395bec10aSVikas Gupta uintptr_t dst = 0;
58495bec10aSVikas Gupta struct nitro_crash_addr_info *info = NULL;
58595bec10aSVikas Gupta uintptr_t src = 0;
58695bec10aSVikas Gupta uint32_t crc = 0;
58795bec10aSVikas Gupta size_t size = 0;
58895bec10aSVikas Gupta
58995bec10aSVikas Gupta /*
59095bec10aSVikas Gupta * First we write into local memory to calculate CRC before
59195bec10aSVikas Gupta * updating into Nitro memory
59295bec10aSVikas Gupta */
59395bec10aSVikas Gupta info = malloc(sizeof(struct nitro_crash_addr_info));
59495bec10aSVikas Gupta if (!info) {
59595bec10aSVikas Gupta EMSG("ERROR: buffer allocation");
59695bec10aSVikas Gupta return TEE_ERROR_OUT_OF_MEMORY;
59795bec10aSVikas Gupta }
59895bec10aSVikas Gupta
59995bec10aSVikas Gupta memset(info, 0, sizeof(struct nitro_crash_addr_info));
60095bec10aSVikas Gupta
60195bec10aSVikas Gupta info->signature = BNXT_CRASH_INFO_SIGNATURE;
60295bec10aSVikas Gupta info->version = 0x01000000 | MAX_CRASH_ADDR_ITEM;
60395bec10aSVikas Gupta
60495bec10aSVikas Gupta /* As of now only one item is filled */
60595bec10aSVikas Gupta item = &info->table[0];
60695bec10aSVikas Gupta item->info = 0;
60795bec10aSVikas Gupta item->size = crash_len | BNXT_CRASH_INFO_VALID;
60895bec10aSVikas Gupta item->addr_hi = 0;
60995bec10aSVikas Gupta item->addr_lo = crash_area_start;
61095bec10aSVikas Gupta
61195bec10aSVikas Gupta /* Checksum calculation */
61295bec10aSVikas Gupta crc = CRC32(CRC32_INIT_VAL,
61395bec10aSVikas Gupta (const char *)info + sizeof(uint32_t),
61495bec10aSVikas Gupta sizeof(struct nitro_crash_addr_info) - sizeof(uint32_t));
61595bec10aSVikas Gupta info->crc = crc;
61695bec10aSVikas Gupta
61795bec10aSVikas Gupta /* First we write the contents and then set valid bit */
61895bec10aSVikas Gupta item->size &= ~BNXT_CRASH_INFO_VALID;
61995bec10aSVikas Gupta
62095bec10aSVikas Gupta size = sizeof(struct nitro_crash_addr_info) / sizeof(uint32_t);
62195bec10aSVikas Gupta dst = info_dst;
62295bec10aSVikas Gupta src = (uintptr_t)info;
62395bec10aSVikas Gupta memcpy32_helper(src, dst, size, INC_SRC_ADDR);
62495bec10aSVikas Gupta
62595bec10aSVikas Gupta /* Set the valid bit */
62695bec10aSVikas Gupta item->size |= BNXT_CRASH_INFO_VALID;
62795bec10aSVikas Gupta dst = info_dst + offsetof(struct nitro_crash_addr_info, table) +
62895bec10aSVikas Gupta offsetof(struct nitro_crash_addr_item, size);
62995bec10aSVikas Gupta bnxt_write32_multiple(dst, (uintptr_t)&item->size, 1, 1);
63095bec10aSVikas Gupta
63195bec10aSVikas Gupta free(info);
63295bec10aSVikas Gupta
63395bec10aSVikas Gupta return TEE_SUCCESS;
63495bec10aSVikas Gupta }
63595bec10aSVikas Gupta
bnxt_load_fw(int chip_type)63695bec10aSVikas Gupta TEE_Result bnxt_load_fw(int chip_type)
63795bec10aSVikas Gupta {
63895bec10aSVikas Gupta uint32_t size = 0;
63995bec10aSVikas Gupta uintptr_t dst = 0;
64095bec10aSVikas Gupta uintptr_t src = 0;
64195bec10aSVikas Gupta struct bnxt_images_info bnxt_src_image_info;
6425f2bc144SVikas Gupta vaddr_t sec_mem_dest = (vaddr_t)phys_to_virt(BNXT_BUFFER_SEC_MEM,
643c2e4eb43SAnton Rybakov MEM_AREA_RAM_SEC, 1);
64495bec10aSVikas Gupta
64595bec10aSVikas Gupta memset(&bnxt_src_image_info, 0, sizeof(struct bnxt_images_info));
64695bec10aSVikas Gupta
6475f2bc144SVikas Gupta if (get_bnxt_images_info(&bnxt_src_image_info,
6485f2bc144SVikas Gupta chip_type, sec_mem_dest) != BNXT_SUCCESS)
64995bec10aSVikas Gupta return TEE_ERROR_ITEM_NOT_FOUND;
65095bec10aSVikas Gupta
6519b726349SSheetal Tigadoli bnxt_handshake_clear();
65295bec10aSVikas Gupta bnxt_kong_halt();
65395bec10aSVikas Gupta bnxt_chimp_halt();
65495bec10aSVikas Gupta
65595bec10aSVikas Gupta /* Copy the configs */
65695bec10aSVikas Gupta src = (uintptr_t)bnxt_src_image_info.bnxt_cfg_vaddr;
65795bec10aSVikas Gupta dst = (uintptr_t)BNXT_CONFIG_NS3_DEST;
65895bec10aSVikas Gupta size = bnxt_src_image_info.bnxt_cfg_len;
65995bec10aSVikas Gupta size = size / sizeof(uint32_t);
66095bec10aSVikas Gupta memcpy32_helper(src, dst, size, INC_SRC_ADDR);
66195bec10aSVikas Gupta
66295bec10aSVikas Gupta /* Copy bspd config */
66395bec10aSVikas Gupta src = (uintptr_t)bnxt_src_image_info.bnxt_bspd_cfg_vaddr;
66495bec10aSVikas Gupta size = bnxt_src_image_info.bnxt_bspd_cfg_len;
66595bec10aSVikas Gupta dst = (uintptr_t)BNXT_CONFIG_NS3_BSPD_DEST;
66695bec10aSVikas Gupta
66795bec10aSVikas Gupta size = size / sizeof(uint32_t);
66895bec10aSVikas Gupta memcpy32_helper(src, dst, size, INC_SRC_ADDR);
66995bec10aSVikas Gupta
67095bec10aSVikas Gupta /* Fill the bnxt crash dump info */
67195bec10aSVikas Gupta bnxt_crash_config((uintptr_t)BNXT_CRASH_DUMP_INFO_NS3_BASE,
67295bec10aSVikas Gupta BNXT_CRASH_SEC_MEM,
67395bec10aSVikas Gupta BNXT_CRASH_LEN);
67495bec10aSVikas Gupta
67595bec10aSVikas Gupta /* Load bnxt firmware and fastboot */
67695bec10aSVikas Gupta bnxt_load(bnxt_src_image_info.bnxt_fw_vaddr);
67795bec10aSVikas Gupta
6789b726349SSheetal Tigadoli return TEE_SUCCESS;
6799b726349SSheetal Tigadoli }
6809b726349SSheetal Tigadoli
bnxt_copy_crash_dump(uint8_t * d,uint32_t offset,uint32_t len)6819b726349SSheetal Tigadoli TEE_Result bnxt_copy_crash_dump(uint8_t *d, uint32_t offset, uint32_t len)
6829b726349SSheetal Tigadoli {
683b5735546SJens Wiklander size_t crash_len = 0;
6849b726349SSheetal Tigadoli void *s = NULL;
6859b726349SSheetal Tigadoli
686b5735546SJens Wiklander if (ADD_OVERFLOW(offset, len, &crash_len) ||
687b5735546SJens Wiklander crash_len > BNXT_CRASH_LEN)
6889b726349SSheetal Tigadoli return TEE_ERROR_BAD_PARAMETERS;
6899b726349SSheetal Tigadoli
690c2e4eb43SAnton Rybakov s = phys_to_virt(BNXT_CRASH_SEC_MEM + offset, MEM_AREA_RAM_SEC, len);
6919b726349SSheetal Tigadoli
6929b726349SSheetal Tigadoli cache_op_inner(DCACHE_AREA_INVALIDATE, s, len);
6939b726349SSheetal Tigadoli
6949b726349SSheetal Tigadoli memcpy(d, s, len);
69595bec10aSVikas Gupta
69695bec10aSVikas Gupta return TEE_SUCCESS;
69795bec10aSVikas Gupta }
698