Merge branch 'master' of git://www.denx.de/git/u-boot-imx
[kernel/u-boot.git] / tools / kwbimage.c
1 /*
2  * (C) Copyright 2008
3  * Marvell Semiconductor <www.marvell.com>
4  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  */
8
9 #include "imagetool.h"
10 #include <image.h>
11 #include "kwbimage.h"
12
13 /*
14  * Supported commands for configuration file
15  */
16 static table_entry_t kwbimage_cmds[] = {
17         {CMD_BOOT_FROM,         "BOOT_FROM",            "boot command", },
18         {CMD_NAND_ECC_MODE,     "NAND_ECC_MODE",        "NAND mode",    },
19         {CMD_NAND_PAGE_SIZE,    "NAND_PAGE_SIZE",       "NAND size",    },
20         {CMD_SATA_PIO_MODE,     "SATA_PIO_MODE",        "SATA mode",    },
21         {CMD_DDR_INIT_DELAY,    "DDR_INIT_DELAY",       "DDR init dly", },
22         {CMD_DATA,              "DATA",                 "Reg Write Data", },
23         {CMD_INVALID,           "",                     "",     },
24 };
25
26 /*
27  * Supported Boot options for configuration file
28  */
29 static table_entry_t kwbimage_bootops[] = {
30         {IBR_HDR_SPI_ID,        "spi",          "SPI Flash",    },
31         {IBR_HDR_NAND_ID,       "nand",         "NAND Flash",   },
32         {IBR_HDR_SATA_ID,       "sata",         "Sata port",    },
33         {IBR_HDR_PEX_ID,        "pex",          "PCIe port",    },
34         {IBR_HDR_UART_ID,       "uart",         "Serial port",  },
35         {-1,                    "",             "Invalid",      },
36 };
37
38 /*
39  * Supported NAND ecc options configuration file
40  */
41 static table_entry_t kwbimage_eccmodes[] = {
42         {IBR_HDR_ECC_DEFAULT,           "default",      "Default mode", },
43         {IBR_HDR_ECC_FORCED_HAMMING,    "hamming",      "Hamming mode", },
44         {IBR_HDR_ECC_FORCED_RS,         "rs",           "RS mode",      },
45         {IBR_HDR_ECC_DISABLED,          "disabled",     "ECC Disabled", },
46         {-1,                            "",             "",     },
47 };
48
49 static struct kwb_header kwbimage_header;
50 static int datacmd_cnt = 0;
51 static char * fname = "Unknown";
52 static int lineno = -1;
53
54 /*
55  * Report Error if xflag is set in addition to default
56  */
57 static int kwbimage_check_params(struct image_tool_params *params)
58 {
59         if (!strlen (params->imagename)) {
60                 printf ("Error:%s - Configuration file not specified, "
61                         "it is needed for kwbimage generation\n",
62                         params->cmdname);
63                 return CFG_INVALID;
64         }
65         return  ((params->dflag && (params->fflag || params->lflag)) ||
66                 (params->fflag && (params->dflag || params->lflag)) ||
67                 (params->lflag && (params->dflag || params->fflag)) ||
68                 (params->xflag) || !(strlen (params->imagename)));
69 }
70
71 static uint32_t check_get_hexval (char *token)
72 {
73         uint32_t hexval;
74
75         if (!sscanf (token, "%x", &hexval)) {
76                 printf ("Error:%s[%d] - Invalid hex data(%s)\n", fname,
77                         lineno, token);
78                 exit (EXIT_FAILURE);
79         }
80         return hexval;
81 }
82
83 /*
84  * Generates 8 bit checksum
85  */
86 static uint8_t kwbimage_checksum8 (void *start, uint32_t len, uint8_t csum)
87 {
88         register uint8_t sum = csum;
89         volatile uint8_t *p = (volatile uint8_t *)start;
90
91         /* check len and return zero checksum if invalid */
92         if (!len)
93                 return 0;
94
95         do {
96                 sum += *p;
97                 p++;
98         } while (--len);
99         return (sum);
100 }
101
102 /*
103  * Generates 32 bit checksum
104  */
105 static uint32_t kwbimage_checksum32 (uint32_t *start, uint32_t len, uint32_t csum)
106 {
107         register uint32_t sum = csum;
108         volatile uint32_t *p = start;
109
110         /* check len and return zero checksum if invalid */
111         if (!len)
112                 return 0;
113
114         if (len % sizeof(uint32_t)) {
115                 printf ("Error:%s[%d] - length is not in multiple of %zu\n",
116                         __FUNCTION__, len, sizeof(uint32_t));
117                 return 0;
118         }
119
120         do {
121                 sum += *p;
122                 p++;
123                 len -= sizeof(uint32_t);
124         } while (len > 0);
125         return (sum);
126 }
127
128 static void kwbimage_check_cfgdata (char *token, enum kwbimage_cmd cmdsw,
129                                         struct kwb_header *kwbhdr)
130 {
131         bhr_t *mhdr = &kwbhdr->kwb_hdr;
132         extbhr_t *exthdr = &kwbhdr->kwb_exthdr;
133         int i;
134
135         switch (cmdsw) {
136         case CMD_BOOT_FROM:
137                 i = get_table_entry_id (kwbimage_bootops,
138                                 "Kwbimage boot option", token);
139
140                 if (i < 0)
141                         goto INVL_DATA;
142
143                 mhdr->blockid = i;
144                 printf ("Preparing kirkwood boot image to boot "
145                         "from %s\n", token);
146                 break;
147         case CMD_NAND_ECC_MODE:
148                 i = get_table_entry_id (kwbimage_eccmodes,
149                         "NAND ecc mode", token);
150
151                 if (i < 0)
152                         goto INVL_DATA;
153
154                 mhdr->nandeccmode = i;
155                 printf ("Nand ECC mode = %s\n", token);
156                 break;
157         case CMD_NAND_PAGE_SIZE:
158                 mhdr->nandpagesize =
159                         (uint16_t) check_get_hexval (token);
160                 printf ("Nand page size = 0x%x\n", mhdr->nandpagesize);
161                 break;
162         case CMD_SATA_PIO_MODE:
163                 mhdr->satapiomode =
164                         (uint8_t) check_get_hexval (token);
165                 printf ("Sata PIO mode = 0x%x\n",
166                                 mhdr->satapiomode);
167                 break;
168         case CMD_DDR_INIT_DELAY:
169                 mhdr->ddrinitdelay =
170                         (uint16_t) check_get_hexval (token);
171                 printf ("DDR init delay = %d msec\n", mhdr->ddrinitdelay);
172                 break;
173         case CMD_DATA:
174                 exthdr->rcfg[datacmd_cnt].raddr =
175                         check_get_hexval (token);
176
177                 break;
178         case CMD_INVALID:
179                 goto INVL_DATA;
180         default:
181                 goto INVL_DATA;
182         }
183         return;
184
185 INVL_DATA:
186         printf ("Error:%s[%d] - Invalid data\n", fname, lineno);
187         exit (EXIT_FAILURE);
188 }
189
190 /*
191  * this function sets the kwbimage header by-
192  *      1. Abstracting input command line arguments data
193  *      2. parses the kwbimage configuration file and update extebded header data
194  *      3. calculates header, extended header and image checksums
195  */
196 static void kwdimage_set_ext_header (struct kwb_header *kwbhdr, char* name) {
197         bhr_t *mhdr = &kwbhdr->kwb_hdr;
198         extbhr_t *exthdr = &kwbhdr->kwb_exthdr;
199         FILE *fd = NULL;
200         int j;
201         char *line = NULL;
202         char * token, *saveptr1, *saveptr2;
203         size_t len = 0;
204         enum kwbimage_cmd cmd;
205
206         fname = name;
207         /* set dram register offset */
208         exthdr->dramregsoffs = (intptr_t)&exthdr->rcfg - (intptr_t)mhdr;
209
210         if ((fd = fopen (name, "r")) == 0) {
211                 printf ("Error:%s - Can't open\n", fname);
212                 exit (EXIT_FAILURE);
213         }
214
215         /* Simple kwimage.cfg file parser */
216         lineno=0;
217         while ((getline (&line, &len, fd)) > 0) {
218                 lineno++;
219                 token = strtok_r (line, "\r\n", &saveptr1);
220                 /* drop all lines with zero tokens (= empty lines) */
221                 if (token == NULL)
222                         continue;
223
224                 for (j = 0, cmd = CMD_INVALID, line = token; ; line = NULL) {
225                         token = strtok_r (line, " \t", &saveptr2);
226                         if (token == NULL)
227                         break;
228                         /* Drop all text starting with '#' as comments */
229                         if (token[0] == '#')
230                                 break;
231
232                         /* Process rest as valid config command line */
233                         switch (j) {
234                         case CFG_COMMAND:
235                                 cmd = get_table_entry_id (kwbimage_cmds,
236                                                 "Kwbimage command", token);
237
238                                 if (cmd == CMD_INVALID)
239                                         goto INVL_CMD;
240                                 break;
241
242                         case CFG_DATA0:
243                                 kwbimage_check_cfgdata (token, cmd, kwbhdr);
244                                 break;
245
246                         case CFG_DATA1:
247                                 if (cmd != CMD_DATA)
248                                         goto INVL_CMD;
249
250                                 exthdr->rcfg[datacmd_cnt].rdata =
251                                                 check_get_hexval (token);
252
253                                 if (datacmd_cnt > KWBIMAGE_MAX_CONFIG ) {
254                                         printf ("Error:%s[%d] - Found more "
255                                                 "than max(%zd) allowed "
256                                                 "data configurations\n",
257                                                 fname, lineno,
258                                                 KWBIMAGE_MAX_CONFIG);
259                                 exit (EXIT_FAILURE);
260                                 } else
261                                         datacmd_cnt++;
262                                 break;
263
264                         default:
265                                 goto INVL_CMD;
266                         }
267                         j++;
268                 }
269         }
270         if (line)
271                 free (line);
272
273         fclose (fd);
274         return;
275
276 /*
277  * Invalid Command error reporring
278  *
279  * command CMD_DATA needs three strings on a line
280  * whereas other commands need only two.
281  *
282  * if more than two/three (as per command type) are observed,
283  * then error will be reported
284  */
285 INVL_CMD:
286         printf ("Error:%s[%d] - Invalid command\n", fname, lineno);
287         exit (EXIT_FAILURE);
288 }
289
290 static void kwbimage_set_header (void *ptr, struct stat *sbuf, int ifd,
291                                 struct image_tool_params *params)
292 {
293         struct kwb_header *hdr = (struct kwb_header *)ptr;
294         bhr_t *mhdr = &hdr->kwb_hdr;
295         extbhr_t *exthdr = &hdr->kwb_exthdr;
296         uint32_t checksum;
297         int size;
298
299         /* Build and add image checksum header */
300         checksum = kwbimage_checksum32 ((uint32_t *)ptr, sbuf->st_size, 0);
301
302         size = write (ifd, &checksum, sizeof(uint32_t));
303         if (size != sizeof(uint32_t)) {
304                 printf ("Error:%s - Checksum write %d bytes %s\n",
305                         params->cmdname, size, params->imagefile);
306                 exit (EXIT_FAILURE);
307         }
308
309         sbuf->st_size += sizeof(uint32_t);
310
311         mhdr->blocksize = sbuf->st_size - sizeof(struct kwb_header);
312         mhdr->srcaddr = sizeof(struct kwb_header);
313         mhdr->destaddr= params->addr;
314         mhdr->execaddr =params->ep;
315         mhdr->ext = 0x1; /* header extension appended */
316
317         kwdimage_set_ext_header (hdr, params->imagename);
318         /* calculate checksums */
319         mhdr->checkSum = kwbimage_checksum8 ((void *)mhdr, sizeof(bhr_t), 0);
320         exthdr->checkSum = kwbimage_checksum8 ((void *)exthdr,
321                                                 sizeof(extbhr_t), 0);
322 }
323
324 static int kwbimage_verify_header (unsigned char *ptr, int image_size,
325                         struct image_tool_params *params)
326 {
327         struct kwb_header *hdr = (struct kwb_header *)ptr;
328         bhr_t *mhdr = &hdr->kwb_hdr;
329         extbhr_t *exthdr = &hdr->kwb_exthdr;
330         uint8_t calc_hdrcsum;
331         uint8_t calc_exthdrcsum;
332
333         calc_hdrcsum = kwbimage_checksum8 ((void *)mhdr,
334                         sizeof(bhr_t) - sizeof(uint8_t), 0);
335         if (calc_hdrcsum != mhdr->checkSum)
336                 return -FDT_ERR_BADSTRUCTURE;   /* mhdr csum not matched */
337
338         calc_exthdrcsum = kwbimage_checksum8 ((void *)exthdr,
339                         sizeof(extbhr_t) - sizeof(uint8_t), 0);
340         if (calc_exthdrcsum != exthdr->checkSum)
341                 return -FDT_ERR_BADSTRUCTURE; /* exthdr csum not matched */
342
343         return 0;
344 }
345
346 static void kwbimage_print_header (const void *ptr)
347 {
348         struct kwb_header *hdr = (struct kwb_header *) ptr;
349         bhr_t *mhdr = &hdr->kwb_hdr;
350         char *name = get_table_entry_name (kwbimage_bootops,
351                                 "Kwbimage boot option",
352                                 (int) mhdr->blockid);
353
354         printf ("Image Type:   Kirkwood Boot from %s Image\n", name);
355         printf ("Data Size:    ");
356         genimg_print_size (mhdr->blocksize - sizeof(uint32_t));
357         printf ("Load Address: %08x\n", mhdr->destaddr);
358         printf ("Entry Point:  %08x\n", mhdr->execaddr);
359 }
360
361 static int kwbimage_check_image_types (uint8_t type)
362 {
363         if (type == IH_TYPE_KWBIMAGE)
364                 return EXIT_SUCCESS;
365         else
366                 return EXIT_FAILURE;
367 }
368
369 /*
370  * kwbimage type parameters definition
371  */
372 static struct image_type_params kwbimage_params = {
373         .name = "Kirkwood Boot Image support",
374         .header_size = sizeof(struct kwb_header),
375         .hdr = (void*)&kwbimage_header,
376         .check_image_type = kwbimage_check_image_types,
377         .verify_header = kwbimage_verify_header,
378         .print_header = kwbimage_print_header,
379         .set_header = kwbimage_set_header,
380         .check_params = kwbimage_check_params,
381 };
382
383 void init_kwb_image_type (void)
384 {
385         register_image_type(&kwbimage_params);
386 }