blob: 2e34d85ad5dd04c66314bf86c0a29ab31c353434 [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 {
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +020030 UNSLASH,
31 SPLIT_1ST,
32 TO_LOWER,
33 TO_UPPER,
34} translate_t;
35
Patrick Georgi114e7b22010-05-05 11:19:50 +000036static struct device root;
37static struct device mainboard = {
38 .name = "mainboard",
39 .name_underscore = "mainboard",
40 .id = 0,
41 .chip = &mainboard,
42 .type = chip,
Stefan Reinauer188e3c22012-07-26 12:46:48 -070043 .chiph_exists = 0,
Patrick Georgi114e7b22010-05-05 11:19:50 +000044 .children = &root
45};
46
47static struct device root = {
48 .name = "dev_root",
49 .name_underscore = "dev_root",
50 .id = 0,
51 .chip = &mainboard,
52 .type = device,
53 .path = " .type = DEVICE_PATH_ROOT ",
54 .ops = "&default_dev_ops_root",
55 .parent = &root,
56 .bus = &root,
57 .enabled = 1
58};
59
Martin Rothbec07532016-08-05 18:32:18 -060060static struct device *new_dev(struct device *parent, struct device *bus)
61{
Patrick Georgi114e7b22010-05-05 11:19:50 +000062 struct device *dev = malloc(sizeof(struct device));
63 memset(dev, 0, sizeof(struct device));
64 dev->id = ++devcount;
Patrick Georgi68befd52010-05-05 12:05:25 +000065 dev->parent = parent;
66 dev->bus = bus;
Sven Schnelle270a9082011-03-01 19:58:15 +000067 dev->subsystem_vendor = -1;
68 dev->subsystem_device = -1;
Patrick Georgi114e7b22010-05-05 11:19:50 +000069 head->next = dev;
70 head = dev;
71 return dev;
72}
73
Martin Rothbec07532016-08-05 18:32:18 -060074static int device_match(struct device *a, struct device *b)
75{
76 if ((a->bustype == b->bustype) && (a->bus == b->bus)
77 && (a->path_a == b->path_a) && (a->path_b == b->path_b))
Patrick Georgi114e7b22010-05-05 11:19:50 +000078 return 1;
79 return 0;
80}
81
Martin Rothbec07532016-08-05 18:32:18 -060082void fold_in(struct device *parent)
83{
Patrick Georgi114e7b22010-05-05 11:19:50 +000084 struct device *child = parent->children;
85 struct device *latest = 0;
86 while (child != latest) {
87 if (child->children) {
Martin Rothbec07532016-08-05 18:32:18 -060088 if (!latest)
89 latest = child->children;
Patrick Georgi114e7b22010-05-05 11:19:50 +000090 parent->latestchild->next_sibling = child->children;
91 parent->latestchild = child->latestchild;
92 }
93 child = child->next_sibling;
94 }
95}
96
Martin Rothbec07532016-08-05 18:32:18 -060097int yywrap(void)
98{
Patrick Georgi114e7b22010-05-05 11:19:50 +000099 return 1;
100}
101
Martin Rothbec07532016-08-05 18:32:18 -0600102void yyerror(char const *str)
Patrick Georgi114e7b22010-05-05 11:19:50 +0000103{
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000104 extern char *yytext;
Martin Rothbec07532016-08-05 18:32:18 -0600105 fprintf(stderr, "line %d: %s: %s\n", linenum + 1, yytext, str);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000106 exit(1);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000107}
108
Martin Rothbec07532016-08-05 18:32:18 -0600109void postprocess_devtree(void)
110{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000111 root.next_sibling = root.children;
112 root.next_sibling->next_sibling = root.next_sibling->children;
113
114 struct device *dev = &root;
115 while (dev) {
116 /* skip "chip" elements in children chain */
Martin Rothbec07532016-08-05 18:32:18 -0600117 while (dev->children && (dev->children->type == chip))
118 dev->children = dev->children->children;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000119 /* skip "chip" elements and functions of the same device in sibling chain */
Martin Rothbec07532016-08-05 18:32:18 -0600120 while (dev->sibling && dev->sibling->used)
121 dev->sibling = dev->sibling->sibling;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000122 /* If end of chain, and parent is a chip, move on */
Martin Rothbec07532016-08-05 18:32:18 -0600123 if (!dev->sibling && (dev->parent->type == chip))
124 dev->sibling = dev->parent->sibling;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000125 /* skip chips */
Martin Rothbec07532016-08-05 18:32:18 -0600126 while (dev->sibling && dev->sibling->type == chip)
127 dev->sibling = dev->sibling->children;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000128 /* skip duplicate function elements in nextdev chain */
Martin Rothbec07532016-08-05 18:32:18 -0600129 while (dev->nextdev && dev->nextdev->used)
130 dev->nextdev = dev->nextdev->nextdev;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000131 dev = dev->next_sibling;
132 }
133}
134
Martin Rothbec07532016-08-05 18:32:18 -0600135char *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 }
Martin Rothbec07532016-08-05 18:32:18 -0600144 if (*c == '/')
145 *c = '_';
146 if (*c == '-')
147 *c = '_';
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200148 if (mode == TO_UPPER)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200149 *c = toupper(*c);
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200150 if (mode == TO_LOWER)
151 *c = tolower(*c);
152 c++;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200153 }
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200154 return b;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200155}
156
Martin Rothbec07532016-08-05 18:32:18 -0600157struct device *new_chip(struct device *parent, struct device *bus, char *path)
158{
Patrick Georgi68befd52010-05-05 12:05:25 +0000159 struct device *new_chip = new_dev(parent, bus);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000160 new_chip->chiph_exists = 1;
161 new_chip->name = path;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200162 new_chip->name_underscore = translate_name(new_chip->name, UNSLASH);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000163 new_chip->type = chip;
164 new_chip->chip = new_chip;
165
166 struct stat st;
Martin Rothbec07532016-08-05 18:32:18 -0600167 char *chip_h = malloc(strlen(path) + 18);
Stefan Reinauer76c44ae2011-10-14 12:41:46 -0700168 sprintf(chip_h, "src/%s", path);
169 if ((stat(chip_h, &st) == -1) && (errno == ENOENT)) {
Patrick Georgi92bcaa22015-11-13 09:39:22 +0100170 /* root_complex gets away without a separate directory, but
171 * exists on on pretty much all AMD chipsets.
172 */
173 if (!strstr(path, "/root_complex")) {
Kyösti Mälkki6aeb4a22013-06-11 17:00:11 +0300174 fprintf(stderr, "ERROR: Chip component %s does not exist.\n",
175 path);
176 exit(1);
177 }
Stefan Reinauer76c44ae2011-10-14 12:41:46 -0700178 }
179
Martin Roth824255e2016-08-05 17:40:39 -0600180 sprintf(chip_h, "src/%s/chip.h", path);
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200181
Martin Roth824255e2016-08-05 17:40:39 -0600182 if ((stat(chip_h, &st) == -1) && (errno == ENOENT))
Martin Rothbec07532016-08-05 18:32:18 -0600183 new_chip->chiph_exists = 0;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000184
Patrick Georgi68befd52010-05-05 12:05:25 +0000185 if (parent->latestchild) {
186 parent->latestchild->next_sibling = new_chip;
187 parent->latestchild->sibling = new_chip;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000188 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000189 parent->latestchild = new_chip;
190 if (!parent->children)
191 parent->children = new_chip;
Patrick Georgi1f688802014-08-03 15:51:19 +0200192 free(chip_h);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000193 return new_chip;
194}
195
Martin Rothbec07532016-08-05 18:32:18 -0600196void add_header(struct device *dev)
197{
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200198 int include_exists = 0;
199 struct header *h = &headers;
200 while (h->next) {
201 int result = strcmp(dev->name, h->next->name);
202 if (result == 0) {
203 include_exists = 1;
204 break;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000205 }
Martin Rothbec07532016-08-05 18:32:18 -0600206 if (result < 0)
207 break;
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200208 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
Martin Rothbec07532016-08-05 18:32:18 -0600220struct device *new_device(struct device *parent, struct device *busdev,
221 const int bus, const char *devnum, int enabled)
222{
Patrick Georgi68befd52010-05-05 12:05:25 +0000223 struct device *new_d = new_dev(parent, busdev);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000224 new_d->bustype = bus;
225
226 char *tmp;
Patrick Georgi1f688802014-08-03 15:51:19 +0200227 new_d->path_a = strtol(devnum, &tmp, 16);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000228 if (*tmp == '.') {
229 tmp++;
230 new_d->path_b = strtol(tmp, NULL, 16);
231 }
232
233 char *name = malloc(10);
234 sprintf(name, "_dev%d", new_d->id);
235 new_d->name = name;
Martin Rothbec07532016-08-05 18:32:18 -0600236 new_d->name_underscore = name; // shouldn't be necessary, but avoid 0-ptr
Patrick Georgi114e7b22010-05-05 11:19:50 +0000237 new_d->type = device;
238 new_d->enabled = enabled;
239 new_d->chip = new_d->parent->chip;
240
Patrick Georgi68befd52010-05-05 12:05:25 +0000241 if (parent->latestchild) {
242 parent->latestchild->next_sibling = new_d;
243 parent->latestchild->sibling = new_d;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000244 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000245 parent->latestchild = new_d;
246 if (!parent->children)
247 parent->children = new_d;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000248
249 lastdev->nextdev = new_d;
250 lastdev = new_d;
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200251
Martin Rothbec07532016-08-05 18:32:18 -0600252 switch (bus) {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200253 case PCI:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000254 new_d->path = ".type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x%x,%d)}}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200255 break;
256
257 case PNP:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000258 new_d->path = ".type=DEVICE_PATH_PNP,{.pnp={ .port = 0x%x, .device = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200259 break;
260
261 case I2C:
Duncan Laurieb7ce5fe2016-05-07 19:49:37 -0700262 new_d->path = ".type=DEVICE_PATH_I2C,{.i2c={ .device = 0x%x, .mode_10bit = %d }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200263 break;
264
265 case APIC:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000266 new_d->path = ".type=DEVICE_PATH_APIC,{.apic={ .apic_id = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200267 break;
268
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800269 case CPU_CLUSTER:
270 new_d->path = ".type=DEVICE_PATH_CPU_CLUSTER,{.cpu_cluster={ .cluster = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200271 break;
272
Aaron Durbinffda804b2014-09-03 12:40:15 -0500273 case CPU:
274 new_d->path = ".type=DEVICE_PATH_CPU,{.cpu={ .id = 0x%x }}";
275 break;
276
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800277 case DOMAIN:
278 new_d->path = ".type=DEVICE_PATH_DOMAIN,{.domain={ .domain = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200279 break;
280
281 case IOAPIC:
282 new_d->path = ".type=DEVICE_PATH_IOAPIC,{.ioapic={ .ioapic_id = 0x%x }}";
283 break;
Duncan Laurie4650f5b2016-05-07 20:01:34 -0700284
285 case GENERIC:
286 new_d->path = ".type=DEVICE_PATH_GENERIC,{.generic={ .id = 0x%x, .subid = 0x%x }}";
287 break;
Furquan Shaikhe6700292017-02-11 00:50:38 -0800288
289 case SPI:
290 new_d->path = ".type=DEVICE_PATH_SPI,{.spi={ .cs = 0x%x }}";
291 break;
292
Duncan Lauriebae9f852018-05-07 14:18:13 -0700293 case USB:
294 new_d->path = ".type=DEVICE_PATH_USB,{.usb={ .port_type = %d, .port_id = %d }}";
295 break;
296
Justin TerAvestca2ed9f2018-01-17 16:36:30 -0800297 case MMIO:
298 new_d->path = ".type=DEVICE_PATH_MMIO,{.mmio={ .addr = 0x%x }}";
299 break;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000300 }
Justin TerAvestca2ed9f2018-01-17 16:36:30 -0800301
Patrick Georgi114e7b22010-05-05 11:19:50 +0000302 return new_d;
303}
304
Martin Rothbec07532016-08-05 18:32:18 -0600305void alias_siblings(struct device *d)
306{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000307 while (d) {
308 int link = 0;
309 struct device *cmp = d->next_sibling;
Martin Rothbec07532016-08-05 18:32:18 -0600310 while (cmp && (cmp->bus == d->bus) && (cmp->path_a == d->path_a)
311 && (cmp->path_b == d->path_b)) {
312 if (cmp->type == device && !cmp->used) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000313 if (device_match(d, cmp)) {
314 d->multidev = 1;
315
Patrick Georgi114e7b22010-05-05 11:19:50 +0000316 cmp->id = d->id;
317 cmp->name = d->name;
318 cmp->used = 1;
319 cmp->link = ++link;
320 }
321 }
322 cmp = cmp->next_sibling;
323 }
324 d = d->next_sibling;
325 }
326}
327
Martin Rothbec07532016-08-05 18:32:18 -0600328void add_resource(struct device *dev, int type, int index, int base)
329{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000330 struct resource *r = malloc(sizeof(struct resource));
Martin Rothbec07532016-08-05 18:32:18 -0600331 memset(r, 0, sizeof(struct resource));
Patrick Georgi114e7b22010-05-05 11:19:50 +0000332 r->type = type;
333 r->index = index;
334 r->base = base;
Patrick Georgi68befd52010-05-05 12:05:25 +0000335 if (dev->res) {
336 struct resource *head = dev->res;
Martin Rothbec07532016-08-05 18:32:18 -0600337 while (head->next)
338 head = head->next;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000339 head->next = r;
340 } else {
Patrick Georgi68befd52010-05-05 12:05:25 +0000341 dev->res = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000342 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000343 dev->rescnt++;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000344}
345
Martin Rothbec07532016-08-05 18:32:18 -0600346void add_register(struct device *dev, char *name, char *val)
347{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000348 struct reg *r = malloc(sizeof(struct reg));
Martin Rothbec07532016-08-05 18:32:18 -0600349 memset(r, 0, sizeof(struct reg));
Patrick Georgi114e7b22010-05-05 11:19:50 +0000350 r->key = name;
351 r->value = val;
Patrick Georgi68befd52010-05-05 12:05:25 +0000352 if (dev->reg) {
353 struct reg *head = dev->reg;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000354 // sorting to be equal to sconfig's behaviour
355 int sort = strcmp(r->key, head->key);
356 if (sort == 0) {
357 printf("ERROR: duplicate 'register' key.\n");
358 exit(1);
359 }
Martin Rothbec07532016-08-05 18:32:18 -0600360 if (sort < 0) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000361 r->next = head;
Patrick Georgi68befd52010-05-05 12:05:25 +0000362 dev->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000363 } else {
Martin Rothbec07532016-08-05 18:32:18 -0600364 while ((head->next)
365 && (strcmp(head->next->key, r->key) < 0))
366 head = head->next;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000367 r->next = head->next;
368 head->next = r;
369 }
370 } else {
Patrick Georgi68befd52010-05-05 12:05:25 +0000371 dev->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000372 }
373}
374
Martin Rothbec07532016-08-05 18:32:18 -0600375void add_pci_subsystem_ids(struct device *dev, int vendor, int device,
376 int inherit)
Sven Schnelle270a9082011-03-01 19:58:15 +0000377{
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800378 if (dev->bustype != PCI && dev->bustype != DOMAIN) {
Sven Schnelle270a9082011-03-01 19:58:15 +0000379 printf("ERROR: 'subsystem' only allowed for PCI devices\n");
380 exit(1);
381 }
382
383 dev->subsystem_vendor = vendor;
384 dev->subsystem_device = device;
385 dev->inherit_subsystem = inherit;
386}
387
Martin Rothbec07532016-08-05 18:32:18 -0600388void add_ioapic_info(struct device *dev, int apicid, const char *_srcpin,
389 int irqpin)
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200390{
391
392 int srcpin;
393
Martin Rothbec07532016-08-05 18:32:18 -0600394 if (!_srcpin || strlen(_srcpin) < 4 || strncasecmp(_srcpin, "INT", 3) ||
395 _srcpin[3] < 'A' || _srcpin[3] > 'D') {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200396 printf("ERROR: malformed ioapic_irq args: %s\n", _srcpin);
397 exit(1);
398 }
399
400 srcpin = _srcpin[3] - 'A';
401
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800402 if (dev->bustype != PCI && dev->bustype != DOMAIN) {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200403 printf("ERROR: ioapic config only allowed for PCI devices\n");
404 exit(1);
405 }
406
407 if (srcpin > 3) {
Patrick Georgi116327e2012-07-20 12:47:06 +0200408 printf("ERROR: srcpin '%d' invalid\n", srcpin);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200409 exit(1);
410 }
411 dev->pci_irq_info[srcpin].ioapic_irq_pin = irqpin;
412 dev->pci_irq_info[srcpin].ioapic_dst_id = apicid;
413}
414
Martin Rothbec07532016-08-05 18:32:18 -0600415static void pass0(FILE * fil, struct device *ptr)
416{
Myles Watson894a3472010-06-09 22:41:35 +0000417 if (ptr->type == device && ptr->id == 0)
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500418 fprintf(fil, "DEVTREE_CONST struct bus %s_links[];\n",
Martin Rothbec07532016-08-05 18:32:18 -0600419 ptr->name);
Stefan Reinauer57879c92012-07-31 16:47:25 -0700420
Myles Watsonc25cc112010-05-21 14:33:48 +0000421 if ((ptr->type == device) && (ptr->id != 0) && (!ptr->used)) {
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500422 fprintf(fil, "DEVTREE_CONST static struct device %s;\n",
Martin Rothbec07532016-08-05 18:32:18 -0600423 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000424 if (ptr->rescnt > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600425 fprintf(fil,
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500426 "DEVTREE_CONST struct resource %s_res[];\n",
Martin Rothbec07532016-08-05 18:32:18 -0600427 ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000428 if (ptr->children || ptr->multidev)
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500429 fprintf(fil, "DEVTREE_CONST struct bus %s_links[];\n",
Martin Rothbec07532016-08-05 18:32:18 -0600430 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000431 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000432}
433
Martin Rothbec07532016-08-05 18:32:18 -0600434static void pass1(FILE * fil, struct device *ptr)
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200435{
436 int pin;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000437 if (!ptr->used && (ptr->type == device)) {
Stefan Reinauerdf61dd22010-08-09 12:02:00 +0000438 if (ptr->id != 0)
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200439 fprintf(fil, "static ");
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500440 fprintf(fil, "DEVTREE_CONST struct device %s = {\n",
Martin Rothbec07532016-08-05 18:32:18 -0600441 ptr->name);
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500442 fprintf(fil, "#if !DEVTREE_EARLY\n");
Martin Rothbec07532016-08-05 18:32:18 -0600443 fprintf(fil, "\t.ops = %s,\n", (ptr->ops) ? (ptr->ops) : "0");
Stefan Reinauer57879c92012-07-31 16:47:25 -0700444 fprintf(fil, "#endif\n");
Martin Rothbec07532016-08-05 18:32:18 -0600445 fprintf(fil, "\t.bus = &%s_links[%d],\n", ptr->bus->name,
446 ptr->bus->link);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000447 fprintf(fil, "\t.path = {");
448 fprintf(fil, ptr->path, ptr->path_a, ptr->path_b);
449 fprintf(fil, "},\n");
450 fprintf(fil, "\t.enabled = %d,\n", ptr->enabled);
451 fprintf(fil, "\t.on_mainboard = 1,\n");
Sven Schnelle270a9082011-03-01 19:58:15 +0000452 if (ptr->subsystem_vendor > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600453 fprintf(fil, "\t.subsystem_vendor = 0x%04x,\n",
454 ptr->subsystem_vendor);
Sven Schnelle270a9082011-03-01 19:58:15 +0000455
Martin Rothbec07532016-08-05 18:32:18 -0600456 for (pin = 0; pin < 4; pin++) {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200457 if (ptr->pci_irq_info[pin].ioapic_irq_pin > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600458 fprintf(fil, "\t.pci_irq_info[%d].ioapic_irq_pin = %d,\n",
459 pin, ptr->pci_irq_info[pin].ioapic_irq_pin);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200460
461 if (ptr->pci_irq_info[pin].ioapic_dst_id > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600462 fprintf(fil, "\t.pci_irq_info[%d].ioapic_dst_id = %d,\n",
463 pin, ptr->pci_irq_info[pin].ioapic_dst_id);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200464 }
465
Sven Schnelle270a9082011-03-01 19:58:15 +0000466 if (ptr->subsystem_device > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600467 fprintf(fil, "\t.subsystem_device = 0x%04x,\n",
468 ptr->subsystem_device);
Sven Schnelle270a9082011-03-01 19:58:15 +0000469
Patrick Georgi114e7b22010-05-05 11:19:50 +0000470 if (ptr->rescnt > 0) {
Martin Rothbec07532016-08-05 18:32:18 -0600471 fprintf(fil, "\t.resource_list = &%s_res[0],\n",
472 ptr->name);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000473 }
Myles Watson894a3472010-06-09 22:41:35 +0000474 if (ptr->children || ptr->multidev)
Martin Rothbec07532016-08-05 18:32:18 -0600475 fprintf(fil, "\t.link_list = &%s_links[0],\n",
476 ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000477 else
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200478 fprintf(fil, "\t.link_list = NULL,\n");
Patrick Georgi114e7b22010-05-05 11:19:50 +0000479 if (ptr->sibling)
480 fprintf(fil, "\t.sibling = &%s,\n", ptr->sibling->name);
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500481 fprintf(fil, "#if !DEVTREE_EARLY\n");
Martin Rothbec07532016-08-05 18:32:18 -0600482 fprintf(fil, "\t.chip_ops = &%s_ops,\n",
483 ptr->chip->name_underscore);
Kyösti Mälkkia93c3fe2012-10-09 22:28:56 +0300484 if (ptr->chip->chip == &mainboard)
485 fprintf(fil, "\t.name = mainboard_name,\n");
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200486 fprintf(fil, "#endif\n");
487 if (ptr->chip->chiph_exists)
Martin Rothbec07532016-08-05 18:32:18 -0600488 fprintf(fil, "\t.chip_info = &%s_info_%d,\n",
489 ptr->chip->name_underscore, ptr->chip->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000490 if (ptr->nextdev)
491 fprintf(fil, "\t.next=&%s\n", ptr->nextdev->name);
492 fprintf(fil, "};\n");
493 }
Myles Watsonc25cc112010-05-21 14:33:48 +0000494 if (ptr->rescnt > 0) {
Martin Rothbec07532016-08-05 18:32:18 -0600495 int i = 1;
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500496 fprintf(fil, "DEVTREE_CONST struct resource %s_res[] = {\n",
Martin Rothbec07532016-08-05 18:32:18 -0600497 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000498 struct resource *r = ptr->res;
499 while (r) {
Martin Rothbec07532016-08-05 18:32:18 -0600500 fprintf(fil,
501 "\t\t{ .flags=IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_");
502 if (r->type == IRQ)
503 fprintf(fil, "IRQ");
504 if (r->type == DRQ)
505 fprintf(fil, "DRQ");
506 if (r->type == IO)
507 fprintf(fil, "IO");
508 fprintf(fil, ", .index=0x%x, .base=0x%x,", r->index,
509 r->base);
Myles Watsonc25cc112010-05-21 14:33:48 +0000510 if (r->next)
Martin Rothbec07532016-08-05 18:32:18 -0600511 fprintf(fil, ".next=&%s_res[%d]},\n", ptr->name,
512 i++);
Myles Watsonc25cc112010-05-21 14:33:48 +0000513 else
514 fprintf(fil, ".next=NULL },\n");
515 r = r->next;
516 }
517 fprintf(fil, "\t };\n");
518 }
Martin Rothbec07532016-08-05 18:32:18 -0600519 if (!ptr->used && ptr->type == device
520 && (ptr->children || ptr->multidev)) {
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500521 fprintf(fil, "DEVTREE_CONST struct bus %s_links[] = {\n",
Martin Rothbec07532016-08-05 18:32:18 -0600522 ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000523 if (ptr->multidev) {
524 struct device *d = ptr;
525 while (d) {
526 if (device_match(d, ptr)) {
527 fprintf(fil, "\t\t[%d] = {\n", d->link);
Martin Rothbec07532016-08-05 18:32:18 -0600528 fprintf(fil, "\t\t\t.link_num = %d,\n",
529 d->link);
530 fprintf(fil, "\t\t\t.dev = &%s,\n",
531 d->name);
Myles Watson894a3472010-06-09 22:41:35 +0000532 if (d->children)
Martin Rothbec07532016-08-05 18:32:18 -0600533 fprintf(fil,
534 "\t\t\t.children = &%s,\n",
535 d->children->name);
536 if (d->next_sibling
537 && device_match(d->next_sibling,
538 ptr))
539 fprintf(fil,
540 "\t\t\t.next=&%s_links[%d],\n",
541 d->name, d->link + 1);
Myles Watson894a3472010-06-09 22:41:35 +0000542 else
Martin Rothbec07532016-08-05 18:32:18 -0600543 fprintf(fil,
544 "\t\t\t.next = NULL,\n");
Myles Watson894a3472010-06-09 22:41:35 +0000545 fprintf(fil, "\t\t},\n");
546 }
547 d = d->next_sibling;
548 }
549 } else {
550 if (ptr->children) {
551 fprintf(fil, "\t\t[0] = {\n");
552 fprintf(fil, "\t\t\t.link_num = 0,\n");
553 fprintf(fil, "\t\t\t.dev = &%s,\n", ptr->name);
Martin Rothbec07532016-08-05 18:32:18 -0600554 fprintf(fil, "\t\t\t.children = &%s,\n",
555 ptr->children->name);
Myles Watson894a3472010-06-09 22:41:35 +0000556 fprintf(fil, "\t\t\t.next = NULL,\n");
557 fprintf(fil, "\t\t},\n");
558 }
559 }
560 fprintf(fil, "\t};\n");
561 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000562 if ((ptr->type == chip) && (ptr->chiph_exists)) {
563 if (ptr->reg) {
Martin Rothbec07532016-08-05 18:32:18 -0600564 fprintf(fil,
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500565 "DEVTREE_CONST struct %s_config %s_info_%d = {\n",
Stefan Reinauer57879c92012-07-31 16:47:25 -0700566 ptr->name_underscore, ptr->name_underscore,
567 ptr->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000568 struct reg *r = ptr->reg;
569 while (r) {
570 fprintf(fil, "\t.%s = %s,\n", r->key, r->value);
571 r = r->next;
572 }
573 fprintf(fil, "};\n\n");
574 } else {
Martin Rothbec07532016-08-05 18:32:18 -0600575 fprintf(fil,
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500576 "DEVTREE_CONST struct %s_config %s_info_%d = { };\n",
Martin Rothbec07532016-08-05 18:32:18 -0600577 ptr->name_underscore, ptr->name_underscore,
578 ptr->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000579 }
580 }
581}
582
Martin Rothbec07532016-08-05 18:32:18 -0600583static void walk_device_tree(FILE * fil, struct device *ptr,
584 void (*func) (FILE *, struct device *),
585 struct device *chips)
586{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000587 do {
588 func(fil, ptr);
589 ptr = ptr->next_sibling;
590 } while (ptr);
591}
592
Martin Rothbec07532016-08-05 18:32:18 -0600593static void inherit_subsystem_ids(FILE * file, struct device *dev)
Sven Schnelle270a9082011-03-01 19:58:15 +0000594{
595 struct device *p;
Sven Schnelle270a9082011-03-01 19:58:15 +0000596
597 if (dev->subsystem_vendor != -1 && dev->subsystem_device != -1) {
598 /* user already gave us a subsystem vendor/device */
599 return;
600 }
601
Martin Rothbec07532016-08-05 18:32:18 -0600602 for (p = dev; p && p != p->parent; p = p->parent) {
Sven Schnelle270a9082011-03-01 19:58:15 +0000603
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800604 if (p->bustype != PCI && p->bustype != DOMAIN)
Sven Schnelle270a9082011-03-01 19:58:15 +0000605 continue;
606
607 if (p->inherit_subsystem) {
608 dev->subsystem_vendor = p->subsystem_vendor;
609 dev->subsystem_device = p->subsystem_device;
610 break;
611 }
612 }
613}
614
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200615static void usage(void)
616{
Martin Rothc9c27bb2016-08-05 18:15:06 -0600617 printf("usage: sconfig devicetree_file output_file\n");
Martin Rothbec07532016-08-05 18:32:18 -0600618 exit(1);
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200619}
620
Martin Roth32051702015-11-24 12:34:16 -0700621enum {
Martin Rothc9c27bb2016-08-05 18:15:06 -0600622 DEVICEFILE_ARG = 1,
Martin Rothbec07532016-08-05 18:32:18 -0600623 OUTPUTFILE_ARG
624};
Martin Roth32051702015-11-24 12:34:16 -0700625
Martin Rothc9c27bb2016-08-05 18:15:06 -0600626#define ARG_COUNT 3
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200627
Martin Rothbec07532016-08-05 18:32:18 -0600628int main(int argc, char **argv)
629{
Martin Roth824255e2016-08-05 17:40:39 -0600630 if (argc != ARG_COUNT)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200631 usage();
632
Martin Roth25f8a4f2016-08-05 15:46:56 -0600633 char *devtree = argv[DEVICEFILE_ARG];
634 char *outputc = argv[OUTPUTFILE_ARG];
Patrick Georgi114e7b22010-05-05 11:19:50 +0000635
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200636 headers.next = 0;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000637
638 FILE *filec = fopen(devtree, "r");
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000639 if (!filec) {
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000640 perror(NULL);
641 exit(1);
642 }
643
Patrick Georgi114e7b22010-05-05 11:19:50 +0000644 yyrestart(filec);
645
Patrick Georgi68befd52010-05-05 12:05:25 +0000646 lastdev = head = &root;
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000647
Patrick Georgi114e7b22010-05-05 11:19:50 +0000648 yyparse();
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000649
Patrick Georgi114e7b22010-05-05 11:19:50 +0000650 fclose(filec);
651
652 if ((head->type == chip) && (!head->chiph_exists)) {
653 struct device *tmp = head;
654 head = &root;
Martin Rothbec07532016-08-05 18:32:18 -0600655 while (head->next != tmp)
656 head = head->next;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000657 }
658
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200659 FILE *autogen = fopen(outputc, "w");
660 if (!autogen) {
Martin Rothbec07532016-08-05 18:32:18 -0600661 fprintf(stderr, "Could not open file '%s' for writing: ",
662 outputc);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000663 perror(NULL);
664 exit(1);
665 }
666
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200667 struct header *h;
Martin Roth824255e2016-08-05 17:40:39 -0600668 fprintf(autogen, "#include <device/device.h>\n");
669 fprintf(autogen, "#include <device/pci.h>\n");
670 h = &headers;
671 while (h->next) {
672 h = h->next;
673 if (h->chiph_exists)
674 fprintf(autogen, "#include \"%s/chip.h\"\n", h->name);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000675 }
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500676 fprintf(autogen, "\n#if !DEVTREE_EARLY\n");
Martin Rothbec07532016-08-05 18:32:18 -0600677 fprintf(autogen,
678 "__attribute__((weak)) struct chip_operations mainboard_ops = {};\n");
Martin Roth824255e2016-08-05 17:40:39 -0600679 h = &headers;
680 while (h->next) {
681 h = h->next;
682 char *name_underscore = translate_name(h->name, UNSLASH);
Martin Rothbec07532016-08-05 18:32:18 -0600683 fprintf(autogen,
684 "__attribute__((weak)) struct chip_operations %s_ops = {};\n",
685 name_underscore);
Martin Roth824255e2016-08-05 17:40:39 -0600686 free(name_underscore);
687 }
688 fprintf(autogen, "#endif\n");
689
690 walk_device_tree(autogen, &root, inherit_subsystem_ids, NULL);
691 fprintf(autogen, "\n/* pass 0 */\n");
692 walk_device_tree(autogen, &root, pass0, NULL);
693 fprintf(autogen, "\n/* pass 1 */\n"
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500694 "DEVTREE_CONST struct device * DEVTREE_CONST last_dev = &%s;\n",
Martin Rothbec07532016-08-05 18:32:18 -0600695 lastdev->name);
Martin Roth824255e2016-08-05 17:40:39 -0600696 walk_device_tree(autogen, &root, pass1, NULL);
Sven Schnelle270a9082011-03-01 19:58:15 +0000697
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200698 fclose(autogen);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000699
Patrick Georgi114e7b22010-05-05 11:19:50 +0000700 return 0;
701}