Merge tag 'v2021.04-rc5' into next
[pandora-u-boot.git] / tools / sunxi_egon.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2018 Arm Ltd.
4  */
5
6 #include "imagetool.h"
7 #include <image.h>
8
9 #include <sunxi_image.h>
10
11 /*
12  * NAND requires 8K padding. SD/eMMC gets away with 512 bytes,
13  * but let's use the larger padding to cover both.
14  */
15 #define PAD_SIZE                        8192
16
17 static int egon_check_params(struct image_tool_params *params)
18 {
19         /* We just need a binary image file. */
20         return !params->dflag;
21 }
22
23 static int egon_verify_header(unsigned char *ptr, int image_size,
24                               struct image_tool_params *params)
25 {
26         const struct boot_file_head *header = (void *)ptr;
27         uint32_t length;
28
29         /* First 4 bytes must be an ARM branch instruction. */
30         if ((le32_to_cpu(header->b_instruction) & 0xff000000) != 0xea000000)
31                 return EXIT_FAILURE;
32
33         if (memcmp(header->magic, BOOT0_MAGIC, sizeof(header->magic)))
34                 return EXIT_FAILURE;
35
36         length = le32_to_cpu(header->length);
37         /* Must be at least 512 byte aligned. */
38         if (length & 511)
39                 return EXIT_FAILURE;
40
41         /*
42          * Image could also contain U-Boot proper, so could be bigger.
43          * But it must not be shorter.
44          */
45         if (image_size < length)
46                 return EXIT_FAILURE;
47
48         return EXIT_SUCCESS;
49 }
50
51 static void egon_print_header(const void *buf)
52 {
53         const struct boot_file_head *header = buf;
54
55         printf("Allwinner eGON image, size: %d bytes\n",
56                le32_to_cpu(header->length));
57
58         if (memcmp(header->spl_signature, SPL_SIGNATURE, 3))
59                 return;
60
61         printf("\tSPL header version %d.%d\n",
62                header->spl_signature[3] >> SPL_MINOR_BITS,
63                header->spl_signature[3] & ((1U << SPL_MINOR_BITS) - 1));
64         if (header->spl_signature[3] >= SPL_DT_HEADER_VERSION) {
65                 uint32_t dt_name_offs = le32_to_cpu(header->dt_name_offset);
66
67                 if (dt_name_offs > 0)
68                         printf("\tDT name: %s\n", (char *)buf + dt_name_offs);
69         }
70 }
71
72 static void egon_set_header(void *buf, struct stat *sbuf, int infd,
73                             struct image_tool_params *params)
74 {
75         struct boot_file_head *header = buf;
76         uint32_t *buf32 = buf;
77         uint32_t checksum = 0, value;
78         int i;
79
80         /* Generate an ARM branch instruction to jump over the header. */
81         value = 0xea000000 | (sizeof(struct boot_file_head) / 4 - 2);
82         header->b_instruction = cpu_to_le32(value);
83
84         memcpy(header->magic, BOOT0_MAGIC, sizeof(header->magic));
85         header->check_sum = cpu_to_le32(BROM_STAMP_VALUE);
86         header->length = cpu_to_le32(params->file_size);
87
88         memcpy(header->spl_signature, SPL_SIGNATURE, 3);
89         header->spl_signature[3] = SPL_ENV_HEADER_VERSION;
90
91         /* If an image name has been provided, use it as the DT name. */
92         if (params->imagename && params->imagename[0]) {
93                 if (strlen(params->imagename) > sizeof(header->string_pool) - 1)
94                         printf("WARNING: DT name too long for SPL header!\n");
95                 else {
96                         strcpy((char *)header->string_pool, params->imagename);
97                         value = offsetof(struct boot_file_head, string_pool);
98                         header->dt_name_offset = cpu_to_le32(value);
99                         header->spl_signature[3] = SPL_DT_HEADER_VERSION;
100                 }
101         }
102
103         /* Calculate the checksum. Yes, it's that simple. */
104         for (i = 0; i < sbuf->st_size / 4; i++)
105                 checksum += le32_to_cpu(buf32[i]);
106         header->check_sum = cpu_to_le32(checksum);
107 }
108
109 static int egon_check_image_type(uint8_t type)
110 {
111         return type == IH_TYPE_SUNXI_EGON ? 0 : 1;
112 }
113
114 static int egon_vrec_header(struct image_tool_params *params,
115                             struct image_type_params *tparams)
116 {
117         tparams->hdr = calloc(sizeof(struct boot_file_head), 1);
118
119         /* Return padding to 8K blocks. */
120         return ALIGN(params->file_size, PAD_SIZE) - params->file_size;
121 }
122
123 U_BOOT_IMAGE_TYPE(
124         sunxi_egon,
125         "Allwinner eGON Boot Image support",
126         sizeof(struct boot_file_head),
127         NULL,
128         egon_check_params,
129         egon_verify_header,
130         egon_print_header,
131         egon_set_header,
132         NULL,
133         egon_check_image_type,
134         NULL,
135         egon_vrec_header
136 );