aa57ba8b95741fd69fefbd71f30375f730648128
[keystone-rtos/ibl.git] / src / util / romparse / romparse.c
1 /*************************************************************************************
2  * FILE PURPOSE: Create an I2C rom with multiple boot parameter sections and
3  *               programs
4  *************************************************************************************
5  * FILE NAME: romparse.c
6  *
7  * DESCRIPTION: Creates a ccs hex file which contains the i2c eprom boot parameter 
8  *              tables as well as any code.
9  *
10  *************************************************************************************/
11 #include <stdio.h>
12 #include <string.h>
13 #include <malloc.h>
14 #include "rparse.tab.h"
15 #include "romparse.h"
17 /*************************************************************************************
18  * Definition: fixed i2c map locations
19  *************************************************************************************/
20 #define PCI_PARAM_BASE  (NUM_BOOT_PARAM_TABLES * 0x80)
21 #define DATA_BASE       (PCI_PARAM_BASE + PCI_EEAI_PARAM_SIZE)
25 /*************************************************************************************
26  * Declaration: The flex input file is assigned based on the command line
27  *************************************************************************************/
28 extern FILE *yyin;
30 /*************************************************************************************
31  * Declaration: currentType identifies the current parse mode, either SECTION
32  *              or LAYOUT.
33  *************************************************************************************/
34 int currentType;
36 /*************************************************************************************
37  * Declaration: The boot parameter tables. The current table is copied into position
38  *              when the section parse is complete.
39  *************************************************************************************/
40 BOOT_PARAMS_T boot_params[NUM_BOOT_PARAM_TABLES];
41 BOOT_PARAMS_T current_table;
42 int           current_file;       /* Identifies the program file in the current table */
43 int           ctable_index = -1;  /* Destination of current table */
44 int           max_index    =  0;  /* maximum table index, used for compacting output */
46 /************************************************************************************
47  * Declaration: Layout tables. 
48  ************************************************************************************/
49 layout_t  layouts[MAX_LAYOUTS];   /* Array of layout structures */                
50 int       currentLayout = 0;      /* Currently active layout    */
52 /************************************************************************************
53  * Declaration: The structure storing the program data files, and the number of
54  *              programs used.
55  ************************************************************************************/
56 progFile_t progFile[NUM_BOOT_PARAM_TABLES];
57 int        nProgFiles = 0;
59 /************************************************************************************
60  * Declaration: The PCI parameter structure
61  ************************************************************************************/
62 pciFile_t pciFile;
63 int       pciSet = 0;
65 /*************************************************************************************
66  * Declaration: The next free address in the ROM for general data usage. For the
67  *              start address there is room for the initial boot parameter tables, 
68  *              plus room for the PCI eeai config.
69  *************************************************************************************/
70 int romBase = DATA_BASE;
73 /*************************************************************************************
74  * Declaration: Args passed in from the command line
75  *************************************************************************************/
76 char *inputFile;
77 int   compact = 0;
80 /*************************************************************************************
81  * FUNCTION PURPOSE: flex/bison required support functions.
82  *************************************************************************************
83  * DESCRIPTION: yyerror and yywrap are required to support flex and/or bison parsing
84  *              of the parameter description file. yyerror directly reports the
85  *              error, yywrap is unused.
86  *************************************************************************************/
87 void yyerror (char *s)
88 {
89   fprintf (stderr, "flex/bison error is %s\n", s);
90 } /* yyerror */
92 void yywrap (void)
93 {
94 } /* yywrap */
96 /*************************************************************************************
97  * FUNCTION PURPOSE: Initialize a boot table
98  *************************************************************************************
99  * DESCRIPTION: Sets a boot parameter table to 0s
100  *************************************************************************************/
101 void initTable (BOOT_PARAMS_T *current_table)
103   memset (current_table, 0, sizeof(BOOT_PARAMS_T));
106 /*************************************************************************************
107  * FUNCTION PURPOSE: Initialize the program data file table
108  *************************************************************************************
109  * DESCRIPTION: The size and tags are all setup
110  *************************************************************************************/
111 void initProgFile (void)
113   int i, j;
115   for (i = 0; i < NUM_BOOT_PARAM_TABLES; i++)  {
116     progFile[i].sizeBytes = 0;
117     progFile[i].align     = 0;
119     for (j = 0; j < NUM_BOOT_PARAM_TABLES; j++)
120       progFile[i].tag[j] = -1;
122   }
127 /*************************************************************************************
128  * FUNCTION PURPOSE: Set the currently active parse type
129  *************************************************************************************
130  * DESCRIPTION: Indicates if the subsequent parameters belong to a section or
131  *              a layout
132  *************************************************************************************/
133 void rBegin (int blockType)
135     currentType = blockType;
138 /*************************************************************************************
139  * FUNCTION PURPOSE: Initialize a layout structure
140  *************************************************************************************
141  * DESCRIPTION: The layout is set to the initial state
142  *************************************************************************************/
143 void initLayout (layout_t *cl)
146   cl->nFiles   = 0;
147   cl->dev_addr = 0x50;
148   cl->address  = 0;
149   cl->align    = 0;
153 /*************************************************************************************
154  * FUNCTION PURPOSE: Complete a layout
155  *************************************************************************************
156  * DESCRIPTION: The parser has found a complete layout specification. Complete
157  *              a layout structure
158  *************************************************************************************/
159 void setLayout (void)
161   int i;
162   int currentAlign;
163   int newAlign;
165   for (i = 0; i < layouts[currentLayout].nFiles; i++)  {
166     currentAlign = progFile[layouts[currentLayout].file[i]].align;
167     newAlign     = layouts[currentLayout].align;
169     if (newAlign > currentAlign)
170       progFile[layouts[currentLayout].file[i]].align = newAlign;
172   }
173     
174   currentLayout += 1;      /* Advance to the next layout */
176   if (currentLayout < MAX_LAYOUTS)
177     initLayout (&layouts[currentLayout]);
179 }    
180     
183 /*************************************************************************************
184  * FUNCTION PURPOSE: Complete a section
185  *************************************************************************************
186  * DESCRIPTION: The parser has detected a complete section. Copy the section into
187  *              it's correct table location.
188  *************************************************************************************/
189 void section (void)
191   int i;
193   /* It's an error if no section value has been declared */
194   if (ctable_index == -1)  {
195     fprintf (stderr, "romparse: the section did not have a boot paramter index specified\n");
196     exit (-1);
197   }
199   /* Make sure the table is in range */
200   if (ctable_index >= NUM_BOOT_PARAM_TABLES)  {
201     fprintf (stderr, "romparse: The section index is too large (max %d)\n", NUM_BOOT_PARAM_TABLES-1);
202     exit (-1);
203   }
205   /* The length must be set. Currently this program only supports I2C mode, so the
206    * length is fixed */
207   current_table.common.length   = 30;
208   current_table.common.checksum = 0;
210   /* Copy the table */
211   memcpy (&boot_params[ctable_index], &current_table, sizeof (BOOT_PARAMS_T));
212   initTable (&current_table);
214   /* Track the maximum table index */
215   if (ctable_index > max_index)
216     max_index = ctable_index;
218   /* If the section referenced a data file, link the data file back to this section */
219   if (current_file >= 0)  {
220     for (i = 0; i < NUM_BOOT_PARAM_TABLES; i++)  {
221       if (progFile[current_file].tag[i] < 0)
222         progFile[current_file].tag[i] = ctable_index;
223         break;
224     }
225   }
227   ctable_index = -1;
228   current_file = -1;
230 } /* section */
232 /***************************************************************************************
233  * FUNCTION PURPOSE: Open a ccs hex file and read in the data.
234  ***************************************************************************************
235  * DESCRIPTION: Reads a ccs hex format data file, loads the file into the
236  *              next program file structure. Returns the index of the just loaded
237  *              table.
238  ***************************************************************************************/
239 int openProgFile (char *fname)
241   FILE *str;
242   int a, b, c, d, e;
243   int i;
244   char iline[132];
246   /* Store the file name */
247   strcpy (progFile[nProgFiles].fname, fname);
249   /* Open the data file */
250   str = fopen (fname, "r");
251   if (str == NULL)  {
252     fprintf (stderr, "romparse: Could not open file %s\n", fname);
253     exit (-1);
254   }
256   /* Read the one line ccs header. The length field in terms of lines */
257   fgets (iline, 132, str);
258   sscanf (iline, "%x %x %x %x %x", &a, &b, &c, &d, &e);
259   progFile[nProgFiles].sizeBytes = e * 4; /* Length was in 4 byte words */
261   /* Read in the data */
262   for (i = 0; i < e; i++)  {
263     fgets (iline, 132, str);
264     sscanf (&(iline[2]), "%x", &((progFile[nProgFiles]).data[i]));
265   }
267   fclose (str);
269   i = nProgFiles;
270   nProgFiles += 1;
272   return (i);
274 } /* openProgFile */
276 /***************************************************************************************
277  * FUNCTION PURPOSE: Load the PCI paramter section
278  ***************************************************************************************
279  * DESCRIPTION: Loads the PCI parameter section and stores it in the rom. */
280 int setPciParams (char *fname)
282   FILE *str;
283   int a, b, c, d, e;
284   int i;
285   char iline[132];
286   char *z;
288   if (pciSet)  {
289     fprintf (stderr, "romparse: PCI parameters specified more then once\n");
290     exit (-1);
291   }
293   /* the input string still contains the quotes. Remove them here */
294   z = &fname[1];
295   *strchr (z, '"') = '\0';
297   /* Store the file name */
298   strcpy (pciFile.fname, z);
300   /* Open the data file */
301   str = fopen (z, "r");
302   if (str == NULL)  {
303     fprintf (stderr, "romparse: Could not open pci file %s\n", fname);
304     exit (-1);
305   }
307   /* The address of the pci params is currently fixed */
308   pciFile.addressBytes = PCI_PARAM_BASE;
310   /* Read the one line ccs header. The length field is in terms of lines */
311   fgets (iline, 132, str);
312   sscanf (iline, "%x %x %x %x %x", &a, &b, &c, &d, &e);
313   pciFile.sizeBytes = e * 4;  /* Convert length to bytes */
315   /* Read in the data */
316   for (i = 0; i < e; i++)  {
317     fgets (iline, 132, str);
318     sscanf (&(iline[2]), "%x", &(pciFile.data[i]));
319   }
321   pciSet = 1;
323   return (0);
325 } /* setPciParams */
327  
329 /***************************************************************************************
330  * FUNCTION PURPOSE: Store an assignment
331  ***************************************************************************************
332  * DESCRIPTION: Stores an assigned value into the current boot parameter table
333  ***************************************************************************************/
334 void assignKeyVal (int field, int value)
337   if ((currentType == SECTION) && (currentLayout >= MAX_LAYOUTS))  {
338     fprintf (stderr, "romparse: Too many layout sections (max = %d\n", MAX_LAYOUTS);
339     return;
340   }
344   switch (field)  {
346     case BOOT_MODE:        current_table.common.boot_mode = value;
347                            break;
349     case PARAM_INDEX:      ctable_index = value;
350                            break;
352     case OPTIONS:          current_table.i2c.options = value;
353                            break;
355     case MULTI_I2C_ID:     current_table.i2c.multi_i2c_id = value;
356                            break;
358     case MY_I2C_ID:        current_table.i2c.my_i2c_id = value;
359                            break;
361     case CORE_FREQ_MHZ:    current_table.i2c.core_freq_mhz = value;
362                            break;
364     case I2C_CLK_FREQ_KHZ: current_table.i2c.i2c_clk_freq_khz = value;
365                            break;
367     case NEXT_DEV_ADDR:    current_table.i2c.next_dev_addr = value;
368                            break;
369                                
371     case NEXT_DEV_ADDR_EXT: current_table.i2c.next_dev_addr_ext = value;
372                             break;
374     case ADDRESS_DELAY:    current_table.i2c.address_delay = value;
375                            break;
377 #ifndef c6455         
378     case SWPLL:            current_table.i2c.swPll = value;
379                            break;
380 #endif
382     case DEV_ADDR_EXT:     if (currentType == SECTION)
383                              current_table.i2c.dev_addr_ext = value;
384                            else 
385                              layouts[currentLayout].dev_addr = value;
387                            break;
389     case DEV_ADDR:         if (currentType == SECTION) 
390                              current_table.i2c.dev_addr = value;
391                            else
392                              layouts[currentLayout].address = value;
394                            break;
396     case ALIGN:            layouts[currentLayout].align = value;
397                            break;
400   }
402 } /* assignKeyVal */
405 /*******************************************************************************
406  * FUNCTION PURPOSE: Parse a string input.
407  *******************************************************************************
408  * DESCRIPTION: Takes a string input. Currently only the i2c exe file name can be 
409  *              assigned a string. 
410  *******************************************************************************/
411 void assignKeyStr (int value, char *y)
413   int i;
414   char *z;
417   /* the input string still contains the quotes. Remove them here */
418   z = &y[1];
419   *strchr (z, '"') = '\0';
421   /* Check if the file name is already open */
422   for (i = 0; i < nProgFiles; i++)  {
424     if (!strcmp (z, progFile[i].fname))  {
426       /* Found a match */
428       if (currentType == SECTION)  {
430         current_file = i;
432         if (current_table.i2c.dev_addr_ext == 0)
433           current_table.i2c.dev_addr_ext = 0x50;  /* hard coded to i2c rom slave address */
435       }  else  {   /* LAYOUT */
437         if (currentLayout < MAX_LAYOUTS)
438           layouts[currentLayout].file[layouts[currentLayout].nFiles++] = i;
439         else
440           fprintf (stderr, "romparse: Number of layout sections exceeded (max = %d)\n", MAX_LAYOUTS);
442       }
443         
445       return;
446     }
448   }
450   /* Open and read the ccs file, set the ROM address */
451   i = openProgFile (z);
452   if (i >= 0) {
454     if (currentType == SECTION)  {
456       current_file = i;
457       if (current_table.i2c.dev_addr_ext == 0)
458           current_table.i2c.dev_addr_ext = 0x50;
460     }  else  {  /* LAYOUT */
461         
462         if (currentLayout < MAX_LAYOUTS)
463           layouts[currentLayout].file[layouts[currentLayout].nFiles++] = i;
464         else
465           fprintf (stderr, "romparse: Number of layout sections exceeded (max = %d)\n", MAX_LAYOUTS);
467     }
468       
469         
470   }
472 } /* assignKeyStr */
474 /************************************************************************************
475  * FUNCTION PURPOSE: Put a 32 bit value into the i2c image memory
476  ************************************************************************************
477  * DESCRIPTION: The 32 bit value is placed in memory in big endian format. The
478  *              new offset is returned (4 bytes more then the input offset)
479  ************************************************************************************/
480 unsigned int imageWord (unsigned int base, unsigned char *image, unsigned int value)
482     image[base+0] = (value >> 24) & 0xff;
483     image[base+1] = (value >> 16) & 0xff;
484     image[base+2] = (value >>  8) & 0xff;
485     image[base+3] = (value >>  0) & 0xff;
487     return (base + 4);
491 /************************************************************************************
492  * FUNCTION PURPOSE: Create a 32 bit value from the image array
493  ************************************************************************************
494  * DESCRIPTION: A 32 bit word in big endian format is created
495  ************************************************************************************/
496 unsigned int formWord (unsigned int p, unsigned char *image)
498   unsigned int v;
500   v = (image[p+0] << 24) |
501       (image[p+1] << 16) |
502       (image[p+2] <<  8) |
503       (image[p+3] <<  0) ;
505   return (v);
509 /************************************************************************************
510  * FUNCTION PURPOSE: Pad the image array
511  ************************************************************************************
512  * DESCRIPTION: Byte (value 0) are added to the image to reach the desired address
513  *              The desired address is returned.
514  ************************************************************************************/
515 unsigned int imagePad (unsigned int base, unsigned char *image, unsigned int desired)
517   int i;
519   if (desired < base)  {
520     fprintf (stderr, "romparse: Padd to %d requested, but current base (%d) is already past this point\n",
521              desired, base);
522     exit (-1);
523   }
525   for (i = base; i < desired; i++)
526     image[i] = 0;
528   return (desired);
532 /************************************************************************************
533  * FUNCTION PURPOSE: Opens and writes the output file
534  ************************************************************************************
535  * DESCRIPTION: Creates the output file in ccs format.
536  ************************************************************************************/
537 void createOutput (void)
539   FILE *str;
540   int   totalLenBytes;
541   int   i, j;
542   int   nTables, len;
543   unsigned int value, v1, v2;
544   unsigned int base, obase;
545   unsigned char *image;
547   str = fopen ("i2crom.ccs", "w");
548   if (str == NULL)  {
549     fprintf (stderr, "romparse: Could not open output file i2crom.ccs for writing\n");
550     exit (-1);
551   }
553   /* Compact the i2c eeprom to use the minimum memory possible */
554   base    = PCI_PARAM_BASE;
555   nTables = NUM_BOOT_PARAM_TABLES; 
557   if ((compact != 0) && (pciSet == 0))  {
558     nTables = max_index + 1;
559     base    = nTables * 0x80;  /* The number of parameter tables * size of a parameter table */
560   }
562   if (pciSet)
563     base = base + PCI_EEAI_PARAM_SIZE;
565   /* Layout tables */
566   for (i = 0; i < currentLayout; i++)  {
568     /* Determine the size of the table. Four bytes for each file, plus the 4 byte header */ 
569     v1 = (layouts[i].nFiles * 4) + 4;
571     v2 = (layouts[i].dev_addr << 16) + layouts[i].address;
573     if (v2 == 0)
574       base = base + v1;
576     else  {
578       /* Mask out device address bits but extend past 64k */
579       v2 = v2 & I2C_ADDR_MASK;
581       if (base > v2)  {
582         fprintf (stderr, "romparse: fatal error - layout block %d specified a start address of 0x%04x\n", i, layouts[i].address);
583         fprintf (stderr, "          but this conflicts with the base mapping (ends at 0x%04x)\n", base);
584         exit (-1);
585       }
587       base = layouts[i].address + v1;
589     }
591   }
594   for (i = 0; i < NUM_BOOT_PARAM_TABLES; i++)  {
595     if (progFile[i].align > 0)  
596       base = ((base + progFile[i].align - 1) / progFile[i].align) * progFile[i].align;
597     progFile[i].addressBytes = base;
598     base = base + progFile[i].sizeBytes;
599   }
601   /* Setup the base program file addresses. If a parameter set has
602    * been tagged it means that this is an i2c program load */
603   for (i = 0; i < NUM_BOOT_PARAM_TABLES; i++)  {
604     for (j = 0; j < NUM_BOOT_PARAM_TABLES; j++)  {
605       if (progFile[i].tag[j] >= 0)
606         boot_params[progFile[i].tag[j]].i2c.dev_addr = progFile[i].addressBytes;
607     }
608   }
610   /* Round up the size to a multiple of 4 bytes to fit into a ccs data file */
611   base = (base + 3) & ~3;
613       
614   /* The total length of the i2c eeprom is now stored in base */
615   /* Write out the ccs header */
616   fprintf (str, "1651 1 10000 1 %x\n", base >> 2);
619   /* Create the image in memory */
620   image = malloc (base * sizeof (unsigned char));
621   if (image == NULL)  {
622     fprintf (stderr, "romparse: malloc failed creating the output image\n");
623     exit (-1);
624   }
626   /* Write out the boot parameter tables. 0x80 bytes will be written out.
627    * There are 16 bits in every parameter field, which is why the index
628    * is from 0 to 0x40 */
629   base = 0;
630   for (i = 0; i < nTables; i++)  {
631     for (j = 0; j < (0x80 >> 1); j += 2)  {
632       v1 = boot_params[i].parameter[j];
633       v2 = boot_params[i].parameter[j+1];
634       value = (v1 << 16) | v2;
635       base = imageWord (base, image, value);
636     }
637   }
639   /* Write out the PCI parameter base. If none was included then zeros will be
640    * written out */
641   if (pciSet)  {
642     for (i = 0; i < PCI_DATA_LEN_32bit; i++)  {
643       base = imageWord (base, image, pciFile.data[i]);
644     }
645   }
648   /* Layout sections */
649   for (i = 0; i < currentLayout; i++)  {
651     v1 = (layouts[i].dev_addr << 16) + layouts[i].address;
653     /* Mask out device address bits */
654     v1 = v1 & I2C_ADDR_MASK;
655     if (v1 > 0)
656       base  = imagePad (base, image, v1);
657     obase = base;
658     len   = (layouts[i].nFiles * 4) + 4;
660     /* Write out the block size and checksum */
661     base = imageWord(base, image, len << 16);
663     for (j = 0; j < layouts[i].nFiles; j++)
664         base = imageWord (base, image, progFile[layouts[i].file[j]].addressBytes);
666   }
667                                 
669   /* Write out each of the program files */
670   for (i = 0; i < nProgFiles; i++)  {
672     base = imagePad (base, image, progFile[i].addressBytes);
674     for (j = 0; j < progFile[i].sizeBytes >> 2; j++)
675       base = imageWord (base, image, (progFile[i]).data[j]);
676   }
678   /* Write out the data file */
679   for (i = 0; i < base; i += 4) 
680     fprintf (str, "0x%08x\n", formWord (i, image));
682   free (image);
684   /* Close the output file */
685   fclose (str);
687 } /* createOutput  */
689 /************************************************************************************
690  * FUNCTION PURPOSE: Initialize the pci paramter table
691  ************************************************************************************
692  * DESCRIPTION: Zeros the pci parameters
693  ************************************************************************************/
694 void initPciParams (void)
696   memset (&pciFile, 0, sizeof(pciFile_t));
697 } /* initPciParams */
701 /************************************************************************************
702  * FUNCTION PURPOSE: Parse the input arguments.
703  ************************************************************************************
704  * DESCRIPTION: Returns -1 on invalid args
705  ************************************************************************************/
706 int parseIt (int argc, char *argv[])
708   int i;
710   if (argc < 2)  {
711      fprintf (stderr, "usage: %s [-compact] inputfile\n", argv[0]);
712      return (-1);
713   }
715   inputFile = NULL;  
717   for (i = 1; i < argc;  )  {
719     if (!strcmp (argv[i], "-compact"))  {
720       compact = 1;
721       i += 1;
723     } else  {
725       if (inputFile != NULL)  {
726         fprintf (stderr, "usage: %s [-compact] inputfile\n", argv[0]);
727         return (-1);
728       }
730       inputFile = argv[i];
731       i += 1;
732     }
733   }
735   return (0);
741 /************************************************************************************
742  * FUNCTION PURPOSE: main function
743  ************************************************************************************
744  * DESCRIPTION: Performs the processing sequence.
745  ************************************************************************************/
746 int main (int argc, char *argv[])
748   int i;
750   /* Initialize the tables */
751   for (i = 0; i < NUM_BOOT_PARAM_TABLES; i++)
752     initTable(&boot_params[i]);
754   initTable (&current_table);
755   current_file = -1;
757   /* Initialize the program file structure */
758   initProgFile ();
760   /* Initialize the PCI param table */
761   initPciParams ();
763   /* Initialize the layout structures */
764   currentLayout = 0;
765   initLayout (&layouts[currentLayout]);
767   /* Parse the input parameters */
768   if (parseIt (argc, argv))
769     return (-1);
771   
772   yyin = fopen (inputFile, "r");
773   if (yyin == NULL)  {
774     fprintf (stderr, "%s: could not open file %s\n", argv[0], inputFile);
775     return (-1);
776   }
778   /* Parse the input description file */
779   yyparse();
782   /* Create the output file */
783   createOutput ();
785   return (0);