blob: 570ca4a0cfa07371631eec73972c5412406494db [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
Patrick Georgi114e7b22010-05-05 11:19:50 +0000293 }
294 return new_d;
295}
296
Martin Rothbec07532016-08-05 18:32:18 -0600297void alias_siblings(struct device *d)
298{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000299 while (d) {
300 int link = 0;
301 struct device *cmp = d->next_sibling;
Martin Rothbec07532016-08-05 18:32:18 -0600302 while (cmp && (cmp->bus == d->bus) && (cmp->path_a == d->path_a)
303 && (cmp->path_b == d->path_b)) {
304 if (cmp->type == device && !cmp->used) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000305 if (device_match(d, cmp)) {
306 d->multidev = 1;
307
Patrick Georgi114e7b22010-05-05 11:19:50 +0000308 cmp->id = d->id;
309 cmp->name = d->name;
310 cmp->used = 1;
311 cmp->link = ++link;
312 }
313 }
314 cmp = cmp->next_sibling;
315 }
316 d = d->next_sibling;
317 }
318}
319
Martin Rothbec07532016-08-05 18:32:18 -0600320void add_resource(struct device *dev, int type, int index, int base)
321{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000322 struct resource *r = malloc(sizeof(struct resource));
Martin Rothbec07532016-08-05 18:32:18 -0600323 memset(r, 0, sizeof(struct resource));
Patrick Georgi114e7b22010-05-05 11:19:50 +0000324 r->type = type;
325 r->index = index;
326 r->base = base;
Patrick Georgi68befd52010-05-05 12:05:25 +0000327 if (dev->res) {
328 struct resource *head = dev->res;
Martin Rothbec07532016-08-05 18:32:18 -0600329 while (head->next)
330 head = head->next;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000331 head->next = r;
332 } else {
Patrick Georgi68befd52010-05-05 12:05:25 +0000333 dev->res = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000334 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000335 dev->rescnt++;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000336}
337
Martin Rothbec07532016-08-05 18:32:18 -0600338void add_register(struct device *dev, char *name, char *val)
339{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000340 struct reg *r = malloc(sizeof(struct reg));
Martin Rothbec07532016-08-05 18:32:18 -0600341 memset(r, 0, sizeof(struct reg));
Patrick Georgi114e7b22010-05-05 11:19:50 +0000342 r->key = name;
343 r->value = val;
Patrick Georgi68befd52010-05-05 12:05:25 +0000344 if (dev->reg) {
345 struct reg *head = dev->reg;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000346 // sorting to be equal to sconfig's behaviour
347 int sort = strcmp(r->key, head->key);
348 if (sort == 0) {
349 printf("ERROR: duplicate 'register' key.\n");
350 exit(1);
351 }
Martin Rothbec07532016-08-05 18:32:18 -0600352 if (sort < 0) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000353 r->next = head;
Patrick Georgi68befd52010-05-05 12:05:25 +0000354 dev->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000355 } else {
Martin Rothbec07532016-08-05 18:32:18 -0600356 while ((head->next)
357 && (strcmp(head->next->key, r->key) < 0))
358 head = head->next;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000359 r->next = head->next;
360 head->next = r;
361 }
362 } else {
Patrick Georgi68befd52010-05-05 12:05:25 +0000363 dev->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000364 }
365}
366
Martin Rothbec07532016-08-05 18:32:18 -0600367void add_pci_subsystem_ids(struct device *dev, int vendor, int device,
368 int inherit)
Sven Schnelle270a9082011-03-01 19:58:15 +0000369{
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800370 if (dev->bustype != PCI && dev->bustype != DOMAIN) {
Sven Schnelle270a9082011-03-01 19:58:15 +0000371 printf("ERROR: 'subsystem' only allowed for PCI devices\n");
372 exit(1);
373 }
374
375 dev->subsystem_vendor = vendor;
376 dev->subsystem_device = device;
377 dev->inherit_subsystem = inherit;
378}
379
Martin Rothbec07532016-08-05 18:32:18 -0600380void add_ioapic_info(struct device *dev, int apicid, const char *_srcpin,
381 int irqpin)
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200382{
383
384 int srcpin;
385
Martin Rothbec07532016-08-05 18:32:18 -0600386 if (!_srcpin || strlen(_srcpin) < 4 || strncasecmp(_srcpin, "INT", 3) ||
387 _srcpin[3] < 'A' || _srcpin[3] > 'D') {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200388 printf("ERROR: malformed ioapic_irq args: %s\n", _srcpin);
389 exit(1);
390 }
391
392 srcpin = _srcpin[3] - 'A';
393
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800394 if (dev->bustype != PCI && dev->bustype != DOMAIN) {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200395 printf("ERROR: ioapic config only allowed for PCI devices\n");
396 exit(1);
397 }
398
399 if (srcpin > 3) {
Patrick Georgi116327e2012-07-20 12:47:06 +0200400 printf("ERROR: srcpin '%d' invalid\n", srcpin);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200401 exit(1);
402 }
403 dev->pci_irq_info[srcpin].ioapic_irq_pin = irqpin;
404 dev->pci_irq_info[srcpin].ioapic_dst_id = apicid;
405}
406
Martin Rothbec07532016-08-05 18:32:18 -0600407static void pass0(FILE * fil, struct device *ptr)
408{
Myles Watson894a3472010-06-09 22:41:35 +0000409 if (ptr->type == device && ptr->id == 0)
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500410 fprintf(fil, "DEVTREE_CONST struct bus %s_links[];\n",
Martin Rothbec07532016-08-05 18:32:18 -0600411 ptr->name);
Stefan Reinauer57879c92012-07-31 16:47:25 -0700412
Myles Watsonc25cc112010-05-21 14:33:48 +0000413 if ((ptr->type == device) && (ptr->id != 0) && (!ptr->used)) {
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500414 fprintf(fil, "DEVTREE_CONST static struct device %s;\n",
Martin Rothbec07532016-08-05 18:32:18 -0600415 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000416 if (ptr->rescnt > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600417 fprintf(fil,
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500418 "DEVTREE_CONST struct resource %s_res[];\n",
Martin Rothbec07532016-08-05 18:32:18 -0600419 ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000420 if (ptr->children || ptr->multidev)
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500421 fprintf(fil, "DEVTREE_CONST struct bus %s_links[];\n",
Martin Rothbec07532016-08-05 18:32:18 -0600422 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000423 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000424}
425
Martin Rothbec07532016-08-05 18:32:18 -0600426static void pass1(FILE * fil, struct device *ptr)
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200427{
428 int pin;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000429 if (!ptr->used && (ptr->type == device)) {
Stefan Reinauerdf61dd22010-08-09 12:02:00 +0000430 if (ptr->id != 0)
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200431 fprintf(fil, "static ");
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500432 fprintf(fil, "DEVTREE_CONST struct device %s = {\n",
Martin Rothbec07532016-08-05 18:32:18 -0600433 ptr->name);
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500434 fprintf(fil, "#if !DEVTREE_EARLY\n");
Martin Rothbec07532016-08-05 18:32:18 -0600435 fprintf(fil, "\t.ops = %s,\n", (ptr->ops) ? (ptr->ops) : "0");
Stefan Reinauer57879c92012-07-31 16:47:25 -0700436 fprintf(fil, "#endif\n");
Martin Rothbec07532016-08-05 18:32:18 -0600437 fprintf(fil, "\t.bus = &%s_links[%d],\n", ptr->bus->name,
438 ptr->bus->link);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000439 fprintf(fil, "\t.path = {");
440 fprintf(fil, ptr->path, ptr->path_a, ptr->path_b);
441 fprintf(fil, "},\n");
442 fprintf(fil, "\t.enabled = %d,\n", ptr->enabled);
443 fprintf(fil, "\t.on_mainboard = 1,\n");
Sven Schnelle270a9082011-03-01 19:58:15 +0000444 if (ptr->subsystem_vendor > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600445 fprintf(fil, "\t.subsystem_vendor = 0x%04x,\n",
446 ptr->subsystem_vendor);
Sven Schnelle270a9082011-03-01 19:58:15 +0000447
Martin Rothbec07532016-08-05 18:32:18 -0600448 for (pin = 0; pin < 4; pin++) {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200449 if (ptr->pci_irq_info[pin].ioapic_irq_pin > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600450 fprintf(fil, "\t.pci_irq_info[%d].ioapic_irq_pin = %d,\n",
451 pin, ptr->pci_irq_info[pin].ioapic_irq_pin);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200452
453 if (ptr->pci_irq_info[pin].ioapic_dst_id > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600454 fprintf(fil, "\t.pci_irq_info[%d].ioapic_dst_id = %d,\n",
455 pin, ptr->pci_irq_info[pin].ioapic_dst_id);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200456 }
457
Sven Schnelle270a9082011-03-01 19:58:15 +0000458 if (ptr->subsystem_device > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600459 fprintf(fil, "\t.subsystem_device = 0x%04x,\n",
460 ptr->subsystem_device);
Sven Schnelle270a9082011-03-01 19:58:15 +0000461
Patrick Georgi114e7b22010-05-05 11:19:50 +0000462 if (ptr->rescnt > 0) {
Martin Rothbec07532016-08-05 18:32:18 -0600463 fprintf(fil, "\t.resource_list = &%s_res[0],\n",
464 ptr->name);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000465 }
Myles Watson894a3472010-06-09 22:41:35 +0000466 if (ptr->children || ptr->multidev)
Martin Rothbec07532016-08-05 18:32:18 -0600467 fprintf(fil, "\t.link_list = &%s_links[0],\n",
468 ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000469 else
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200470 fprintf(fil, "\t.link_list = NULL,\n");
Patrick Georgi114e7b22010-05-05 11:19:50 +0000471 if (ptr->sibling)
472 fprintf(fil, "\t.sibling = &%s,\n", ptr->sibling->name);
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500473 fprintf(fil, "#if !DEVTREE_EARLY\n");
Martin Rothbec07532016-08-05 18:32:18 -0600474 fprintf(fil, "\t.chip_ops = &%s_ops,\n",
475 ptr->chip->name_underscore);
Kyösti Mälkkia93c3fe2012-10-09 22:28:56 +0300476 if (ptr->chip->chip == &mainboard)
477 fprintf(fil, "\t.name = mainboard_name,\n");
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200478 fprintf(fil, "#endif\n");
479 if (ptr->chip->chiph_exists)
Martin Rothbec07532016-08-05 18:32:18 -0600480 fprintf(fil, "\t.chip_info = &%s_info_%d,\n",
481 ptr->chip->name_underscore, ptr->chip->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000482 if (ptr->nextdev)
483 fprintf(fil, "\t.next=&%s\n", ptr->nextdev->name);
484 fprintf(fil, "};\n");
485 }
Myles Watsonc25cc112010-05-21 14:33:48 +0000486 if (ptr->rescnt > 0) {
Martin Rothbec07532016-08-05 18:32:18 -0600487 int i = 1;
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500488 fprintf(fil, "DEVTREE_CONST struct resource %s_res[] = {\n",
Martin Rothbec07532016-08-05 18:32:18 -0600489 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000490 struct resource *r = ptr->res;
491 while (r) {
Martin Rothbec07532016-08-05 18:32:18 -0600492 fprintf(fil,
493 "\t\t{ .flags=IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_");
494 if (r->type == IRQ)
495 fprintf(fil, "IRQ");
496 if (r->type == DRQ)
497 fprintf(fil, "DRQ");
498 if (r->type == IO)
499 fprintf(fil, "IO");
500 fprintf(fil, ", .index=0x%x, .base=0x%x,", r->index,
501 r->base);
Myles Watsonc25cc112010-05-21 14:33:48 +0000502 if (r->next)
Martin Rothbec07532016-08-05 18:32:18 -0600503 fprintf(fil, ".next=&%s_res[%d]},\n", ptr->name,
504 i++);
Myles Watsonc25cc112010-05-21 14:33:48 +0000505 else
506 fprintf(fil, ".next=NULL },\n");
507 r = r->next;
508 }
509 fprintf(fil, "\t };\n");
510 }
Martin Rothbec07532016-08-05 18:32:18 -0600511 if (!ptr->used && ptr->type == device
512 && (ptr->children || ptr->multidev)) {
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500513 fprintf(fil, "DEVTREE_CONST struct bus %s_links[] = {\n",
Martin Rothbec07532016-08-05 18:32:18 -0600514 ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000515 if (ptr->multidev) {
516 struct device *d = ptr;
517 while (d) {
518 if (device_match(d, ptr)) {
519 fprintf(fil, "\t\t[%d] = {\n", d->link);
Martin Rothbec07532016-08-05 18:32:18 -0600520 fprintf(fil, "\t\t\t.link_num = %d,\n",
521 d->link);
522 fprintf(fil, "\t\t\t.dev = &%s,\n",
523 d->name);
Myles Watson894a3472010-06-09 22:41:35 +0000524 if (d->children)
Martin Rothbec07532016-08-05 18:32:18 -0600525 fprintf(fil,
526 "\t\t\t.children = &%s,\n",
527 d->children->name);
528 if (d->next_sibling
529 && device_match(d->next_sibling,
530 ptr))
531 fprintf(fil,
532 "\t\t\t.next=&%s_links[%d],\n",
533 d->name, d->link + 1);
Myles Watson894a3472010-06-09 22:41:35 +0000534 else
Martin Rothbec07532016-08-05 18:32:18 -0600535 fprintf(fil,
536 "\t\t\t.next = NULL,\n");
Myles Watson894a3472010-06-09 22:41:35 +0000537 fprintf(fil, "\t\t},\n");
538 }
539 d = d->next_sibling;
540 }
541 } else {
542 if (ptr->children) {
543 fprintf(fil, "\t\t[0] = {\n");
544 fprintf(fil, "\t\t\t.link_num = 0,\n");
545 fprintf(fil, "\t\t\t.dev = &%s,\n", ptr->name);
Martin Rothbec07532016-08-05 18:32:18 -0600546 fprintf(fil, "\t\t\t.children = &%s,\n",
547 ptr->children->name);
Myles Watson894a3472010-06-09 22:41:35 +0000548 fprintf(fil, "\t\t\t.next = NULL,\n");
549 fprintf(fil, "\t\t},\n");
550 }
551 }
552 fprintf(fil, "\t};\n");
553 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000554 if ((ptr->type == chip) && (ptr->chiph_exists)) {
555 if (ptr->reg) {
Martin Rothbec07532016-08-05 18:32:18 -0600556 fprintf(fil,
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500557 "DEVTREE_CONST struct %s_config %s_info_%d = {\n",
Stefan Reinauer57879c92012-07-31 16:47:25 -0700558 ptr->name_underscore, ptr->name_underscore,
559 ptr->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000560 struct reg *r = ptr->reg;
561 while (r) {
562 fprintf(fil, "\t.%s = %s,\n", r->key, r->value);
563 r = r->next;
564 }
565 fprintf(fil, "};\n\n");
566 } else {
Martin Rothbec07532016-08-05 18:32:18 -0600567 fprintf(fil,
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500568 "DEVTREE_CONST struct %s_config %s_info_%d = { };\n",
Martin Rothbec07532016-08-05 18:32:18 -0600569 ptr->name_underscore, ptr->name_underscore,
570 ptr->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000571 }
572 }
573}
574
Martin Rothbec07532016-08-05 18:32:18 -0600575static void walk_device_tree(FILE * fil, struct device *ptr,
576 void (*func) (FILE *, struct device *),
577 struct device *chips)
578{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000579 do {
580 func(fil, ptr);
581 ptr = ptr->next_sibling;
582 } while (ptr);
583}
584
Martin Rothbec07532016-08-05 18:32:18 -0600585static void inherit_subsystem_ids(FILE * file, struct device *dev)
Sven Schnelle270a9082011-03-01 19:58:15 +0000586{
587 struct device *p;
Sven Schnelle270a9082011-03-01 19:58:15 +0000588
589 if (dev->subsystem_vendor != -1 && dev->subsystem_device != -1) {
590 /* user already gave us a subsystem vendor/device */
591 return;
592 }
593
Martin Rothbec07532016-08-05 18:32:18 -0600594 for (p = dev; p && p != p->parent; p = p->parent) {
Sven Schnelle270a9082011-03-01 19:58:15 +0000595
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800596 if (p->bustype != PCI && p->bustype != DOMAIN)
Sven Schnelle270a9082011-03-01 19:58:15 +0000597 continue;
598
599 if (p->inherit_subsystem) {
600 dev->subsystem_vendor = p->subsystem_vendor;
601 dev->subsystem_device = p->subsystem_device;
602 break;
603 }
604 }
605}
606
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200607static void usage(void)
608{
Martin Rothc9c27bb2016-08-05 18:15:06 -0600609 printf("usage: sconfig devicetree_file output_file\n");
Martin Rothbec07532016-08-05 18:32:18 -0600610 exit(1);
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200611}
612
Martin Roth32051702015-11-24 12:34:16 -0700613enum {
Martin Rothc9c27bb2016-08-05 18:15:06 -0600614 DEVICEFILE_ARG = 1,
Martin Rothbec07532016-08-05 18:32:18 -0600615 OUTPUTFILE_ARG
616};
Martin Roth32051702015-11-24 12:34:16 -0700617
Martin Rothc9c27bb2016-08-05 18:15:06 -0600618#define ARG_COUNT 3
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200619
Martin Rothbec07532016-08-05 18:32:18 -0600620int main(int argc, char **argv)
621{
Martin Roth824255e2016-08-05 17:40:39 -0600622 if (argc != ARG_COUNT)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200623 usage();
624
Martin Roth25f8a4f2016-08-05 15:46:56 -0600625 char *devtree = argv[DEVICEFILE_ARG];
626 char *outputc = argv[OUTPUTFILE_ARG];
Patrick Georgi114e7b22010-05-05 11:19:50 +0000627
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200628 headers.next = 0;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000629
630 FILE *filec = fopen(devtree, "r");
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000631 if (!filec) {
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000632 perror(NULL);
633 exit(1);
634 }
635
Patrick Georgi114e7b22010-05-05 11:19:50 +0000636 yyrestart(filec);
637
Patrick Georgi68befd52010-05-05 12:05:25 +0000638 lastdev = head = &root;
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000639
Patrick Georgi114e7b22010-05-05 11:19:50 +0000640 yyparse();
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000641
Patrick Georgi114e7b22010-05-05 11:19:50 +0000642 fclose(filec);
643
644 if ((head->type == chip) && (!head->chiph_exists)) {
645 struct device *tmp = head;
646 head = &root;
Martin Rothbec07532016-08-05 18:32:18 -0600647 while (head->next != tmp)
648 head = head->next;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000649 }
650
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200651 FILE *autogen = fopen(outputc, "w");
652 if (!autogen) {
Martin Rothbec07532016-08-05 18:32:18 -0600653 fprintf(stderr, "Could not open file '%s' for writing: ",
654 outputc);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000655 perror(NULL);
656 exit(1);
657 }
658
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200659 struct header *h;
Martin Roth824255e2016-08-05 17:40:39 -0600660 fprintf(autogen, "#include <device/device.h>\n");
661 fprintf(autogen, "#include <device/pci.h>\n");
662 h = &headers;
663 while (h->next) {
664 h = h->next;
665 if (h->chiph_exists)
666 fprintf(autogen, "#include \"%s/chip.h\"\n", h->name);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000667 }
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500668 fprintf(autogen, "\n#if !DEVTREE_EARLY\n");
Martin Rothbec07532016-08-05 18:32:18 -0600669 fprintf(autogen,
670 "__attribute__((weak)) struct chip_operations mainboard_ops = {};\n");
Martin Roth824255e2016-08-05 17:40:39 -0600671 h = &headers;
672 while (h->next) {
673 h = h->next;
674 char *name_underscore = translate_name(h->name, UNSLASH);
Martin Rothbec07532016-08-05 18:32:18 -0600675 fprintf(autogen,
676 "__attribute__((weak)) struct chip_operations %s_ops = {};\n",
677 name_underscore);
Martin Roth824255e2016-08-05 17:40:39 -0600678 free(name_underscore);
679 }
680 fprintf(autogen, "#endif\n");
681
682 walk_device_tree(autogen, &root, inherit_subsystem_ids, NULL);
683 fprintf(autogen, "\n/* pass 0 */\n");
684 walk_device_tree(autogen, &root, pass0, NULL);
685 fprintf(autogen, "\n/* pass 1 */\n"
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500686 "DEVTREE_CONST struct device * DEVTREE_CONST last_dev = &%s;\n",
Martin Rothbec07532016-08-05 18:32:18 -0600687 lastdev->name);
Martin Roth824255e2016-08-05 17:40:39 -0600688 walk_device_tree(autogen, &root, pass1, NULL);
Sven Schnelle270a9082011-03-01 19:58:15 +0000689
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200690 fclose(autogen);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000691
Patrick Georgi114e7b22010-05-05 11:19:50 +0000692 return 0;
693}