blob: 24ba0190743295708ff29c1c450df30a46787bba [file] [log] [blame]
Patrick Georgi114e7b22010-05-05 11:19:50 +00001/*
2 * sconfig, coreboot device tree compiler
3 *
4 * Copyright (C) 2010 coresystems GmbH
Stefan Reinauer2e78aa52016-05-07 01:11:14 -07005 * written by Patrick Georgi <patrick@georgi-clan.de>
Patrick Georgi114e7b22010-05-05 11:19:50 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Patrick Georgi114e7b22010-05-05 11:19:50 +000015 */
16
Patrick Georgi2dbfcb72012-05-30 16:26:30 +020017#include <ctype.h>
Patrick Georgi114e7b22010-05-05 11:19:50 +000018#include "sconfig.h"
19#include "sconfig.tab.h"
20
Patrick Georgi7fc9e292010-07-15 15:59:07 +000021extern int linenum;
22
Patrick Georgi114e7b22010-05-05 11:19:50 +000023struct device *head, *lastdev;
24
25struct header headers;
26
27static int devcount = 0;
28
Kyösti Mälkki472d9022011-12-05 20:33:55 +020029typedef enum {
30 STATIC_MODE,
31 BOOTBLOCK_MODE,
32 KCONFIG_MODE
33} scan_t;
34
35static scan_t scan_mode = STATIC_MODE;
36
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +020037typedef enum {
38 UNSLASH,
39 SPLIT_1ST,
40 TO_LOWER,
41 TO_UPPER,
42} translate_t;
43
Patrick Georgi114e7b22010-05-05 11:19:50 +000044static struct device root;
45static struct device mainboard = {
46 .name = "mainboard",
47 .name_underscore = "mainboard",
48 .id = 0,
49 .chip = &mainboard,
50 .type = chip,
Stefan Reinauer188e3c22012-07-26 12:46:48 -070051#ifdef MAINBOARDS_HAVE_CHIP_H
Patrick Georgi114e7b22010-05-05 11:19:50 +000052 .chiph_exists = 1,
Stefan Reinauer188e3c22012-07-26 12:46:48 -070053#else
54 .chiph_exists = 0,
55#endif
Patrick Georgi114e7b22010-05-05 11:19:50 +000056 .children = &root
57};
58
59static struct device root = {
60 .name = "dev_root",
61 .name_underscore = "dev_root",
62 .id = 0,
63 .chip = &mainboard,
64 .type = device,
65 .path = " .type = DEVICE_PATH_ROOT ",
66 .ops = "&default_dev_ops_root",
67 .parent = &root,
68 .bus = &root,
69 .enabled = 1
70};
71
Patrick Georgi68befd52010-05-05 12:05:25 +000072static struct device *new_dev(struct device *parent, struct device *bus) {
Patrick Georgi114e7b22010-05-05 11:19:50 +000073 struct device *dev = malloc(sizeof(struct device));
74 memset(dev, 0, sizeof(struct device));
75 dev->id = ++devcount;
Patrick Georgi68befd52010-05-05 12:05:25 +000076 dev->parent = parent;
77 dev->bus = bus;
Sven Schnelle270a9082011-03-01 19:58:15 +000078 dev->subsystem_vendor = -1;
79 dev->subsystem_device = -1;
Patrick Georgi114e7b22010-05-05 11:19:50 +000080 head->next = dev;
81 head = dev;
82 return dev;
83}
84
85static int device_match(struct device *a, struct device *b) {
86 if ((a->bustype == b->bustype) && (a->bus == b->bus) && (a->path_a == b->path_a) && (a->path_b == b->path_b))
87 return 1;
88 return 0;
89}
90
91void fold_in(struct device *parent) {
92 struct device *child = parent->children;
93 struct device *latest = 0;
94 while (child != latest) {
95 if (child->children) {
96 if (!latest) latest = child->children;
97 parent->latestchild->next_sibling = child->children;
98 parent->latestchild = child->latestchild;
99 }
100 child = child->next_sibling;
101 }
102}
103
104int yywrap(void) {
105 return 1;
106}
107
108void yyerror (char const *str)
109{
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000110 extern char *yytext;
111 fprintf (stderr, "line %d: %s: %s\n", linenum + 1, yytext, str);
112 exit(1);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000113}
114
115void postprocess_devtree(void) {
116 root.next_sibling = root.children;
117 root.next_sibling->next_sibling = root.next_sibling->children;
118
119 struct device *dev = &root;
120 while (dev) {
121 /* skip "chip" elements in children chain */
122 while (dev->children && (dev->children->type == chip)) dev->children = dev->children->children;
123 /* skip "chip" elements and functions of the same device in sibling chain */
124 while (dev->sibling && dev->sibling->used) dev->sibling = dev->sibling->sibling;
125 /* If end of chain, and parent is a chip, move on */
126 if (!dev->sibling && (dev->parent->type == chip)) dev->sibling = dev->parent->sibling;
127 /* skip chips */
128 while (dev->sibling && dev->sibling->type == chip) dev->sibling = dev->sibling->children;
129 /* skip duplicate function elements in nextdev chain */
130 while (dev->nextdev && dev->nextdev->used) dev->nextdev = dev->nextdev->nextdev;
131 dev = dev->next_sibling;
132 }
133}
134
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200135char * translate_name(const char *str, translate_t mode)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200136{
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200137 char *b, *c;
138 b = c = strdup(str);
139 while (c && *c) {
140 if ((mode == SPLIT_1ST) && (*c == '/')) {
141 *c = 0;
142 break;
143 }
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200144 if (*c == '/') *c = '_';
145 if (*c == '-') *c = '_';
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200146 if (mode == TO_UPPER)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200147 *c = toupper(*c);
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200148 if (mode == TO_LOWER)
149 *c = tolower(*c);
150 c++;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200151 }
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200152 return b;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200153}
154
Patrick Georgi68befd52010-05-05 12:05:25 +0000155struct device *new_chip(struct device *parent, struct device *bus, char *path) {
156 struct device *new_chip = new_dev(parent, bus);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000157 new_chip->chiph_exists = 1;
158 new_chip->name = path;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200159 new_chip->name_underscore = translate_name(new_chip->name, UNSLASH);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000160 new_chip->type = chip;
161 new_chip->chip = new_chip;
162
163 struct stat st;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200164 char *chip_h = malloc(strlen(path)+18);
Stefan Reinauer76c44ae2011-10-14 12:41:46 -0700165 sprintf(chip_h, "src/%s", path);
166 if ((stat(chip_h, &st) == -1) && (errno == ENOENT)) {
Patrick Georgi92bcaa22015-11-13 09:39:22 +0100167 /* root_complex gets away without a separate directory, but
168 * exists on on pretty much all AMD chipsets.
169 */
170 if (!strstr(path, "/root_complex")) {
Kyösti Mälkki6aeb4a22013-06-11 17:00:11 +0300171 fprintf(stderr, "ERROR: Chip component %s does not exist.\n",
172 path);
173 exit(1);
174 }
Stefan Reinauer76c44ae2011-10-14 12:41:46 -0700175 }
176
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200177 if (scan_mode == STATIC_MODE)
178 sprintf(chip_h, "src/%s/chip.h", path);
179 else if (scan_mode == BOOTBLOCK_MODE)
180 sprintf(chip_h, "src/%s/bootblock.c", path);
181
182 if ((scan_mode == STATIC_MODE) || (scan_mode == BOOTBLOCK_MODE)) {
183 if ((stat(chip_h, &st) == -1) && (errno == ENOENT))
184 new_chip->chiph_exists = 0;
185 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000186
Patrick Georgi68befd52010-05-05 12:05:25 +0000187 if (parent->latestchild) {
188 parent->latestchild->next_sibling = new_chip;
189 parent->latestchild->sibling = new_chip;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000190 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000191 parent->latestchild = new_chip;
192 if (!parent->children)
193 parent->children = new_chip;
Patrick Georgi1f688802014-08-03 15:51:19 +0200194 free(chip_h);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000195 return new_chip;
196}
197
198void add_header(struct device *dev) {
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200199 int include_exists = 0;
200 struct header *h = &headers;
201 while (h->next) {
202 int result = strcmp(dev->name, h->next->name);
203 if (result == 0) {
204 include_exists = 1;
205 break;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000206 }
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200207 if (result < 0) break;
208 h = h->next;
209 }
210 if (!include_exists) {
211 struct header *tmp = h->next;
212 h->next = malloc(sizeof(struct header));
213 memset(h->next, 0, sizeof(struct header));
214 h->next->chiph_exists = dev->chiph_exists;
215 h->next->name = dev->name;
216 h->next->next = tmp;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000217 }
218}
219
Patrick Georgi68befd52010-05-05 12:05:25 +0000220struct device *new_device(struct device *parent, struct device *busdev, const int bus, const char *devnum, int enabled) {
221 struct device *new_d = new_dev(parent, busdev);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000222 new_d->bustype = bus;
223
224 char *tmp;
Patrick Georgi1f688802014-08-03 15:51:19 +0200225 new_d->path_a = strtol(devnum, &tmp, 16);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000226 if (*tmp == '.') {
227 tmp++;
228 new_d->path_b = strtol(tmp, NULL, 16);
229 }
230
231 char *name = malloc(10);
232 sprintf(name, "_dev%d", new_d->id);
233 new_d->name = name;
234 new_d->name_underscore = name; // shouldn't be necessary, but avoid 0-ptr
235 new_d->type = device;
236 new_d->enabled = enabled;
237 new_d->chip = new_d->parent->chip;
238
Patrick Georgi68befd52010-05-05 12:05:25 +0000239 if (parent->latestchild) {
240 parent->latestchild->next_sibling = new_d;
241 parent->latestchild->sibling = new_d;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000242 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000243 parent->latestchild = new_d;
244 if (!parent->children)
245 parent->children = new_d;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000246
247 lastdev->nextdev = new_d;
248 lastdev = new_d;
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200249
250 switch(bus) {
251 case PCI:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000252 new_d->path = ".type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x%x,%d)}}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200253 break;
254
255 case PNP:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000256 new_d->path = ".type=DEVICE_PATH_PNP,{.pnp={ .port = 0x%x, .device = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200257 break;
258
259 case I2C:
Duncan Laurieb7ce5fe2016-05-07 19:49:37 -0700260 new_d->path = ".type=DEVICE_PATH_I2C,{.i2c={ .device = 0x%x, .mode_10bit = %d }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200261 break;
262
263 case APIC:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000264 new_d->path = ".type=DEVICE_PATH_APIC,{.apic={ .apic_id = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200265 break;
266
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800267 case CPU_CLUSTER:
268 new_d->path = ".type=DEVICE_PATH_CPU_CLUSTER,{.cpu_cluster={ .cluster = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200269 break;
270
Aaron Durbinffda804b2014-09-03 12:40:15 -0500271 case CPU:
272 new_d->path = ".type=DEVICE_PATH_CPU,{.cpu={ .id = 0x%x }}";
273 break;
274
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800275 case DOMAIN:
276 new_d->path = ".type=DEVICE_PATH_DOMAIN,{.domain={ .domain = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200277 break;
278
279 case IOAPIC:
280 new_d->path = ".type=DEVICE_PATH_IOAPIC,{.ioapic={ .ioapic_id = 0x%x }}";
281 break;
Duncan Laurie4650f5b2016-05-07 20:01:34 -0700282
283 case GENERIC:
284 new_d->path = ".type=DEVICE_PATH_GENERIC,{.generic={ .id = 0x%x, .subid = 0x%x }}";
285 break;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000286 }
287 return new_d;
288}
289
290void alias_siblings(struct device *d) {
291 while (d) {
292 int link = 0;
293 struct device *cmp = d->next_sibling;
294 while (cmp && (cmp->bus == d->bus) && (cmp->path_a == d->path_a) && (cmp->path_b == d->path_b)) {
295 if (cmp->type==device && !cmp->used) {
296 if (device_match(d, cmp)) {
297 d->multidev = 1;
298
Patrick Georgi114e7b22010-05-05 11:19:50 +0000299 cmp->id = d->id;
300 cmp->name = d->name;
301 cmp->used = 1;
302 cmp->link = ++link;
303 }
304 }
305 cmp = cmp->next_sibling;
306 }
307 d = d->next_sibling;
308 }
309}
310
Patrick Georgi68befd52010-05-05 12:05:25 +0000311void add_resource(struct device *dev, int type, int index, int base) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000312 struct resource *r = malloc(sizeof(struct resource));
313 memset (r, 0, sizeof(struct resource));
314 r->type = type;
315 r->index = index;
316 r->base = base;
Patrick Georgi68befd52010-05-05 12:05:25 +0000317 if (dev->res) {
318 struct resource *head = dev->res;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000319 while (head->next) head = head->next;
320 head->next = r;
321 } else {
Patrick Georgi68befd52010-05-05 12:05:25 +0000322 dev->res = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000323 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000324 dev->rescnt++;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000325}
326
Patrick Georgi68befd52010-05-05 12:05:25 +0000327void add_register(struct device *dev, char *name, char *val) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000328 struct reg *r = malloc(sizeof(struct reg));
329 memset (r, 0, sizeof(struct reg));
330 r->key = name;
331 r->value = val;
Patrick Georgi68befd52010-05-05 12:05:25 +0000332 if (dev->reg) {
333 struct reg *head = dev->reg;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000334 // sorting to be equal to sconfig's behaviour
335 int sort = strcmp(r->key, head->key);
336 if (sort == 0) {
337 printf("ERROR: duplicate 'register' key.\n");
338 exit(1);
339 }
340 if (sort<0) {
341 r->next = head;
Patrick Georgi68befd52010-05-05 12:05:25 +0000342 dev->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000343 } else {
344 while ((head->next) && (strcmp(head->next->key, r->key)<0)) head = head->next;
345 r->next = head->next;
346 head->next = r;
347 }
348 } else {
Patrick Georgi68befd52010-05-05 12:05:25 +0000349 dev->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000350 }
351}
352
Sven Schnelle270a9082011-03-01 19:58:15 +0000353void add_pci_subsystem_ids(struct device *dev, int vendor, int device, int inherit)
354{
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800355 if (dev->bustype != PCI && dev->bustype != DOMAIN) {
Sven Schnelle270a9082011-03-01 19:58:15 +0000356 printf("ERROR: 'subsystem' only allowed for PCI devices\n");
357 exit(1);
358 }
359
360 dev->subsystem_vendor = vendor;
361 dev->subsystem_device = device;
362 dev->inherit_subsystem = inherit;
363}
364
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200365void add_ioapic_info(struct device *dev, int apicid, const char *_srcpin, int irqpin)
366{
367
368 int srcpin;
369
370 if (!_srcpin || strlen(_srcpin) < 4 ||strncasecmp(_srcpin, "INT", 3) ||
371 _srcpin[3] < 'A' || _srcpin[3] > 'D') {
372 printf("ERROR: malformed ioapic_irq args: %s\n", _srcpin);
373 exit(1);
374 }
375
376 srcpin = _srcpin[3] - 'A';
377
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800378 if (dev->bustype != PCI && dev->bustype != DOMAIN) {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200379 printf("ERROR: ioapic config only allowed for PCI devices\n");
380 exit(1);
381 }
382
383 if (srcpin > 3) {
Patrick Georgi116327e2012-07-20 12:47:06 +0200384 printf("ERROR: srcpin '%d' invalid\n", srcpin);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200385 exit(1);
386 }
387 dev->pci_irq_info[srcpin].ioapic_irq_pin = irqpin;
388 dev->pci_irq_info[srcpin].ioapic_dst_id = apicid;
389}
390
Patrick Georgi114e7b22010-05-05 11:19:50 +0000391static void pass0(FILE *fil, struct device *ptr) {
Myles Watson894a3472010-06-09 22:41:35 +0000392 if (ptr->type == device && ptr->id == 0)
Stefan Reinauer57879c92012-07-31 16:47:25 -0700393 fprintf(fil, "ROMSTAGE_CONST struct bus %s_links[];\n", ptr->name);
394
Myles Watsonc25cc112010-05-21 14:33:48 +0000395 if ((ptr->type == device) && (ptr->id != 0) && (!ptr->used)) {
Stefan Reinauer57879c92012-07-31 16:47:25 -0700396 fprintf(fil, "ROMSTAGE_CONST static struct device %s;\n", ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000397 if (ptr->rescnt > 0)
Stefan Reinauer57879c92012-07-31 16:47:25 -0700398 fprintf(fil, "ROMSTAGE_CONST struct resource %s_res[];\n", ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000399 if (ptr->children || ptr->multidev)
Stefan Reinauer57879c92012-07-31 16:47:25 -0700400 fprintf(fil, "ROMSTAGE_CONST struct bus %s_links[];\n",
401 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000402 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000403}
404
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200405static void pass1(FILE *fil, struct device *ptr)
406{
407 int pin;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000408 if (!ptr->used && (ptr->type == device)) {
Stefan Reinauerdf61dd22010-08-09 12:02:00 +0000409 if (ptr->id != 0)
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200410 fprintf(fil, "static ");
Stefan Reinauer57879c92012-07-31 16:47:25 -0700411 fprintf(fil, "ROMSTAGE_CONST struct device %s = {\n", ptr->name);
412 fprintf(fil, "#ifndef __PRE_RAM__\n");
Patrick Georgi114e7b22010-05-05 11:19:50 +0000413 fprintf(fil, "\t.ops = %s,\n", (ptr->ops)?(ptr->ops):"0");
Stefan Reinauer57879c92012-07-31 16:47:25 -0700414 fprintf(fil, "#endif\n");
Myles Watson894a3472010-06-09 22:41:35 +0000415 fprintf(fil, "\t.bus = &%s_links[%d],\n", ptr->bus->name, ptr->bus->link);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000416 fprintf(fil, "\t.path = {");
417 fprintf(fil, ptr->path, ptr->path_a, ptr->path_b);
418 fprintf(fil, "},\n");
419 fprintf(fil, "\t.enabled = %d,\n", ptr->enabled);
420 fprintf(fil, "\t.on_mainboard = 1,\n");
Sven Schnelle270a9082011-03-01 19:58:15 +0000421 if (ptr->subsystem_vendor > 0)
422 fprintf(fil, "\t.subsystem_vendor = 0x%04x,\n", ptr->subsystem_vendor);
423
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200424 for(pin = 0; pin < 4; pin++) {
425 if (ptr->pci_irq_info[pin].ioapic_irq_pin > 0)
426 fprintf(fil, "\t.pci_irq_info[%d].ioapic_irq_pin = %d,\n", pin, ptr->pci_irq_info[pin].ioapic_irq_pin);
427
428 if (ptr->pci_irq_info[pin].ioapic_dst_id > 0)
429 fprintf(fil, "\t.pci_irq_info[%d].ioapic_dst_id = %d,\n", pin, ptr->pci_irq_info[pin].ioapic_dst_id);
430 }
431
Sven Schnelle270a9082011-03-01 19:58:15 +0000432 if (ptr->subsystem_device > 0)
433 fprintf(fil, "\t.subsystem_device = 0x%04x,\n", ptr->subsystem_device);
434
Patrick Georgi114e7b22010-05-05 11:19:50 +0000435 if (ptr->rescnt > 0) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000436 fprintf(fil, "\t.resource_list = &%s_res[0],\n", ptr->name);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000437 }
Myles Watson894a3472010-06-09 22:41:35 +0000438 if (ptr->children || ptr->multidev)
439 fprintf(fil, "\t.link_list = &%s_links[0],\n", ptr->name);
440 else
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200441 fprintf(fil, "\t.link_list = NULL,\n");
Patrick Georgi114e7b22010-05-05 11:19:50 +0000442 if (ptr->sibling)
443 fprintf(fil, "\t.sibling = &%s,\n", ptr->sibling->name);
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200444 fprintf(fil, "#ifndef __PRE_RAM__\n");
445 fprintf(fil, "\t.chip_ops = &%s_ops,\n", ptr->chip->name_underscore);
Kyösti Mälkkia93c3fe2012-10-09 22:28:56 +0300446 if (ptr->chip->chip == &mainboard)
447 fprintf(fil, "\t.name = mainboard_name,\n");
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200448 fprintf(fil, "#endif\n");
449 if (ptr->chip->chiph_exists)
Patrick Georgi114e7b22010-05-05 11:19:50 +0000450 fprintf(fil, "\t.chip_info = &%s_info_%d,\n", ptr->chip->name_underscore, ptr->chip->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000451 if (ptr->nextdev)
452 fprintf(fil, "\t.next=&%s\n", ptr->nextdev->name);
453 fprintf(fil, "};\n");
454 }
Myles Watsonc25cc112010-05-21 14:33:48 +0000455 if (ptr->rescnt > 0) {
456 int i=1;
Stefan Reinauer57879c92012-07-31 16:47:25 -0700457 fprintf(fil, "ROMSTAGE_CONST struct resource %s_res[] = {\n",
458 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000459 struct resource *r = ptr->res;
460 while (r) {
461 fprintf(fil, "\t\t{ .flags=IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_");
462 if (r->type == IRQ) fprintf(fil, "IRQ");
463 if (r->type == DRQ) fprintf(fil, "DRQ");
464 if (r->type == IO) fprintf(fil, "IO");
465 fprintf(fil, ", .index=0x%x, .base=0x%x,", r->index, r->base);
466 if (r->next)
467 fprintf(fil, ".next=&%s_res[%d]},\n", ptr->name, i++);
468 else
469 fprintf(fil, ".next=NULL },\n");
470 r = r->next;
471 }
472 fprintf(fil, "\t };\n");
473 }
Myles Watson894a3472010-06-09 22:41:35 +0000474 if (!ptr->used && ptr->type == device && (ptr->children || ptr->multidev)) {
Stefan Reinauer57879c92012-07-31 16:47:25 -0700475 fprintf(fil, "ROMSTAGE_CONST struct bus %s_links[] = {\n", ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000476 if (ptr->multidev) {
477 struct device *d = ptr;
478 while (d) {
479 if (device_match(d, ptr)) {
480 fprintf(fil, "\t\t[%d] = {\n", d->link);
481 fprintf(fil, "\t\t\t.link_num = %d,\n", d->link);
482 fprintf(fil, "\t\t\t.dev = &%s,\n", d->name);
483 if (d->children)
484 fprintf(fil, "\t\t\t.children = &%s,\n", d->children->name);
Myles Watson1965a232010-06-10 04:06:52 +0000485 if (d->next_sibling && device_match(d->next_sibling, ptr))
Myles Watson894a3472010-06-09 22:41:35 +0000486 fprintf(fil, "\t\t\t.next=&%s_links[%d],\n", d->name, d->link+1);
487 else
488 fprintf(fil, "\t\t\t.next = NULL,\n");
489 fprintf(fil, "\t\t},\n");
490 }
491 d = d->next_sibling;
492 }
493 } else {
494 if (ptr->children) {
495 fprintf(fil, "\t\t[0] = {\n");
496 fprintf(fil, "\t\t\t.link_num = 0,\n");
497 fprintf(fil, "\t\t\t.dev = &%s,\n", ptr->name);
498 fprintf(fil, "\t\t\t.children = &%s,\n", ptr->children->name);
499 fprintf(fil, "\t\t\t.next = NULL,\n");
500 fprintf(fil, "\t\t},\n");
501 }
502 }
503 fprintf(fil, "\t};\n");
504 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000505 if ((ptr->type == chip) && (ptr->chiph_exists)) {
506 if (ptr->reg) {
Patrick Georgi73586432014-01-18 16:23:32 +0100507 fprintf(fil, "ROMSTAGE_CONST struct %s_config %s_info_%d = {\n",
Stefan Reinauer57879c92012-07-31 16:47:25 -0700508 ptr->name_underscore, ptr->name_underscore,
509 ptr->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000510 struct reg *r = ptr->reg;
511 while (r) {
512 fprintf(fil, "\t.%s = %s,\n", r->key, r->value);
513 r = r->next;
514 }
515 fprintf(fil, "};\n\n");
516 } else {
Patrick Georgi73586432014-01-18 16:23:32 +0100517 fprintf(fil, "ROMSTAGE_CONST struct %s_config %s_info_%d = { };\n",
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200518 ptr->name_underscore, ptr->name_underscore, ptr->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000519 }
520 }
521}
522
523static void walk_device_tree(FILE *fil, struct device *ptr, void (*func)(FILE *, struct device*), struct device *chips) {
524 do {
525 func(fil, ptr);
526 ptr = ptr->next_sibling;
527 } while (ptr);
528}
529
Sven Schnelle270a9082011-03-01 19:58:15 +0000530static void inherit_subsystem_ids(FILE *file, struct device *dev)
531{
532 struct device *p;
Sven Schnelle270a9082011-03-01 19:58:15 +0000533
534 if (dev->subsystem_vendor != -1 && dev->subsystem_device != -1) {
535 /* user already gave us a subsystem vendor/device */
536 return;
537 }
538
Sylvain "ythier" Hitier5325a482011-03-01 21:57:11 +0000539 for(p = dev; p && p != p->parent; p = p->parent) {
Sven Schnelle270a9082011-03-01 19:58:15 +0000540
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800541 if (p->bustype != PCI && p->bustype != DOMAIN)
Sven Schnelle270a9082011-03-01 19:58:15 +0000542 continue;
543
544 if (p->inherit_subsystem) {
545 dev->subsystem_vendor = p->subsystem_vendor;
546 dev->subsystem_device = p->subsystem_device;
547 break;
548 }
549 }
550}
551
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200552static void usage(void)
553{
Martin Roth25f8a4f2016-08-05 15:46:56 -0600554 printf("usage: sconfig vendor/mainboard devicetree_file output_file [-{s|b|k}]\n");
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200555 printf("\t-s file\tcreate ramstage static device map\n");
556 printf("\t-b file\tcreate bootblock init_mainboard()\n");
557 printf("\t-k file\tcreate Kconfig devicetree section\n");
558 printf("Defaults to \"-s static.c\" if no {s|b|k} specified.\n");
559 exit (1);
560}
561
Martin Roth32051702015-11-24 12:34:16 -0700562enum {
Martin Roth25f8a4f2016-08-05 15:46:56 -0600563 MAINBOARD_ARG = 1,
Martin Roth32051702015-11-24 12:34:16 -0700564 DEVICEFILE_ARG,
Martin Roth25f8a4f2016-08-05 15:46:56 -0600565 OUTPUTFILE_ARG,
566 OUTPUTTYPE_ARG
Martin Roth32051702015-11-24 12:34:16 -0700567};
568
569#define MIN_ARGS 4
Martin Roth25f8a4f2016-08-05 15:46:56 -0600570#define MAX_ARGS 5
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200571
Patrick Georgi114e7b22010-05-05 11:19:50 +0000572int main(int argc, char** argv) {
Martin Roth32051702015-11-24 12:34:16 -0700573 if (argc != MIN_ARGS && argc != MAX_ARGS)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200574 usage();
575
Martin Roth25f8a4f2016-08-05 15:46:56 -0600576 char *mainboard = argv[MAINBOARD_ARG];
577 char *devtree = argv[DEVICEFILE_ARG];
578 char *outputc = argv[OUTPUTFILE_ARG];
Patrick Georgi114e7b22010-05-05 11:19:50 +0000579
Martin Roth32051702015-11-24 12:34:16 -0700580 if (argc == MIN_ARGS) {
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200581 scan_mode = STATIC_MODE;
Martin Roth32051702015-11-24 12:34:16 -0700582 } else if (argc == MAX_ARGS) {
583 if ((argv[OUTPUTTYPE_ARG][0] != '-') ||
584 (argv[OUTPUTTYPE_ARG][2] == 0)) {
Patrick Georgi6fa68432014-08-03 15:27:35 +0200585 usage();
586 }
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200587
Martin Roth32051702015-11-24 12:34:16 -0700588 switch (argv[OUTPUTTYPE_ARG][1]) {
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200589 case 's':
590 scan_mode = STATIC_MODE;
591 break;
592 case 'b':
593 scan_mode = BOOTBLOCK_MODE;
594 break;
595 case 'k':
596 scan_mode = KCONFIG_MODE;
597 break;
598 default:
599 usage();
600 break;
601 }
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200602 }
603
604 headers.next = 0;
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700605#ifdef MAINBOARDS_HAVE_CHIP_H
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200606 if (scan_mode == STATIC_MODE) {
607 headers.next = malloc(sizeof(struct header));
608 headers.next->name = malloc(strlen(mainboard)+12);
609 headers.next->next = 0;
610 sprintf(headers.next->name, "mainboard/%s", mainboard);
611 }
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700612#endif
Patrick Georgi114e7b22010-05-05 11:19:50 +0000613
614 FILE *filec = fopen(devtree, "r");
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000615 if (!filec) {
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000616 perror(NULL);
617 exit(1);
618 }
619
Patrick Georgi114e7b22010-05-05 11:19:50 +0000620 yyrestart(filec);
621
Patrick Georgi68befd52010-05-05 12:05:25 +0000622 lastdev = head = &root;
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000623
Patrick Georgi114e7b22010-05-05 11:19:50 +0000624 yyparse();
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000625
Patrick Georgi114e7b22010-05-05 11:19:50 +0000626 fclose(filec);
627
628 if ((head->type == chip) && (!head->chiph_exists)) {
629 struct device *tmp = head;
630 head = &root;
631 while (head->next != tmp) head = head->next;
632 }
633
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200634 FILE *autogen = fopen(outputc, "w");
635 if (!autogen) {
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000636 fprintf(stderr, "Could not open file '%s' for writing: ", outputc);
637 perror(NULL);
638 exit(1);
639 }
640
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200641 struct header *h;
642 if (scan_mode == STATIC_MODE) {
643
644 fprintf(autogen, "#include <device/device.h>\n");
645 fprintf(autogen, "#include <device/pci.h>\n");
646 h = &headers;
647 while (h->next) {
648 h = h->next;
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200649 if (h->chiph_exists)
650 fprintf(autogen, "#include \"%s/chip.h\"\n", h->name);
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200651 }
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200652 fprintf(autogen, "\n#ifndef __PRE_RAM__\n");
Kyösti Mälkkie773c922012-11-15 07:05:43 +0200653 fprintf(autogen, "__attribute__((weak)) struct chip_operations mainboard_ops = {};\n");
Kyösti Mälkkifee73df2012-08-21 11:37:11 +0300654 h = &headers;
655 while (h->next) {
656 h = h->next;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200657 char *name_underscore = translate_name(h->name, UNSLASH);
Patrick Georgib6f765e2012-10-07 22:04:52 +0200658 fprintf(autogen, "__attribute__((weak)) struct chip_operations %s_ops = {};\n", name_underscore);
Kyösti Mälkkifee73df2012-08-21 11:37:11 +0300659 free(name_underscore);
660 }
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200661 fprintf(autogen, "#endif\n");
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200662
663 walk_device_tree(autogen, &root, inherit_subsystem_ids, NULL);
664 fprintf(autogen, "\n/* pass 0 */\n");
665 walk_device_tree(autogen, &root, pass0, NULL);
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700666 fprintf(autogen, "\n/* pass 1 */\n"
Stefan Reinauer57879c92012-07-31 16:47:25 -0700667 "ROMSTAGE_CONST struct device * ROMSTAGE_CONST last_dev = &%s;\n", lastdev->name);
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700668#ifdef MAINBOARDS_HAVE_CHIP_H
Stefan Reinauer57879c92012-07-31 16:47:25 -0700669 fprintf(autogen, "static ROMSTAGE_CONST struct mainboard_config ROMSTAGE_CONST mainboard_info_0;\n");
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700670#endif
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200671 walk_device_tree(autogen, &root, pass1, NULL);
672
673 } else if (scan_mode == BOOTBLOCK_MODE) {
674 h = &headers;
675 while (h->next) {
676 h = h->next;
677 fprintf(autogen, "#include \"%s/bootblock.c\"\n", h->name);
678 }
679
680 fprintf(autogen, "\n#if CONFIG_HAS_MAINBOARD_BOOTBLOCK\n");
681 fprintf(autogen, "#include \"mainboard/%s/bootblock.c\"\n", mainboard);
682 fprintf(autogen, "#else\n");
683 fprintf(autogen, "static unsigned long init_mainboard(int bsp_cpu)\n{\n");
684 fprintf(autogen, "\tif (! bsp_cpu) return 0;\n");
685 h = &headers;
686 while (h->next) {
687 h = h->next;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200688 char * buf = translate_name(h->name, UNSLASH);
689 if (buf) {
690 fprintf(autogen, "\tinit_%s();\n", buf);
691 free(buf);
692 }
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200693 }
694
695 fprintf(autogen, "\treturn 0;\n}\n");
696 fprintf(autogen, "#endif\n");
697
698 } else if (scan_mode == KCONFIG_MODE) {
699 fprintf(autogen, "\nconfig MAINBOARD_DIR\n\tstring\n");
700 fprintf(autogen, "\tdefault %s\n", mainboard);
701
702 fprintf(autogen, "\nconfig MAINBOARD_DEVTREE\n\tdef_bool y\n");
703 h = &headers;
704 while (h->next) {
705 h = h->next;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200706 char * buf = translate_name(h->name, TO_UPPER);
707 if (buf) {
708 fprintf(autogen, "\tselect %s\n", buf);
709 free(buf);
710 }
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200711 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000712 }
Sven Schnelle270a9082011-03-01 19:58:15 +0000713
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200714 fclose(autogen);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000715
Patrick Georgi114e7b22010-05-05 11:19:50 +0000716 return 0;
717}