2b6157f89f4fda184fefa15f91164fd7c5697024
[coreboot.git] / util / sconfig / sconfig.y
1 %{
2 /*
3  * sconfig, coreboot device tree compiler
4  *
5  * Copyright (C) 2010 coresystems GmbH
6  *                 written by Patrick Georgi <patrick.georgi@coresystems.de>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <errno.h>
29
30 enum devtype { chip, device };
31
32 struct resource;
33 struct resource {
34         int type;
35         int index;
36         int base;
37         struct resource *next;
38 };
39
40 struct reg;
41 struct reg {
42         char *key;
43         char *value;
44         struct reg *next;
45 };
46
47 struct device;
48 struct device {
49         int id;
50         int enabled;
51         int used;
52         int multidev;
53         int link;
54         int rescnt;
55         int chiph_exists;
56         char *ops;
57         char *name;
58         char *aliased_name;
59         char *name_underscore;
60         char *path;
61         int path_a;
62         int path_b;
63         int bustype;
64         enum devtype type;
65         struct device *parent;
66         struct device *bus;
67         struct device *next;
68         struct device *nextdev;
69         struct device *children;
70         struct device *latestchild;
71         struct device *next_sibling;
72         struct device *sibling;
73         struct device *chip;
74         struct resource *res;
75         struct reg *reg;
76 } *head, *lastdev, *cur_parent, *cur_bus, root;
77
78 struct header;
79 struct header {
80         char *name;
81         struct header *next;
82 } headers;
83
84 int devcount = 0;
85
86 struct device *new_dev() {
87         struct device *dev = malloc(sizeof(struct device));
88         memset(dev, 0, sizeof(struct device));
89         dev->id = ++devcount;
90         dev->parent = cur_parent;
91         dev->bus = cur_bus;
92         head->next = dev;
93         head = dev;
94         return dev;
95 }
96
97 int device_match(struct device *a, struct device *b) {
98         if ((a->bustype == b->bustype) && (a->bus == b->bus) && (a->path_a == b->path_a) && (a->path_b == b->path_b))
99                 return 1;
100         return 0;
101 }
102
103 void fold_in(struct device *parent) {
104         struct device *child = parent->children;
105         struct device *latest = 0;
106         while (child != latest) {
107                 if (child->children) {
108                         if (!latest) latest = child->children;
109                         parent->latestchild->next_sibling = child->children;
110                         parent->latestchild = child->latestchild;
111                 }
112                 child = child->next_sibling;
113         }
114 }
115
116 int yywrap(void) {
117         return 1;
118 }
119
120 void yyerror (char const *str)
121 {
122         fprintf (stderr, "%s\n", str);
123 }
124 %}
125 %union {
126         struct device *device;
127         char *string;
128         int number;
129 }
130 %token CHIP DEVICE REGISTER BOOL BUS RESOURCE END EQUALS HEX STRING PCI PNP I2C APIC APIC_CLUSTER PCI_DOMAIN IRQ DRQ IO NUMBER
131 %%
132 devtree: devchip {
133         root.next_sibling = root.children;
134         root.next_sibling->next_sibling = root.next_sibling->children;
135
136         struct device *dev = &root;
137         while (dev) {
138                 /* skip "chip" elements in children chain */
139                 while (dev->children && (dev->children->type == chip)) dev->children = dev->children->children;
140                 /* skip "chip" elements and functions of the same device in sibling chain */
141                 while (dev->sibling && dev->sibling->used) dev->sibling = dev->sibling->sibling;
142                 /* If end of chain, and parent is a chip, move on */
143                 if (!dev->sibling && (dev->parent->type == chip)) dev->sibling = dev->parent->sibling;
144                 /* skip chips */
145                 while (dev->sibling && dev->sibling->type == chip) dev->sibling = dev->sibling->children;
146                 /* skip duplicate function elements in nextdev chain */
147                 while (dev->nextdev && dev->nextdev->used) dev->nextdev = dev->nextdev->nextdev;
148                 dev = dev->next_sibling;
149         }
150         };
151
152 devchip: chip | device ;
153
154 devices: devices devchip | devices registers | ;
155
156 devicesorresources: devicesorresources devchip | devicesorresources resource | ;
157
158 chip: CHIP STRING /* == path */ {
159         $<device>$ = new_dev();
160         $<device>$->chiph_exists = 1;
161         $<device>$->name = $<string>2;
162         $<device>$->name_underscore = strdup($<device>$->name);
163         char *c;
164         for (c = $<device>$->name_underscore; *c; c++) {
165                 if (*c == '/') *c = '_';
166                 if (*c == '-') *c = '_';
167         }
168         $<device>$->type = chip;
169         $<device>$->chip = $<device>$;
170
171         struct stat st;
172         char *chip_h = malloc(strlen($<string>2)+12);
173         sprintf(chip_h, "src/%s/chip.h", $<string>2);
174         if ((stat(chip_h, &st) == -1) && (errno == ENOENT))
175                 $<device>$->chiph_exists = 0;
176
177         if (cur_parent->latestchild) {
178                 cur_parent->latestchild->next_sibling = $<device>$;
179                 cur_parent->latestchild->sibling = $<device>$;
180         }
181         cur_parent->latestchild = $<device>$;
182         if (!cur_parent->children)
183                 cur_parent->children = $<device>$;
184
185         cur_parent = $<device>$;
186 }
187         devices END {
188         cur_parent = $<device>3->parent;
189
190         fold_in($<device>3);
191
192         if ($<device>3->chiph_exists) {
193                 int include_exists = 0;
194                 struct header *h = &headers;
195                 while (h->next) {
196                         int result = strcmp($<device>3->name, h->next->name);
197                         if (result == 0) {
198                                 include_exists = 1;
199                                 break;
200                         }
201                         if (result < 0) break;
202                         h = h->next;
203                 }
204                 if (!include_exists) {
205                         struct header *tmp = h->next;
206                         h->next = malloc(sizeof(struct header));
207                         memset(h->next, 0, sizeof(struct header));
208                         h->next->name = $<device>3->name;
209                         h->next->next = tmp;
210                         break;
211                 }
212         }
213 };
214
215 device: DEVICE BUS NUMBER /* == devnum */ BOOL {
216         $<device>$ = new_dev();
217         $<device>$->bustype = $<number>2;
218
219         char *tmp;
220         $<device>$->path_a = strtol(strdup($<string>3), &tmp, 16);
221         if (*tmp == '.') {
222                 tmp++;
223                 $<device>$->path_b = strtol(tmp, NULL, 16);
224         }
225
226         char *name = malloc(10);
227         sprintf(name, "_dev%d", $<device>$->id);
228         $<device>$->name = name;
229         $<device>$->name_underscore = name; // shouldn't be necessary, but avoid 0-ptr
230         $<device>$->type = device;
231         $<device>$->enabled = $<number>4;
232         $<device>$->chip = $<device>$->parent->chip;
233
234         if (cur_parent->latestchild) {
235                 cur_parent->latestchild->next_sibling = $<device>$;
236                 cur_parent->latestchild->sibling = $<device>$;
237         }
238         cur_parent->latestchild = $<device>$;
239         if (!cur_parent->children)
240                 cur_parent->children = $<device>$;
241
242         lastdev->nextdev = $<device>$;
243         lastdev = $<device>$;
244         if ($<number>2 == PCI) {
245                 $<device>$->path = ".type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x%x,%d)}}";
246         }
247         if ($<number>2 == PNP) {
248                 $<device>$->path = ".type=DEVICE_PATH_PNP,{.pnp={ .port = 0x%x, .device = 0x%x }}";
249         }
250         if ($<number>2 == I2C) {
251                 $<device>$->path = ".type=DEVICE_PATH_I2C,{.i2c={ .device = 0x%x }}";
252         }
253         if ($<number>2 == APIC) {
254                 $<device>$->path = ".type=DEVICE_PATH_APIC,{.apic={ .apic_id = 0x%x }}";
255         }
256         if ($<number>2 == APIC_CLUSTER) {
257                 $<device>$->path = ".type=DEVICE_PATH_APIC_CLUSTER,{.apic_cluster={ .cluster = 0x%x }}";
258         }
259         if ($<number>2 == PCI_DOMAIN) {
260                 $<device>$->path = ".type=DEVICE_PATH_PCI_DOMAIN,{.pci_domain={ .domain = 0x%x }}";
261         }
262         cur_parent = $<device>$;
263         cur_bus = $<device>$;
264 }
265         devicesorresources END {
266         cur_parent = $<device>5->parent;
267         cur_bus = $<device>5->bus;
268
269         fold_in($<device>5);
270
271         struct device *d = $<device>5->children;
272         while (d) {
273                 int link = 0;
274                 struct device *cmp = d->next_sibling;
275                 while (cmp && (cmp->bus == d->bus) && (cmp->path_a == d->path_a) && (cmp->path_b == d->path_b)) {
276                         if (cmp->type==device && !cmp->used) {
277                                 if (device_match(d, cmp)) {
278                                         d->multidev = 1;
279
280                                         cmp->aliased_name = malloc(12);
281                                         sprintf(cmp->aliased_name, "_dev%d", cmp->id);
282                                         cmp->id = d->id;
283                                         cmp->name = d->name;
284                                         cmp->used = 1;
285                                         cmp->link = ++link;
286                                 }
287                         }
288                         cmp = cmp->next_sibling;
289                 }
290                 d = d->next_sibling;
291         }
292 };
293
294 resource: RESOURCE NUMBER /* == resnum */ EQUALS NUMBER /* == resval */
295         {
296                 struct resource *r = malloc(sizeof(struct resource));
297                 memset (r, 0, sizeof(struct resource));
298                 r->type = $<number>1;
299                 r->index = strtol($<string>2, NULL, 0);
300                 r->base = strtol($<string>4, NULL, 0);
301                 if (cur_parent->res) {
302                         struct resource *head = cur_parent->res;
303                         while (head->next) head = head->next;
304                         head->next = r;
305                 } else {
306                         cur_parent->res = r;
307                 }
308                 cur_parent->rescnt++;
309         }
310         ;
311
312 registers: REGISTER STRING /* == regname */ EQUALS STRING /* == regval */
313         {
314                 struct reg *r = malloc(sizeof(struct reg));
315                 memset (r, 0, sizeof(struct reg));
316                 r->key = $<string>2;
317                 r->value = $<string>4;
318                 if (cur_parent->reg) {
319                         struct reg *head = cur_parent->reg;
320                         // sorting to be equal to sconfig's behaviour
321                         int sort = strcmp(r->key, head->key);
322                         if (sort == 0) {
323                                 printf("ERROR: duplicate 'register' key.\n");
324                                 exit(1);
325                         }
326                         if (sort<0) {
327                                 r->next = head;
328                                 cur_parent->reg = r;
329                         } else {
330                                 while ((head->next) && (strcmp(head->next->key, r->key)<0)) head = head->next;
331                                 r->next = head->next;
332                                 head->next = r;
333                         }
334                 } else {
335                         cur_parent->reg = r;
336                 }
337         }
338         ;
339
340 %%
341 void pass0(FILE *fil, struct device *ptr) {
342         if ((ptr->type == device) && (ptr->id != 0) && (!ptr->used))
343                 fprintf(fil, "struct device %s;\n", ptr->name);
344         if ((ptr->type == device) && (ptr->id != 0) && ptr->used)
345                 fprintf(fil, "struct device %s;\n", ptr->aliased_name);
346 }
347
348 void pass1(FILE *fil, struct device *ptr) {
349         if (!ptr->used && (ptr->type == device)) {
350                 fprintf(fil, "struct device %s = {\n", ptr->name);
351                 fprintf(fil, "\t.ops = %s,\n", (ptr->ops)?(ptr->ops):"0");
352                 fprintf(fil, "\t.bus = &%s.link[%d],\n", ptr->bus->name, ptr->bus->link);
353                 fprintf(fil, "\t.path = {");
354                 fprintf(fil, ptr->path, ptr->path_a, ptr->path_b);
355                 fprintf(fil, "},\n");
356                 fprintf(fil, "\t.enabled = %d,\n", ptr->enabled);
357                 fprintf(fil, "\t.on_mainboard = 1,\n");
358                 if (ptr->rescnt > 0) {
359                         fprintf(fil, "\t.resources = %d,\n", ptr->rescnt);
360                         fprintf(fil, "\t.resource = {\n");
361                         struct resource *r = ptr->res;
362                         while (r) {
363                                 fprintf(fil, "\t\t{ .flags=IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_");
364                                 if (r->type == IRQ) fprintf(fil, "IRQ");
365                                 if (r->type == DRQ) fprintf(fil, "DRQ");
366                                 if (r->type == IO) fprintf(fil, "IO");
367                                 fprintf(fil, ", .index=0x%x, .base=0x%x},\n", r->index, r->base);
368                                 r = r->next;
369                         }
370                         fprintf(fil, "\t },\n");
371                 }
372                 int link = 0;
373                 fprintf(fil, "\t.link = {\n");
374                 if (ptr->multidev) {
375                         struct device *d = ptr;
376                         while (d) {
377                                 if (device_match(d, ptr)) {
378                                         fprintf(fil, "\t\t[%d] = {\n", d->link);
379                                         fprintf(fil, "\t\t\t.link = %d,\n", d->link);
380                                         fprintf(fil, "\t\t\t.dev = &%s,\n", d->name);
381                                         if (d->children)
382                                                 fprintf(fil, "\t\t\t.children = &%s,\n", d->children->name);
383                                         fprintf(fil, "\t\t},\n");
384                                         link++;
385                                 }
386                                 d = d->next_sibling;
387                         }
388                 } else {
389                         if (ptr->children) {
390                                 fprintf(fil, "\t\t[0] = {\n");
391                                 fprintf(fil, "\t\t\t.link = 0,\n");
392                                 fprintf(fil, "\t\t\t.dev = &%s,\n", ptr->name);
393                                 fprintf(fil, "\t\t\t.children = &%s,\n", ptr->children->name);
394                                 fprintf(fil, "\t\t},\n");
395                                 link++;
396                         }
397                 }
398                 fprintf(fil, "\t},\n");
399                 fprintf(fil, "\t.links = %d,\n", link);
400                 if (ptr->sibling)
401                         fprintf(fil, "\t.sibling = &%s,\n", ptr->sibling->name);
402                 if (ptr->chip->chiph_exists) {
403                         fprintf(fil, "\t.chip_ops = &%s_ops,\n", ptr->chip->name_underscore);
404                         fprintf(fil, "\t.chip_info = &%s_info_%d,\n", ptr->chip->name_underscore, ptr->chip->id);
405                 }
406                 if (ptr->nextdev)
407                         fprintf(fil, "\t.next=&%s\n", ptr->nextdev->name);
408                 fprintf(fil, "};\n");
409         }
410         if ((ptr->type == chip) && (ptr->chiph_exists)) {
411                 if (ptr->reg) {
412                         fprintf(fil, "struct %s_config %s_info_%d\t= {\n", ptr->name_underscore, ptr->name_underscore, ptr->id);
413                         struct reg *r = ptr->reg;
414                         while (r) {
415                                 fprintf(fil, "\t.%s = %s,\n", r->key, r->value);
416                                 r = r->next;
417                         }
418                         fprintf(fil, "};\n\n");
419                 } else {
420                         fprintf(fil, "struct %s_config %s_info_%d;\n", ptr->name_underscore, ptr->name_underscore, ptr->id);
421                 }
422         }
423 }
424
425 void walk_device_tree(FILE *fil, struct device *ptr, void (*func)(FILE *, struct device*), struct device *chips) {
426         do {
427                 func(fil, ptr);
428                 ptr = ptr->next_sibling;
429         } while (ptr);
430 }
431
432 struct device mainboard = {
433         .name = "mainboard",
434         .name_underscore = "mainboard",
435         .id = 0,
436         .chip = &mainboard,
437         .type = chip,
438         .chiph_exists = 1,
439         .children = &root
440 };
441
442 struct device root = {
443         .name = "dev_root",
444         .name_underscore = "dev_root",
445         .id = 0,
446         .chip = &mainboard,
447         .type = device,
448         .path = " .type = DEVICE_PATH_ROOT ",
449         .ops = "&default_dev_ops_root",
450         .parent = &root,
451         .bus = &root,
452         .enabled = 1
453 };
454
455 int main(int argc, char** argv) {
456         if (argc != 3) {
457                 printf("usage: sconfig vendor/mainboard outputdir\n");
458                 return 1;
459         }
460         char *mainboard=argv[1];
461         char *outputdir=argv[2];
462         char *devtree=malloc(strlen(mainboard)+30);
463         char *outputc=malloc(strlen(outputdir)+10);
464         sprintf(devtree, "src/mainboard/%s/devicetree.cb", mainboard);
465         sprintf(outputc, "%s/static.c", outputdir);
466
467         headers.next = malloc(sizeof(struct header));
468         headers.next->name = malloc(strlen(mainboard)+12);
469         headers.next->next = 0;
470         sprintf(headers.next->name, "mainboard/%s", mainboard);
471
472         FILE *filec = fopen(devtree, "r");
473         yyrestart(filec);
474
475         FILE *staticc = fopen(outputc, "w");
476
477         cur_bus = cur_parent = lastdev = head = &root;
478         yyparse();
479         fclose(filec);
480
481         if ((head->type == chip) && (!head->chiph_exists)) {
482                 struct device *tmp = head;
483                 head = &root;
484                 while (head->next != tmp) head = head->next;
485         }
486
487         fprintf(staticc, "#include <device/device.h>\n");
488         fprintf(staticc, "#include <device/pci.h>\n");
489         struct header *h = &headers;
490         while (h->next) {
491                 h = h->next;
492                 fprintf(staticc, "#include \"%s/chip.h\"\n", h->name);
493         }
494         fprintf(staticc, "\n/* pass 0 */\n");
495         walk_device_tree(staticc, &root, pass0, NULL);
496         fprintf(staticc, "\n/* pass 1 */\nstruct mainboard_config mainboard_info_0;\nstruct device **last_dev_p = &%s.next;\n", lastdev->name);
497         walk_device_tree(staticc, &root, pass1, NULL);
498
499         fclose(staticc);
500         return 0;
501 }