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