blob: 43b083e92b47ceec6ec0187114b598b149945ab9 [file] [log] [blame]
Patrick Georgi114e7b22010-05-05 11:19:50 +00001/*
2 * sconfig, coreboot device tree compiler
3 *
4 * Copyright (C) 2010 coresystems GmbH
5 * written by Patrick Georgi <patrick.georgi@coresystems.de>
6 *
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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
19 */
20
Patrick Georgi2dbfcb72012-05-30 16:26:30 +020021#include <ctype.h>
Patrick Georgi114e7b22010-05-05 11:19:50 +000022#include "sconfig.h"
23#include "sconfig.tab.h"
24
Patrick Georgi7fc9e292010-07-15 15:59:07 +000025extern int linenum;
26
Patrick Georgi114e7b22010-05-05 11:19:50 +000027struct device *head, *lastdev;
28
29struct header headers;
30
31static int devcount = 0;
32
Kyösti Mälkki472d9022011-12-05 20:33:55 +020033typedef enum {
34 STATIC_MODE,
35 BOOTBLOCK_MODE,
36 KCONFIG_MODE
37} scan_t;
38
39static scan_t scan_mode = STATIC_MODE;
40
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +020041typedef enum {
42 UNSLASH,
43 SPLIT_1ST,
44 TO_LOWER,
45 TO_UPPER,
46} translate_t;
47
Patrick Georgi114e7b22010-05-05 11:19:50 +000048static struct device root;
49static struct device mainboard = {
50 .name = "mainboard",
51 .name_underscore = "mainboard",
52 .id = 0,
53 .chip = &mainboard,
54 .type = chip,
Stefan Reinauer188e3c22012-07-26 12:46:48 -070055#ifdef MAINBOARDS_HAVE_CHIP_H
Patrick Georgi114e7b22010-05-05 11:19:50 +000056 .chiph_exists = 1,
Stefan Reinauer188e3c22012-07-26 12:46:48 -070057#else
58 .chiph_exists = 0,
59#endif
Patrick Georgi114e7b22010-05-05 11:19:50 +000060 .children = &root
61};
62
63static struct device root = {
64 .name = "dev_root",
65 .name_underscore = "dev_root",
66 .id = 0,
67 .chip = &mainboard,
68 .type = device,
69 .path = " .type = DEVICE_PATH_ROOT ",
70 .ops = "&default_dev_ops_root",
71 .parent = &root,
72 .bus = &root,
73 .enabled = 1
74};
75
Patrick Georgi68befd52010-05-05 12:05:25 +000076static struct device *new_dev(struct device *parent, struct device *bus) {
Patrick Georgi114e7b22010-05-05 11:19:50 +000077 struct device *dev = malloc(sizeof(struct device));
78 memset(dev, 0, sizeof(struct device));
79 dev->id = ++devcount;
Patrick Georgi68befd52010-05-05 12:05:25 +000080 dev->parent = parent;
81 dev->bus = bus;
Sven Schnelle270a9082011-03-01 19:58:15 +000082 dev->subsystem_vendor = -1;
83 dev->subsystem_device = -1;
Patrick Georgi114e7b22010-05-05 11:19:50 +000084 head->next = dev;
85 head = dev;
86 return dev;
87}
88
89static int device_match(struct device *a, struct device *b) {
90 if ((a->bustype == b->bustype) && (a->bus == b->bus) && (a->path_a == b->path_a) && (a->path_b == b->path_b))
91 return 1;
92 return 0;
93}
94
95void fold_in(struct device *parent) {
96 struct device *child = parent->children;
97 struct device *latest = 0;
98 while (child != latest) {
99 if (child->children) {
100 if (!latest) latest = child->children;
101 parent->latestchild->next_sibling = child->children;
102 parent->latestchild = child->latestchild;
103 }
104 child = child->next_sibling;
105 }
106}
107
108int yywrap(void) {
109 return 1;
110}
111
112void yyerror (char const *str)
113{
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000114 extern char *yytext;
115 fprintf (stderr, "line %d: %s: %s\n", linenum + 1, yytext, str);
116 exit(1);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000117}
118
119void postprocess_devtree(void) {
120 root.next_sibling = root.children;
121 root.next_sibling->next_sibling = root.next_sibling->children;
122
123 struct device *dev = &root;
124 while (dev) {
125 /* skip "chip" elements in children chain */
126 while (dev->children && (dev->children->type == chip)) dev->children = dev->children->children;
127 /* skip "chip" elements and functions of the same device in sibling chain */
128 while (dev->sibling && dev->sibling->used) dev->sibling = dev->sibling->sibling;
129 /* If end of chain, and parent is a chip, move on */
130 if (!dev->sibling && (dev->parent->type == chip)) dev->sibling = dev->parent->sibling;
131 /* skip chips */
132 while (dev->sibling && dev->sibling->type == chip) dev->sibling = dev->sibling->children;
133 /* skip duplicate function elements in nextdev chain */
134 while (dev->nextdev && dev->nextdev->used) dev->nextdev = dev->nextdev->nextdev;
135 dev = dev->next_sibling;
136 }
137}
138
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200139char * translate_name(const char *str, translate_t mode)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200140{
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200141 char *b, *c;
142 b = c = strdup(str);
143 while (c && *c) {
144 if ((mode == SPLIT_1ST) && (*c == '/')) {
145 *c = 0;
146 break;
147 }
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200148 if (*c == '/') *c = '_';
149 if (*c == '-') *c = '_';
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200150 if (mode == TO_UPPER)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200151 *c = toupper(*c);
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200152 if (mode == TO_LOWER)
153 *c = tolower(*c);
154 c++;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200155 }
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200156 return b;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200157}
158
Patrick Georgi68befd52010-05-05 12:05:25 +0000159struct device *new_chip(struct device *parent, struct device *bus, char *path) {
160 struct device *new_chip = new_dev(parent, bus);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000161 new_chip->chiph_exists = 1;
162 new_chip->name = path;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200163 new_chip->name_underscore = translate_name(new_chip->name, UNSLASH);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000164 new_chip->type = chip;
165 new_chip->chip = new_chip;
166
167 struct stat st;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200168 char *chip_h = malloc(strlen(path)+18);
Stefan Reinauer76c44ae2011-10-14 12:41:46 -0700169 sprintf(chip_h, "src/%s", path);
170 if ((stat(chip_h, &st) == -1) && (errno == ENOENT)) {
171 fprintf(stderr, "ERROR: Chip component %s does not exist.\n",
172 path);
173 exit(1);
174 }
175
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200176 if (scan_mode == STATIC_MODE)
177 sprintf(chip_h, "src/%s/chip.h", path);
178 else if (scan_mode == BOOTBLOCK_MODE)
179 sprintf(chip_h, "src/%s/bootblock.c", path);
180
181 if ((scan_mode == STATIC_MODE) || (scan_mode == BOOTBLOCK_MODE)) {
182 if ((stat(chip_h, &st) == -1) && (errno == ENOENT))
183 new_chip->chiph_exists = 0;
184 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000185
Patrick Georgi68befd52010-05-05 12:05:25 +0000186 if (parent->latestchild) {
187 parent->latestchild->next_sibling = new_chip;
188 parent->latestchild->sibling = new_chip;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000189 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000190 parent->latestchild = new_chip;
191 if (!parent->children)
192 parent->children = new_chip;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000193 return new_chip;
194}
195
196void add_header(struct device *dev) {
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200197 int include_exists = 0;
198 struct header *h = &headers;
199 while (h->next) {
200 int result = strcmp(dev->name, h->next->name);
201 if (result == 0) {
202 include_exists = 1;
203 break;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000204 }
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200205 if (result < 0) break;
206 h = h->next;
207 }
208 if (!include_exists) {
209 struct header *tmp = h->next;
210 h->next = malloc(sizeof(struct header));
211 memset(h->next, 0, sizeof(struct header));
212 h->next->chiph_exists = dev->chiph_exists;
213 h->next->name = dev->name;
214 h->next->next = tmp;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000215 }
216}
217
Patrick Georgi68befd52010-05-05 12:05:25 +0000218struct device *new_device(struct device *parent, struct device *busdev, const int bus, const char *devnum, int enabled) {
219 struct device *new_d = new_dev(parent, busdev);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000220 new_d->bustype = bus;
221
222 char *tmp;
223 new_d->path_a = strtol(strdup(devnum), &tmp, 16);
224 if (*tmp == '.') {
225 tmp++;
226 new_d->path_b = strtol(tmp, NULL, 16);
227 }
228
229 char *name = malloc(10);
230 sprintf(name, "_dev%d", new_d->id);
231 new_d->name = name;
232 new_d->name_underscore = name; // shouldn't be necessary, but avoid 0-ptr
233 new_d->type = device;
234 new_d->enabled = enabled;
235 new_d->chip = new_d->parent->chip;
236
Patrick Georgi68befd52010-05-05 12:05:25 +0000237 if (parent->latestchild) {
238 parent->latestchild->next_sibling = new_d;
239 parent->latestchild->sibling = new_d;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000240 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000241 parent->latestchild = new_d;
242 if (!parent->children)
243 parent->children = new_d;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000244
245 lastdev->nextdev = new_d;
246 lastdev = new_d;
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200247
248 switch(bus) {
249 case PCI:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000250 new_d->path = ".type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x%x,%d)}}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200251 break;
252
253 case PNP:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000254 new_d->path = ".type=DEVICE_PATH_PNP,{.pnp={ .port = 0x%x, .device = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200255 break;
256
257 case I2C:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000258 new_d->path = ".type=DEVICE_PATH_I2C,{.i2c={ .device = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200259 break;
260
261 case APIC:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000262 new_d->path = ".type=DEVICE_PATH_APIC,{.apic={ .apic_id = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200263 break;
264
265 case APIC_CLUSTER:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000266 new_d->path = ".type=DEVICE_PATH_APIC_CLUSTER,{.apic_cluster={ .cluster = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200267 break;
268
269 case PCI_DOMAIN:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000270 new_d->path = ".type=DEVICE_PATH_PCI_DOMAIN,{.pci_domain={ .domain = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200271 break;
272
273 case IOAPIC:
274 new_d->path = ".type=DEVICE_PATH_IOAPIC,{.ioapic={ .ioapic_id = 0x%x }}";
275 break;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000276 }
277 return new_d;
278}
279
280void alias_siblings(struct device *d) {
281 while (d) {
282 int link = 0;
283 struct device *cmp = d->next_sibling;
284 while (cmp && (cmp->bus == d->bus) && (cmp->path_a == d->path_a) && (cmp->path_b == d->path_b)) {
285 if (cmp->type==device && !cmp->used) {
286 if (device_match(d, cmp)) {
287 d->multidev = 1;
288
Patrick Georgi114e7b22010-05-05 11:19:50 +0000289 cmp->id = d->id;
290 cmp->name = d->name;
291 cmp->used = 1;
292 cmp->link = ++link;
293 }
294 }
295 cmp = cmp->next_sibling;
296 }
297 d = d->next_sibling;
298 }
299}
300
Patrick Georgi68befd52010-05-05 12:05:25 +0000301void add_resource(struct device *dev, int type, int index, int base) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000302 struct resource *r = malloc(sizeof(struct resource));
303 memset (r, 0, sizeof(struct resource));
304 r->type = type;
305 r->index = index;
306 r->base = base;
Patrick Georgi68befd52010-05-05 12:05:25 +0000307 if (dev->res) {
308 struct resource *head = dev->res;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000309 while (head->next) head = head->next;
310 head->next = r;
311 } else {
Patrick Georgi68befd52010-05-05 12:05:25 +0000312 dev->res = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000313 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000314 dev->rescnt++;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000315}
316
Patrick Georgi68befd52010-05-05 12:05:25 +0000317void add_register(struct device *dev, char *name, char *val) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000318 struct reg *r = malloc(sizeof(struct reg));
319 memset (r, 0, sizeof(struct reg));
320 r->key = name;
321 r->value = val;
Patrick Georgi68befd52010-05-05 12:05:25 +0000322 if (dev->reg) {
323 struct reg *head = dev->reg;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000324 // sorting to be equal to sconfig's behaviour
325 int sort = strcmp(r->key, head->key);
326 if (sort == 0) {
327 printf("ERROR: duplicate 'register' key.\n");
328 exit(1);
329 }
330 if (sort<0) {
331 r->next = head;
Patrick Georgi68befd52010-05-05 12:05:25 +0000332 dev->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000333 } else {
334 while ((head->next) && (strcmp(head->next->key, r->key)<0)) head = head->next;
335 r->next = head->next;
336 head->next = r;
337 }
338 } else {
Patrick Georgi68befd52010-05-05 12:05:25 +0000339 dev->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000340 }
341}
342
Sven Schnelle270a9082011-03-01 19:58:15 +0000343void add_pci_subsystem_ids(struct device *dev, int vendor, int device, int inherit)
344{
345 if (dev->bustype != PCI && dev->bustype != PCI_DOMAIN) {
346 printf("ERROR: 'subsystem' only allowed for PCI devices\n");
347 exit(1);
348 }
349
350 dev->subsystem_vendor = vendor;
351 dev->subsystem_device = device;
352 dev->inherit_subsystem = inherit;
353}
354
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200355void add_ioapic_info(struct device *dev, int apicid, const char *_srcpin, int irqpin)
356{
357
358 int srcpin;
359
360 if (!_srcpin || strlen(_srcpin) < 4 ||strncasecmp(_srcpin, "INT", 3) ||
361 _srcpin[3] < 'A' || _srcpin[3] > 'D') {
362 printf("ERROR: malformed ioapic_irq args: %s\n", _srcpin);
363 exit(1);
364 }
365
366 srcpin = _srcpin[3] - 'A';
367
368 if (dev->bustype != PCI && dev->bustype != PCI_DOMAIN) {
369 printf("ERROR: ioapic config only allowed for PCI devices\n");
370 exit(1);
371 }
372
373 if (srcpin > 3) {
Patrick Georgi116327e2012-07-20 12:47:06 +0200374 printf("ERROR: srcpin '%d' invalid\n", srcpin);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200375 exit(1);
376 }
377 dev->pci_irq_info[srcpin].ioapic_irq_pin = irqpin;
378 dev->pci_irq_info[srcpin].ioapic_dst_id = apicid;
379}
380
Patrick Georgi114e7b22010-05-05 11:19:50 +0000381static void pass0(FILE *fil, struct device *ptr) {
Myles Watson894a3472010-06-09 22:41:35 +0000382 if (ptr->type == device && ptr->id == 0)
Stefan Reinauer57879c92012-07-31 16:47:25 -0700383 fprintf(fil, "ROMSTAGE_CONST struct bus %s_links[];\n", ptr->name);
384
Myles Watsonc25cc112010-05-21 14:33:48 +0000385 if ((ptr->type == device) && (ptr->id != 0) && (!ptr->used)) {
Stefan Reinauer57879c92012-07-31 16:47:25 -0700386 fprintf(fil, "ROMSTAGE_CONST static struct device %s;\n", ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000387 if (ptr->rescnt > 0)
Stefan Reinauer57879c92012-07-31 16:47:25 -0700388 fprintf(fil, "ROMSTAGE_CONST struct resource %s_res[];\n", ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000389 if (ptr->children || ptr->multidev)
Stefan Reinauer57879c92012-07-31 16:47:25 -0700390 fprintf(fil, "ROMSTAGE_CONST struct bus %s_links[];\n",
391 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000392 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000393}
394
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200395static void pass1(FILE *fil, struct device *ptr)
396{
397 int pin;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000398 if (!ptr->used && (ptr->type == device)) {
Stefan Reinauerdf61dd22010-08-09 12:02:00 +0000399 if (ptr->id != 0)
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200400 fprintf(fil, "static ");
Stefan Reinauer57879c92012-07-31 16:47:25 -0700401 fprintf(fil, "ROMSTAGE_CONST struct device %s = {\n", ptr->name);
402 fprintf(fil, "#ifndef __PRE_RAM__\n");
Patrick Georgi114e7b22010-05-05 11:19:50 +0000403 fprintf(fil, "\t.ops = %s,\n", (ptr->ops)?(ptr->ops):"0");
Stefan Reinauer57879c92012-07-31 16:47:25 -0700404 fprintf(fil, "#endif\n");
Myles Watson894a3472010-06-09 22:41:35 +0000405 fprintf(fil, "\t.bus = &%s_links[%d],\n", ptr->bus->name, ptr->bus->link);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000406 fprintf(fil, "\t.path = {");
407 fprintf(fil, ptr->path, ptr->path_a, ptr->path_b);
408 fprintf(fil, "},\n");
409 fprintf(fil, "\t.enabled = %d,\n", ptr->enabled);
410 fprintf(fil, "\t.on_mainboard = 1,\n");
Sven Schnelle270a9082011-03-01 19:58:15 +0000411 if (ptr->subsystem_vendor > 0)
412 fprintf(fil, "\t.subsystem_vendor = 0x%04x,\n", ptr->subsystem_vendor);
413
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200414 for(pin = 0; pin < 4; pin++) {
415 if (ptr->pci_irq_info[pin].ioapic_irq_pin > 0)
416 fprintf(fil, "\t.pci_irq_info[%d].ioapic_irq_pin = %d,\n", pin, ptr->pci_irq_info[pin].ioapic_irq_pin);
417
418 if (ptr->pci_irq_info[pin].ioapic_dst_id > 0)
419 fprintf(fil, "\t.pci_irq_info[%d].ioapic_dst_id = %d,\n", pin, ptr->pci_irq_info[pin].ioapic_dst_id);
420 }
421
Sven Schnelle270a9082011-03-01 19:58:15 +0000422 if (ptr->subsystem_device > 0)
423 fprintf(fil, "\t.subsystem_device = 0x%04x,\n", ptr->subsystem_device);
424
Patrick Georgi114e7b22010-05-05 11:19:50 +0000425 if (ptr->rescnt > 0) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000426 fprintf(fil, "\t.resource_list = &%s_res[0],\n", ptr->name);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000427 }
428 int link = 0;
Myles Watson894a3472010-06-09 22:41:35 +0000429 if (ptr->children || ptr->multidev)
430 fprintf(fil, "\t.link_list = &%s_links[0],\n", ptr->name);
431 else
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200432 fprintf(fil, "\t.link_list = NULL,\n");
Patrick Georgi114e7b22010-05-05 11:19:50 +0000433 if (ptr->sibling)
434 fprintf(fil, "\t.sibling = &%s,\n", ptr->sibling->name);
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200435 fprintf(fil, "#ifndef __PRE_RAM__\n");
436 fprintf(fil, "\t.chip_ops = &%s_ops,\n", ptr->chip->name_underscore);
Kyösti Mälkkia93c3fe2012-10-09 22:28:56 +0300437 if (ptr->chip->chip == &mainboard)
438 fprintf(fil, "\t.name = mainboard_name,\n");
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200439 fprintf(fil, "#endif\n");
440 if (ptr->chip->chiph_exists)
Patrick Georgi114e7b22010-05-05 11:19:50 +0000441 fprintf(fil, "\t.chip_info = &%s_info_%d,\n", ptr->chip->name_underscore, ptr->chip->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000442 if (ptr->nextdev)
443 fprintf(fil, "\t.next=&%s\n", ptr->nextdev->name);
444 fprintf(fil, "};\n");
445 }
Myles Watsonc25cc112010-05-21 14:33:48 +0000446 if (ptr->rescnt > 0) {
447 int i=1;
Stefan Reinauer57879c92012-07-31 16:47:25 -0700448 fprintf(fil, "ROMSTAGE_CONST struct resource %s_res[] = {\n",
449 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000450 struct resource *r = ptr->res;
451 while (r) {
452 fprintf(fil, "\t\t{ .flags=IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_");
453 if (r->type == IRQ) fprintf(fil, "IRQ");
454 if (r->type == DRQ) fprintf(fil, "DRQ");
455 if (r->type == IO) fprintf(fil, "IO");
456 fprintf(fil, ", .index=0x%x, .base=0x%x,", r->index, r->base);
457 if (r->next)
458 fprintf(fil, ".next=&%s_res[%d]},\n", ptr->name, i++);
459 else
460 fprintf(fil, ".next=NULL },\n");
461 r = r->next;
462 }
463 fprintf(fil, "\t };\n");
464 }
Myles Watson894a3472010-06-09 22:41:35 +0000465 if (!ptr->used && ptr->type == device && (ptr->children || ptr->multidev)) {
Stefan Reinauer57879c92012-07-31 16:47:25 -0700466 fprintf(fil, "ROMSTAGE_CONST struct bus %s_links[] = {\n", ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000467 if (ptr->multidev) {
468 struct device *d = ptr;
469 while (d) {
470 if (device_match(d, ptr)) {
471 fprintf(fil, "\t\t[%d] = {\n", d->link);
472 fprintf(fil, "\t\t\t.link_num = %d,\n", d->link);
473 fprintf(fil, "\t\t\t.dev = &%s,\n", d->name);
474 if (d->children)
475 fprintf(fil, "\t\t\t.children = &%s,\n", d->children->name);
Myles Watson1965a232010-06-10 04:06:52 +0000476 if (d->next_sibling && device_match(d->next_sibling, ptr))
Myles Watson894a3472010-06-09 22:41:35 +0000477 fprintf(fil, "\t\t\t.next=&%s_links[%d],\n", d->name, d->link+1);
478 else
479 fprintf(fil, "\t\t\t.next = NULL,\n");
480 fprintf(fil, "\t\t},\n");
481 }
482 d = d->next_sibling;
483 }
484 } else {
485 if (ptr->children) {
486 fprintf(fil, "\t\t[0] = {\n");
487 fprintf(fil, "\t\t\t.link_num = 0,\n");
488 fprintf(fil, "\t\t\t.dev = &%s,\n", ptr->name);
489 fprintf(fil, "\t\t\t.children = &%s,\n", ptr->children->name);
490 fprintf(fil, "\t\t\t.next = NULL,\n");
491 fprintf(fil, "\t\t},\n");
492 }
493 }
494 fprintf(fil, "\t};\n");
495 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000496 if ((ptr->type == chip) && (ptr->chiph_exists)) {
497 if (ptr->reg) {
Stefan Reinauer57879c92012-07-31 16:47:25 -0700498 fprintf(fil, "ROMSTAGE_CONST struct %s_config ROMSTAGE_CONST %s_info_%d = {\n",
499 ptr->name_underscore, ptr->name_underscore,
500 ptr->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000501 struct reg *r = ptr->reg;
502 while (r) {
503 fprintf(fil, "\t.%s = %s,\n", r->key, r->value);
504 r = r->next;
505 }
506 fprintf(fil, "};\n\n");
507 } else {
Stefan Reinauer57879c92012-07-31 16:47:25 -0700508 fprintf(fil, "ROMSTAGE_CONST struct %s_config ROMSTAGE_CONST %s_info_%d = { };\n",
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200509 ptr->name_underscore, ptr->name_underscore, ptr->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000510 }
511 }
512}
513
514static void walk_device_tree(FILE *fil, struct device *ptr, void (*func)(FILE *, struct device*), struct device *chips) {
515 do {
516 func(fil, ptr);
517 ptr = ptr->next_sibling;
518 } while (ptr);
519}
520
Sven Schnelle270a9082011-03-01 19:58:15 +0000521static void inherit_subsystem_ids(FILE *file, struct device *dev)
522{
523 struct device *p;
Sven Schnelle270a9082011-03-01 19:58:15 +0000524
525 if (dev->subsystem_vendor != -1 && dev->subsystem_device != -1) {
526 /* user already gave us a subsystem vendor/device */
527 return;
528 }
529
Sylvain "ythier" Hitier5325a482011-03-01 21:57:11 +0000530 for(p = dev; p && p != p->parent; p = p->parent) {
Sven Schnelle270a9082011-03-01 19:58:15 +0000531
532 if (p->bustype != PCI && p->bustype != PCI_DOMAIN)
533 continue;
534
535 if (p->inherit_subsystem) {
536 dev->subsystem_vendor = p->subsystem_vendor;
537 dev->subsystem_device = p->subsystem_device;
538 break;
539 }
540 }
541}
542
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200543static void usage(void)
544{
545 printf("usage: sconfig vendor/mainboard outputdir [-{s|b|k} outputfile]\n");
546 printf("\t-s file\tcreate ramstage static device map\n");
547 printf("\t-b file\tcreate bootblock init_mainboard()\n");
548 printf("\t-k file\tcreate Kconfig devicetree section\n");
549 printf("Defaults to \"-s static.c\" if no {s|b|k} specified.\n");
550 exit (1);
551}
552
553
Patrick Georgi114e7b22010-05-05 11:19:50 +0000554int main(int argc, char** argv) {
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200555 if (argc < 3)
556 usage();
557
Patrick Georgi114e7b22010-05-05 11:19:50 +0000558 char *mainboard=argv[1];
559 char *outputdir=argv[2];
560 char *devtree=malloc(strlen(mainboard)+30);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000561 sprintf(devtree, "src/mainboard/%s/devicetree.cb", mainboard);
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200562 char *outputc;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000563
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200564 if (argc == 3) {
565 scan_mode = STATIC_MODE;
566 outputc=malloc(strlen(outputdir)+20);
567 sprintf(outputc, "%s/static.c", outputdir);
568 } else if ((argc == 5) && (argv[3][0] == '-') && (argv[3][2] == 0)) {
569
570 switch (argv[3][1]) {
571 case 's':
572 scan_mode = STATIC_MODE;
573 break;
574 case 'b':
575 scan_mode = BOOTBLOCK_MODE;
576 break;
577 case 'k':
578 scan_mode = KCONFIG_MODE;
579 break;
580 default:
581 usage();
582 break;
583 }
584 char *outputfile=argv[4];
585
586 outputc=malloc(strlen(outputdir)+strlen(outputfile)+2);
587 sprintf(outputc, "%s/%s", outputdir, outputfile);
588 }
589
590 headers.next = 0;
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700591#ifdef MAINBOARDS_HAVE_CHIP_H
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200592 if (scan_mode == STATIC_MODE) {
593 headers.next = malloc(sizeof(struct header));
594 headers.next->name = malloc(strlen(mainboard)+12);
595 headers.next->next = 0;
596 sprintf(headers.next->name, "mainboard/%s", mainboard);
597 }
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700598#endif
Patrick Georgi114e7b22010-05-05 11:19:50 +0000599
600 FILE *filec = fopen(devtree, "r");
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000601 if (!filec) {
602 fprintf(stderr, "Could not open file '%s' for reading: ", devtree);
603 perror(NULL);
604 exit(1);
605 }
606
Patrick Georgi114e7b22010-05-05 11:19:50 +0000607 yyrestart(filec);
608
Patrick Georgi68befd52010-05-05 12:05:25 +0000609 lastdev = head = &root;
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000610
Patrick Georgi114e7b22010-05-05 11:19:50 +0000611 yyparse();
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000612
Patrick Georgi114e7b22010-05-05 11:19:50 +0000613 fclose(filec);
614
615 if ((head->type == chip) && (!head->chiph_exists)) {
616 struct device *tmp = head;
617 head = &root;
618 while (head->next != tmp) head = head->next;
619 }
620
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200621 FILE *autogen = fopen(outputc, "w");
622 if (!autogen) {
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000623 fprintf(stderr, "Could not open file '%s' for writing: ", outputc);
624 perror(NULL);
625 exit(1);
626 }
627
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200628 struct header *h;
629 if (scan_mode == STATIC_MODE) {
630
631 fprintf(autogen, "#include <device/device.h>\n");
632 fprintf(autogen, "#include <device/pci.h>\n");
633 h = &headers;
634 while (h->next) {
635 h = h->next;
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200636 if (h->chiph_exists)
637 fprintf(autogen, "#include \"%s/chip.h\"\n", h->name);
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200638 }
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200639 fprintf(autogen, "\n#ifndef __PRE_RAM__\n");
Kyösti Mälkkifee73df2012-08-21 11:37:11 +0300640 h = &headers;
641 while (h->next) {
642 h = h->next;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200643 char *name_underscore = translate_name(h->name, UNSLASH);
Kyösti Mälkkifee73df2012-08-21 11:37:11 +0300644 fprintf(autogen, "extern struct chip_operations %s_ops;\n", name_underscore);
645 free(name_underscore);
646 }
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200647 fprintf(autogen, "#endif\n");
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200648
649 walk_device_tree(autogen, &root, inherit_subsystem_ids, NULL);
650 fprintf(autogen, "\n/* pass 0 */\n");
651 walk_device_tree(autogen, &root, pass0, NULL);
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700652 fprintf(autogen, "\n/* pass 1 */\n"
Stefan Reinauer57879c92012-07-31 16:47:25 -0700653 "ROMSTAGE_CONST struct device * ROMSTAGE_CONST last_dev = &%s;\n", lastdev->name);
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700654#ifdef MAINBOARDS_HAVE_CHIP_H
Stefan Reinauer57879c92012-07-31 16:47:25 -0700655 fprintf(autogen, "static ROMSTAGE_CONST struct mainboard_config ROMSTAGE_CONST mainboard_info_0;\n");
Stefan Reinauera675d492012-08-07 14:50:47 -0700656#else
657 fprintf(autogen, "extern struct chip_operations mainboard_ops;\n");
Stefan Reinauer188e3c22012-07-26 12:46:48 -0700658#endif
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200659 walk_device_tree(autogen, &root, pass1, NULL);
660
661 } else if (scan_mode == BOOTBLOCK_MODE) {
662 h = &headers;
663 while (h->next) {
664 h = h->next;
665 fprintf(autogen, "#include \"%s/bootblock.c\"\n", h->name);
666 }
667
668 fprintf(autogen, "\n#if CONFIG_HAS_MAINBOARD_BOOTBLOCK\n");
669 fprintf(autogen, "#include \"mainboard/%s/bootblock.c\"\n", mainboard);
670 fprintf(autogen, "#else\n");
671 fprintf(autogen, "static unsigned long init_mainboard(int bsp_cpu)\n{\n");
672 fprintf(autogen, "\tif (! bsp_cpu) return 0;\n");
673 h = &headers;
674 while (h->next) {
675 h = h->next;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200676 char * buf = translate_name(h->name, UNSLASH);
677 if (buf) {
678 fprintf(autogen, "\tinit_%s();\n", buf);
679 free(buf);
680 }
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200681 }
682
683 fprintf(autogen, "\treturn 0;\n}\n");
684 fprintf(autogen, "#endif\n");
685
686 } else if (scan_mode == KCONFIG_MODE) {
687 fprintf(autogen, "\nconfig MAINBOARD_DIR\n\tstring\n");
688 fprintf(autogen, "\tdefault %s\n", mainboard);
689
690 fprintf(autogen, "\nconfig MAINBOARD_DEVTREE\n\tdef_bool y\n");
691 h = &headers;
692 while (h->next) {
693 h = h->next;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200694 char * buf = translate_name(h->name, TO_UPPER);
695 if (buf) {
696 fprintf(autogen, "\tselect %s\n", buf);
697 free(buf);
698 }
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200699 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000700 }
Sven Schnelle270a9082011-03-01 19:58:15 +0000701
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200702 fclose(autogen);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000703
Patrick Georgi114e7b22010-05-05 11:19:50 +0000704 return 0;
705}