blob: 382d5e5c7b3d506dcfbbfd5a9d342f88143058f5 [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
Furquan Shaikh79e84122018-05-30 15:09:09 -070027static struct chip *chip_head;
28
29/*
30 * This is intentionally shared between chip and device structure ids because it
31 * is easier to track the order of parsing for chip and device.
32 */
33static int count = 0;
Patrick Georgi114e7b22010-05-05 11:19:50 +000034
Kyösti Mälkki472d9022011-12-05 20:33:55 +020035typedef enum {
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +020036 UNSLASH,
37 SPLIT_1ST,
38 TO_LOWER,
39 TO_UPPER,
40} translate_t;
41
Patrick Georgi114e7b22010-05-05 11:19:50 +000042static struct device root;
Furquan Shaikh79e84122018-05-30 15:09:09 -070043static struct chip mainboard = {
Patrick Georgi114e7b22010-05-05 11:19:50 +000044 .name = "mainboard",
45 .name_underscore = "mainboard",
Patrick Georgi114e7b22010-05-05 11:19:50 +000046};
47
48static struct device root = {
49 .name = "dev_root",
Patrick Georgi114e7b22010-05-05 11:19:50 +000050 .id = 0,
51 .chip = &mainboard,
Patrick Georgi114e7b22010-05-05 11:19:50 +000052 .path = " .type = DEVICE_PATH_ROOT ",
53 .ops = "&default_dev_ops_root",
54 .parent = &root,
55 .bus = &root,
56 .enabled = 1
57};
58
Furquan Shaikh79e84122018-05-30 15:09:09 -070059static struct queue {
60 void *data;
61 struct queue *next;
62 struct queue *prev;
63} *q;
64
65struct queue *new_queue_entry(void *data)
66{
67 struct queue *e = malloc(sizeof(*e));
68
69 if (!e) {
70 fprintf(stderr, "%s: malloc failure!\n", __func__);
71 exit(1);
72 }
73
74 e->data = data;
75 e->next = e->prev = e;
76 return e;
77}
78
79void chip_enqueue_tail(void *data)
80{
81 struct queue *tmp = new_queue_entry(data);
82
83 if (!q) {
84 q = tmp;
85 return;
86 }
87
88 q->prev->next = tmp;
89 tmp->prev = q->prev;
90 q->prev = tmp;
91 tmp->next = q;
92}
93
94void *chip_dequeue_tail(void)
95{
96 struct queue *tmp = q->prev;
97 void *data;
98
99 if (tmp == q)
100 q = NULL;
101 else {
102 tmp->prev->next = q;
103 q->prev = tmp->prev;
104 }
105
106 data = tmp->data;
107 free(tmp);
108
109 return data;
110}
111
Martin Rothbec07532016-08-05 18:32:18 -0600112static struct device *new_dev(struct device *parent, struct device *bus)
113{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000114 struct device *dev = malloc(sizeof(struct device));
115 memset(dev, 0, sizeof(struct device));
Furquan Shaikh79e84122018-05-30 15:09:09 -0700116 dev->id = ++count;
Patrick Georgi68befd52010-05-05 12:05:25 +0000117 dev->parent = parent;
118 dev->bus = bus;
Sven Schnelle270a9082011-03-01 19:58:15 +0000119 dev->subsystem_vendor = -1;
120 dev->subsystem_device = -1;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000121 head->next = dev;
122 head = dev;
123 return dev;
124}
125
Martin Rothbec07532016-08-05 18:32:18 -0600126static int device_match(struct device *a, struct device *b)
127{
128 if ((a->bustype == b->bustype) && (a->bus == b->bus)
129 && (a->path_a == b->path_a) && (a->path_b == b->path_b))
Patrick Georgi114e7b22010-05-05 11:19:50 +0000130 return 1;
131 return 0;
132}
133
Martin Rothbec07532016-08-05 18:32:18 -0600134void fold_in(struct device *parent)
135{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000136 struct device *child = parent->children;
137 struct device *latest = 0;
138 while (child != latest) {
139 if (child->children) {
Martin Rothbec07532016-08-05 18:32:18 -0600140 if (!latest)
141 latest = child->children;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000142 parent->latestchild->next_sibling = child->children;
143 parent->latestchild = child->latestchild;
144 }
145 child = child->next_sibling;
146 }
147}
148
Martin Rothbec07532016-08-05 18:32:18 -0600149int yywrap(void)
150{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000151 return 1;
152}
153
Martin Rothbec07532016-08-05 18:32:18 -0600154void yyerror(char const *str)
Patrick Georgi114e7b22010-05-05 11:19:50 +0000155{
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000156 extern char *yytext;
Martin Rothbec07532016-08-05 18:32:18 -0600157 fprintf(stderr, "line %d: %s: %s\n", linenum + 1, yytext, str);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000158 exit(1);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000159}
160
Martin Rothbec07532016-08-05 18:32:18 -0600161void postprocess_devtree(void)
162{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000163 root.next_sibling = root.children;
Furquan Shaikh79e84122018-05-30 15:09:09 -0700164
165 /*
166 * Since root is statically created we need to call fold_in explicitly
167 * here to have the next_sibling and latestchild setup correctly.
168 */
169 fold_in(&root);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000170
171 struct device *dev = &root;
172 while (dev) {
Furquan Shaikh79e84122018-05-30 15:09:09 -0700173 /* skip functions of the same device in sibling chain */
Martin Rothbec07532016-08-05 18:32:18 -0600174 while (dev->sibling && dev->sibling->used)
175 dev->sibling = dev->sibling->sibling;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000176 /* skip duplicate function elements in nextdev chain */
Martin Rothbec07532016-08-05 18:32:18 -0600177 while (dev->nextdev && dev->nextdev->used)
178 dev->nextdev = dev->nextdev->nextdev;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000179 dev = dev->next_sibling;
180 }
181}
182
Martin Rothbec07532016-08-05 18:32:18 -0600183char *translate_name(const char *str, translate_t mode)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200184{
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200185 char *b, *c;
186 b = c = strdup(str);
187 while (c && *c) {
188 if ((mode == SPLIT_1ST) && (*c == '/')) {
189 *c = 0;
190 break;
191 }
Martin Rothbec07532016-08-05 18:32:18 -0600192 if (*c == '/')
193 *c = '_';
194 if (*c == '-')
195 *c = '_';
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200196 if (mode == TO_UPPER)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200197 *c = toupper(*c);
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200198 if (mode == TO_LOWER)
199 *c = tolower(*c);
200 c++;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200201 }
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200202 return b;
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200203}
204
Furquan Shaikh79e84122018-05-30 15:09:09 -0700205struct chip *new_chip(char *path)
Martin Rothbec07532016-08-05 18:32:18 -0600206{
Furquan Shaikh79e84122018-05-30 15:09:09 -0700207 struct chip *new_chip = malloc(sizeof(*new_chip));
208 if (!new_chip) {
209 fprintf(stderr, "%s: malloc failure!\n", __func__);
210 exit(1);
211 }
212
213 memset(new_chip, 0, sizeof(*new_chip));
214
215 new_chip->id = ++count;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000216 new_chip->chiph_exists = 1;
217 new_chip->name = path;
Kyösti Mälkki1a2a6ee2012-03-18 20:19:28 +0200218 new_chip->name_underscore = translate_name(new_chip->name, UNSLASH);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000219
220 struct stat st;
Martin Rothbec07532016-08-05 18:32:18 -0600221 char *chip_h = malloc(strlen(path) + 18);
Stefan Reinauer76c44ae2011-10-14 12:41:46 -0700222 sprintf(chip_h, "src/%s", path);
223 if ((stat(chip_h, &st) == -1) && (errno == ENOENT)) {
Patrick Georgi92bcaa22015-11-13 09:39:22 +0100224 /* root_complex gets away without a separate directory, but
225 * exists on on pretty much all AMD chipsets.
226 */
227 if (!strstr(path, "/root_complex")) {
Kyösti Mälkki6aeb4a22013-06-11 17:00:11 +0300228 fprintf(stderr, "ERROR: Chip component %s does not exist.\n",
229 path);
230 exit(1);
231 }
Stefan Reinauer76c44ae2011-10-14 12:41:46 -0700232 }
233
Martin Roth824255e2016-08-05 17:40:39 -0600234 sprintf(chip_h, "src/%s/chip.h", path);
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200235
Martin Roth824255e2016-08-05 17:40:39 -0600236 if ((stat(chip_h, &st) == -1) && (errno == ENOENT))
Martin Rothbec07532016-08-05 18:32:18 -0600237 new_chip->chiph_exists = 0;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000238
Patrick Georgi1f688802014-08-03 15:51:19 +0200239 free(chip_h);
Furquan Shaikh79e84122018-05-30 15:09:09 -0700240
241 new_chip->next = chip_head;
242 chip_head = new_chip;
243
Patrick Georgi114e7b22010-05-05 11:19:50 +0000244 return new_chip;
245}
246
Furquan Shaikh79e84122018-05-30 15:09:09 -0700247void add_header(struct chip *chip)
Martin Rothbec07532016-08-05 18:32:18 -0600248{
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200249 int include_exists = 0;
250 struct header *h = &headers;
251 while (h->next) {
Furquan Shaikh79e84122018-05-30 15:09:09 -0700252 int result = strcmp(chip->name, h->next->name);
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200253 if (result == 0) {
254 include_exists = 1;
255 break;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000256 }
Martin Rothbec07532016-08-05 18:32:18 -0600257 if (result < 0)
258 break;
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200259 h = h->next;
260 }
261 if (!include_exists) {
262 struct header *tmp = h->next;
263 h->next = malloc(sizeof(struct header));
264 memset(h->next, 0, sizeof(struct header));
Furquan Shaikh79e84122018-05-30 15:09:09 -0700265 h->next->chiph_exists = chip->chiph_exists;
266 h->next->name = chip->name;
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200267 h->next->next = tmp;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000268 }
269}
270
Martin Rothbec07532016-08-05 18:32:18 -0600271struct device *new_device(struct device *parent, struct device *busdev,
Furquan Shaikh79e84122018-05-30 15:09:09 -0700272 struct chip *chip, const int bus, const char *devnum,
273 int enabled)
Martin Rothbec07532016-08-05 18:32:18 -0600274{
Patrick Georgi68befd52010-05-05 12:05:25 +0000275 struct device *new_d = new_dev(parent, busdev);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000276 new_d->bustype = bus;
277
278 char *tmp;
Patrick Georgi1f688802014-08-03 15:51:19 +0200279 new_d->path_a = strtol(devnum, &tmp, 16);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000280 if (*tmp == '.') {
281 tmp++;
282 new_d->path_b = strtol(tmp, NULL, 16);
283 }
284
285 char *name = malloc(10);
286 sprintf(name, "_dev%d", new_d->id);
287 new_d->name = name;
Furquan Shaikh79e84122018-05-30 15:09:09 -0700288
Patrick Georgi114e7b22010-05-05 11:19:50 +0000289 new_d->enabled = enabled;
Furquan Shaikh79e84122018-05-30 15:09:09 -0700290 new_d->chip = chip;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000291
Patrick Georgi68befd52010-05-05 12:05:25 +0000292 if (parent->latestchild) {
293 parent->latestchild->next_sibling = new_d;
294 parent->latestchild->sibling = new_d;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000295 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000296 parent->latestchild = new_d;
297 if (!parent->children)
298 parent->children = new_d;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000299
300 lastdev->nextdev = new_d;
301 lastdev = new_d;
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200302
Martin Rothbec07532016-08-05 18:32:18 -0600303 switch (bus) {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200304 case PCI:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000305 new_d->path = ".type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x%x,%d)}}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200306 break;
307
308 case PNP:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000309 new_d->path = ".type=DEVICE_PATH_PNP,{.pnp={ .port = 0x%x, .device = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200310 break;
311
312 case I2C:
Duncan Laurieb7ce5fe2016-05-07 19:49:37 -0700313 new_d->path = ".type=DEVICE_PATH_I2C,{.i2c={ .device = 0x%x, .mode_10bit = %d }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200314 break;
315
316 case APIC:
Patrick Georgi114e7b22010-05-05 11:19:50 +0000317 new_d->path = ".type=DEVICE_PATH_APIC,{.apic={ .apic_id = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200318 break;
319
Stefan Reinauer0aa37c42013-02-12 15:20:54 -0800320 case CPU_CLUSTER:
321 new_d->path = ".type=DEVICE_PATH_CPU_CLUSTER,{.cpu_cluster={ .cluster = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200322 break;
323
Aaron Durbinffda804b2014-09-03 12:40:15 -0500324 case CPU:
325 new_d->path = ".type=DEVICE_PATH_CPU,{.cpu={ .id = 0x%x }}";
326 break;
327
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800328 case DOMAIN:
329 new_d->path = ".type=DEVICE_PATH_DOMAIN,{.domain={ .domain = 0x%x }}";
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200330 break;
331
332 case IOAPIC:
333 new_d->path = ".type=DEVICE_PATH_IOAPIC,{.ioapic={ .ioapic_id = 0x%x }}";
334 break;
Duncan Laurie4650f5b2016-05-07 20:01:34 -0700335
336 case GENERIC:
337 new_d->path = ".type=DEVICE_PATH_GENERIC,{.generic={ .id = 0x%x, .subid = 0x%x }}";
338 break;
Furquan Shaikhe6700292017-02-11 00:50:38 -0800339
340 case SPI:
341 new_d->path = ".type=DEVICE_PATH_SPI,{.spi={ .cs = 0x%x }}";
342 break;
343
Duncan Lauriebae9f852018-05-07 14:18:13 -0700344 case USB:
345 new_d->path = ".type=DEVICE_PATH_USB,{.usb={ .port_type = %d, .port_id = %d }}";
346 break;
347
Justin TerAvestca2ed9f2018-01-17 16:36:30 -0800348 case MMIO:
349 new_d->path = ".type=DEVICE_PATH_MMIO,{.mmio={ .addr = 0x%x }}";
350 break;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000351 }
Justin TerAvestca2ed9f2018-01-17 16:36:30 -0800352
Patrick Georgi114e7b22010-05-05 11:19:50 +0000353 return new_d;
354}
355
Martin Rothbec07532016-08-05 18:32:18 -0600356void alias_siblings(struct device *d)
357{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000358 while (d) {
359 int link = 0;
360 struct device *cmp = d->next_sibling;
Martin Rothbec07532016-08-05 18:32:18 -0600361 while (cmp && (cmp->bus == d->bus) && (cmp->path_a == d->path_a)
362 && (cmp->path_b == d->path_b)) {
Furquan Shaikh79e84122018-05-30 15:09:09 -0700363 if (!cmp->used) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000364 if (device_match(d, cmp)) {
365 d->multidev = 1;
366
Patrick Georgi114e7b22010-05-05 11:19:50 +0000367 cmp->id = d->id;
368 cmp->name = d->name;
369 cmp->used = 1;
370 cmp->link = ++link;
371 }
372 }
373 cmp = cmp->next_sibling;
374 }
375 d = d->next_sibling;
376 }
377}
378
Martin Rothbec07532016-08-05 18:32:18 -0600379void add_resource(struct device *dev, int type, int index, int base)
380{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000381 struct resource *r = malloc(sizeof(struct resource));
Martin Rothbec07532016-08-05 18:32:18 -0600382 memset(r, 0, sizeof(struct resource));
Patrick Georgi114e7b22010-05-05 11:19:50 +0000383 r->type = type;
384 r->index = index;
385 r->base = base;
Patrick Georgi68befd52010-05-05 12:05:25 +0000386 if (dev->res) {
387 struct resource *head = dev->res;
Martin Rothbec07532016-08-05 18:32:18 -0600388 while (head->next)
389 head = head->next;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000390 head->next = r;
391 } else {
Patrick Georgi68befd52010-05-05 12:05:25 +0000392 dev->res = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000393 }
Patrick Georgi68befd52010-05-05 12:05:25 +0000394 dev->rescnt++;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000395}
396
Furquan Shaikh79e84122018-05-30 15:09:09 -0700397void add_register(struct chip *chip, char *name, char *val)
Martin Rothbec07532016-08-05 18:32:18 -0600398{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000399 struct reg *r = malloc(sizeof(struct reg));
Martin Rothbec07532016-08-05 18:32:18 -0600400 memset(r, 0, sizeof(struct reg));
Patrick Georgi114e7b22010-05-05 11:19:50 +0000401 r->key = name;
402 r->value = val;
Furquan Shaikh79e84122018-05-30 15:09:09 -0700403 if (chip->reg) {
404 struct reg *head = chip->reg;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000405 // sorting to be equal to sconfig's behaviour
406 int sort = strcmp(r->key, head->key);
407 if (sort == 0) {
408 printf("ERROR: duplicate 'register' key.\n");
409 exit(1);
410 }
Martin Rothbec07532016-08-05 18:32:18 -0600411 if (sort < 0) {
Patrick Georgi114e7b22010-05-05 11:19:50 +0000412 r->next = head;
Furquan Shaikh79e84122018-05-30 15:09:09 -0700413 chip->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000414 } else {
Martin Rothbec07532016-08-05 18:32:18 -0600415 while ((head->next)
416 && (strcmp(head->next->key, r->key) < 0))
417 head = head->next;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000418 r->next = head->next;
419 head->next = r;
420 }
421 } else {
Furquan Shaikh79e84122018-05-30 15:09:09 -0700422 chip->reg = r;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000423 }
424}
425
Martin Rothbec07532016-08-05 18:32:18 -0600426void add_pci_subsystem_ids(struct device *dev, int vendor, int device,
427 int inherit)
Sven Schnelle270a9082011-03-01 19:58:15 +0000428{
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800429 if (dev->bustype != PCI && dev->bustype != DOMAIN) {
Sven Schnelle270a9082011-03-01 19:58:15 +0000430 printf("ERROR: 'subsystem' only allowed for PCI devices\n");
431 exit(1);
432 }
433
434 dev->subsystem_vendor = vendor;
435 dev->subsystem_device = device;
436 dev->inherit_subsystem = inherit;
437}
438
Martin Rothbec07532016-08-05 18:32:18 -0600439void add_ioapic_info(struct device *dev, int apicid, const char *_srcpin,
440 int irqpin)
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200441{
442
443 int srcpin;
444
Martin Rothbec07532016-08-05 18:32:18 -0600445 if (!_srcpin || strlen(_srcpin) < 4 || strncasecmp(_srcpin, "INT", 3) ||
446 _srcpin[3] < 'A' || _srcpin[3] > 'D') {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200447 printf("ERROR: malformed ioapic_irq args: %s\n", _srcpin);
448 exit(1);
449 }
450
451 srcpin = _srcpin[3] - 'A';
452
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800453 if (dev->bustype != PCI && dev->bustype != DOMAIN) {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200454 printf("ERROR: ioapic config only allowed for PCI devices\n");
455 exit(1);
456 }
457
458 if (srcpin > 3) {
Patrick Georgi116327e2012-07-20 12:47:06 +0200459 printf("ERROR: srcpin '%d' invalid\n", srcpin);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200460 exit(1);
461 }
462 dev->pci_irq_info[srcpin].ioapic_irq_pin = irqpin;
463 dev->pci_irq_info[srcpin].ioapic_dst_id = apicid;
464}
465
Furquan Shaikh79e84122018-05-30 15:09:09 -0700466static void pass0(FILE *fil, struct device *ptr)
Martin Rothbec07532016-08-05 18:32:18 -0600467{
Furquan Shaikh79e84122018-05-30 15:09:09 -0700468 if (ptr->id == 0)
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500469 fprintf(fil, "DEVTREE_CONST struct bus %s_links[];\n",
Martin Rothbec07532016-08-05 18:32:18 -0600470 ptr->name);
Stefan Reinauer57879c92012-07-31 16:47:25 -0700471
Furquan Shaikh79e84122018-05-30 15:09:09 -0700472 if ((ptr->id != 0) && (!ptr->used)) {
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500473 fprintf(fil, "DEVTREE_CONST static struct device %s;\n",
Martin Rothbec07532016-08-05 18:32:18 -0600474 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000475 if (ptr->rescnt > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600476 fprintf(fil,
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500477 "DEVTREE_CONST struct resource %s_res[];\n",
Martin Rothbec07532016-08-05 18:32:18 -0600478 ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000479 if (ptr->children || ptr->multidev)
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500480 fprintf(fil, "DEVTREE_CONST struct bus %s_links[];\n",
Martin Rothbec07532016-08-05 18:32:18 -0600481 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000482 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000483}
484
Furquan Shaikh79e84122018-05-30 15:09:09 -0700485static void pass1(FILE *fil, struct device *ptr)
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200486{
487 int pin;
Furquan Shaikh79e84122018-05-30 15:09:09 -0700488
489 if (!ptr->used) {
Stefan Reinauerdf61dd22010-08-09 12:02:00 +0000490 if (ptr->id != 0)
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200491 fprintf(fil, "static ");
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500492 fprintf(fil, "DEVTREE_CONST struct device %s = {\n",
Martin Rothbec07532016-08-05 18:32:18 -0600493 ptr->name);
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500494 fprintf(fil, "#if !DEVTREE_EARLY\n");
Martin Rothbec07532016-08-05 18:32:18 -0600495 fprintf(fil, "\t.ops = %s,\n", (ptr->ops) ? (ptr->ops) : "0");
Stefan Reinauer57879c92012-07-31 16:47:25 -0700496 fprintf(fil, "#endif\n");
Martin Rothbec07532016-08-05 18:32:18 -0600497 fprintf(fil, "\t.bus = &%s_links[%d],\n", ptr->bus->name,
498 ptr->bus->link);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000499 fprintf(fil, "\t.path = {");
500 fprintf(fil, ptr->path, ptr->path_a, ptr->path_b);
501 fprintf(fil, "},\n");
502 fprintf(fil, "\t.enabled = %d,\n", ptr->enabled);
503 fprintf(fil, "\t.on_mainboard = 1,\n");
Sven Schnelle270a9082011-03-01 19:58:15 +0000504 if (ptr->subsystem_vendor > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600505 fprintf(fil, "\t.subsystem_vendor = 0x%04x,\n",
506 ptr->subsystem_vendor);
Sven Schnelle270a9082011-03-01 19:58:15 +0000507
Martin Rothbec07532016-08-05 18:32:18 -0600508 for (pin = 0; pin < 4; pin++) {
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200509 if (ptr->pci_irq_info[pin].ioapic_irq_pin > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600510 fprintf(fil, "\t.pci_irq_info[%d].ioapic_irq_pin = %d,\n",
511 pin, ptr->pci_irq_info[pin].ioapic_irq_pin);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200512
513 if (ptr->pci_irq_info[pin].ioapic_dst_id > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600514 fprintf(fil, "\t.pci_irq_info[%d].ioapic_dst_id = %d,\n",
515 pin, ptr->pci_irq_info[pin].ioapic_dst_id);
Sven Schnelle0fa50a12012-06-21 22:19:48 +0200516 }
517
Sven Schnelle270a9082011-03-01 19:58:15 +0000518 if (ptr->subsystem_device > 0)
Martin Rothbec07532016-08-05 18:32:18 -0600519 fprintf(fil, "\t.subsystem_device = 0x%04x,\n",
520 ptr->subsystem_device);
Sven Schnelle270a9082011-03-01 19:58:15 +0000521
Patrick Georgi114e7b22010-05-05 11:19:50 +0000522 if (ptr->rescnt > 0) {
Martin Rothbec07532016-08-05 18:32:18 -0600523 fprintf(fil, "\t.resource_list = &%s_res[0],\n",
524 ptr->name);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000525 }
Myles Watson894a3472010-06-09 22:41:35 +0000526 if (ptr->children || ptr->multidev)
Martin Rothbec07532016-08-05 18:32:18 -0600527 fprintf(fil, "\t.link_list = &%s_links[0],\n",
528 ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000529 else
Patrick Georgi2dbfcb72012-05-30 16:26:30 +0200530 fprintf(fil, "\t.link_list = NULL,\n");
Patrick Georgi114e7b22010-05-05 11:19:50 +0000531 if (ptr->sibling)
532 fprintf(fil, "\t.sibling = &%s,\n", ptr->sibling->name);
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500533 fprintf(fil, "#if !DEVTREE_EARLY\n");
Martin Rothbec07532016-08-05 18:32:18 -0600534 fprintf(fil, "\t.chip_ops = &%s_ops,\n",
535 ptr->chip->name_underscore);
Furquan Shaikh79e84122018-05-30 15:09:09 -0700536 if (ptr->chip == &mainboard)
Kyösti Mälkkia93c3fe2012-10-09 22:28:56 +0300537 fprintf(fil, "\t.name = mainboard_name,\n");
Kyösti Mälkkiaada2e12012-10-07 15:08:32 +0200538 fprintf(fil, "#endif\n");
539 if (ptr->chip->chiph_exists)
Martin Rothbec07532016-08-05 18:32:18 -0600540 fprintf(fil, "\t.chip_info = &%s_info_%d,\n",
541 ptr->chip->name_underscore, ptr->chip->id);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000542 if (ptr->nextdev)
543 fprintf(fil, "\t.next=&%s\n", ptr->nextdev->name);
544 fprintf(fil, "};\n");
545 }
Myles Watsonc25cc112010-05-21 14:33:48 +0000546 if (ptr->rescnt > 0) {
Martin Rothbec07532016-08-05 18:32:18 -0600547 int i = 1;
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500548 fprintf(fil, "DEVTREE_CONST struct resource %s_res[] = {\n",
Martin Rothbec07532016-08-05 18:32:18 -0600549 ptr->name);
Myles Watsonc25cc112010-05-21 14:33:48 +0000550 struct resource *r = ptr->res;
551 while (r) {
Martin Rothbec07532016-08-05 18:32:18 -0600552 fprintf(fil,
553 "\t\t{ .flags=IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_");
554 if (r->type == IRQ)
555 fprintf(fil, "IRQ");
556 if (r->type == DRQ)
557 fprintf(fil, "DRQ");
558 if (r->type == IO)
559 fprintf(fil, "IO");
560 fprintf(fil, ", .index=0x%x, .base=0x%x,", r->index,
561 r->base);
Myles Watsonc25cc112010-05-21 14:33:48 +0000562 if (r->next)
Martin Rothbec07532016-08-05 18:32:18 -0600563 fprintf(fil, ".next=&%s_res[%d]},\n", ptr->name,
564 i++);
Myles Watsonc25cc112010-05-21 14:33:48 +0000565 else
566 fprintf(fil, ".next=NULL },\n");
567 r = r->next;
568 }
569 fprintf(fil, "\t };\n");
570 }
Furquan Shaikh79e84122018-05-30 15:09:09 -0700571 if (!ptr->used && (ptr->children || ptr->multidev)) {
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500572 fprintf(fil, "DEVTREE_CONST struct bus %s_links[] = {\n",
Martin Rothbec07532016-08-05 18:32:18 -0600573 ptr->name);
Myles Watson894a3472010-06-09 22:41:35 +0000574 if (ptr->multidev) {
575 struct device *d = ptr;
576 while (d) {
577 if (device_match(d, ptr)) {
578 fprintf(fil, "\t\t[%d] = {\n", d->link);
Martin Rothbec07532016-08-05 18:32:18 -0600579 fprintf(fil, "\t\t\t.link_num = %d,\n",
580 d->link);
581 fprintf(fil, "\t\t\t.dev = &%s,\n",
582 d->name);
Myles Watson894a3472010-06-09 22:41:35 +0000583 if (d->children)
Martin Rothbec07532016-08-05 18:32:18 -0600584 fprintf(fil,
585 "\t\t\t.children = &%s,\n",
586 d->children->name);
587 if (d->next_sibling
588 && device_match(d->next_sibling,
589 ptr))
590 fprintf(fil,
591 "\t\t\t.next=&%s_links[%d],\n",
592 d->name, d->link + 1);
Myles Watson894a3472010-06-09 22:41:35 +0000593 else
Martin Rothbec07532016-08-05 18:32:18 -0600594 fprintf(fil,
595 "\t\t\t.next = NULL,\n");
Myles Watson894a3472010-06-09 22:41:35 +0000596 fprintf(fil, "\t\t},\n");
597 }
598 d = d->next_sibling;
599 }
600 } else {
601 if (ptr->children) {
602 fprintf(fil, "\t\t[0] = {\n");
603 fprintf(fil, "\t\t\t.link_num = 0,\n");
604 fprintf(fil, "\t\t\t.dev = &%s,\n", ptr->name);
Martin Rothbec07532016-08-05 18:32:18 -0600605 fprintf(fil, "\t\t\t.children = &%s,\n",
606 ptr->children->name);
Myles Watson894a3472010-06-09 22:41:35 +0000607 fprintf(fil, "\t\t\t.next = NULL,\n");
608 fprintf(fil, "\t\t},\n");
609 }
610 }
611 fprintf(fil, "\t};\n");
612 }
Patrick Georgi114e7b22010-05-05 11:19:50 +0000613}
614
Furquan Shaikh79e84122018-05-30 15:09:09 -0700615static void walk_device_tree(FILE *fil, struct device *ptr,
616 void (*func)(FILE *, struct device *),
Martin Rothbec07532016-08-05 18:32:18 -0600617 struct device *chips)
618{
Patrick Georgi114e7b22010-05-05 11:19:50 +0000619 do {
620 func(fil, ptr);
621 ptr = ptr->next_sibling;
622 } while (ptr);
623}
624
Furquan Shaikh79e84122018-05-30 15:09:09 -0700625static void emit_chips(FILE *fil)
626{
627 struct chip *chip;
628
629 for (chip = chip_head; chip; chip = chip->next) {
630 if (!chip->chiph_exists)
631 continue;
632
633 if (chip->reg) {
634 fprintf(fil,
635 "DEVTREE_CONST struct %s_config %s_info_%d = {\n",
636 chip->name_underscore, chip->name_underscore,
637 chip->id);
638 struct reg *r = chip->reg;
639 while (r) {
640 fprintf(fil, "\t.%s = %s,\n", r->key, r->value);
641 r = r->next;
642 }
643 fprintf(fil, "};\n\n");
644 } else {
645 fprintf(fil,
646 "DEVTREE_CONST struct %s_config %s_info_%d = { };\n",
647 chip->name_underscore, chip->name_underscore,
648 chip->id);
649 }
650 }
651}
652
653static void inherit_subsystem_ids(FILE *file, struct device *dev)
Sven Schnelle270a9082011-03-01 19:58:15 +0000654{
655 struct device *p;
Sven Schnelle270a9082011-03-01 19:58:15 +0000656
657 if (dev->subsystem_vendor != -1 && dev->subsystem_device != -1) {
658 /* user already gave us a subsystem vendor/device */
659 return;
660 }
661
Martin Rothbec07532016-08-05 18:32:18 -0600662 for (p = dev; p && p != p->parent; p = p->parent) {
Sven Schnelle270a9082011-03-01 19:58:15 +0000663
Stefan Reinauer4aff4452013-02-12 14:17:15 -0800664 if (p->bustype != PCI && p->bustype != DOMAIN)
Sven Schnelle270a9082011-03-01 19:58:15 +0000665 continue;
666
667 if (p->inherit_subsystem) {
668 dev->subsystem_vendor = p->subsystem_vendor;
669 dev->subsystem_device = p->subsystem_device;
670 break;
671 }
672 }
673}
674
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200675static void usage(void)
676{
Martin Rothc9c27bb2016-08-05 18:15:06 -0600677 printf("usage: sconfig devicetree_file output_file\n");
Martin Rothbec07532016-08-05 18:32:18 -0600678 exit(1);
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200679}
680
Martin Roth32051702015-11-24 12:34:16 -0700681enum {
Martin Rothc9c27bb2016-08-05 18:15:06 -0600682 DEVICEFILE_ARG = 1,
Martin Rothbec07532016-08-05 18:32:18 -0600683 OUTPUTFILE_ARG
684};
Martin Roth32051702015-11-24 12:34:16 -0700685
Martin Rothc9c27bb2016-08-05 18:15:06 -0600686#define ARG_COUNT 3
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200687
Martin Rothbec07532016-08-05 18:32:18 -0600688int main(int argc, char **argv)
689{
Martin Roth824255e2016-08-05 17:40:39 -0600690 if (argc != ARG_COUNT)
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200691 usage();
692
Martin Roth25f8a4f2016-08-05 15:46:56 -0600693 char *devtree = argv[DEVICEFILE_ARG];
694 char *outputc = argv[OUTPUTFILE_ARG];
Patrick Georgi114e7b22010-05-05 11:19:50 +0000695
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200696 headers.next = 0;
Patrick Georgi114e7b22010-05-05 11:19:50 +0000697
698 FILE *filec = fopen(devtree, "r");
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000699 if (!filec) {
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000700 perror(NULL);
701 exit(1);
702 }
703
Patrick Georgi114e7b22010-05-05 11:19:50 +0000704 yyrestart(filec);
705
Patrick Georgi68befd52010-05-05 12:05:25 +0000706 lastdev = head = &root;
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000707
Patrick Georgi114e7b22010-05-05 11:19:50 +0000708 yyparse();
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000709
Patrick Georgi114e7b22010-05-05 11:19:50 +0000710 fclose(filec);
711
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200712 FILE *autogen = fopen(outputc, "w");
713 if (!autogen) {
Martin Rothbec07532016-08-05 18:32:18 -0600714 fprintf(stderr, "Could not open file '%s' for writing: ",
715 outputc);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000716 perror(NULL);
717 exit(1);
718 }
719
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200720 struct header *h;
Martin Roth824255e2016-08-05 17:40:39 -0600721 fprintf(autogen, "#include <device/device.h>\n");
722 fprintf(autogen, "#include <device/pci.h>\n");
723 h = &headers;
724 while (h->next) {
725 h = h->next;
726 if (h->chiph_exists)
727 fprintf(autogen, "#include \"%s/chip.h\"\n", h->name);
Patrick Georgi114e7b22010-05-05 11:19:50 +0000728 }
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500729 fprintf(autogen, "\n#if !DEVTREE_EARLY\n");
Martin Rothbec07532016-08-05 18:32:18 -0600730 fprintf(autogen,
731 "__attribute__((weak)) struct chip_operations mainboard_ops = {};\n");
Martin Roth824255e2016-08-05 17:40:39 -0600732 h = &headers;
733 while (h->next) {
734 h = h->next;
735 char *name_underscore = translate_name(h->name, UNSLASH);
Martin Rothbec07532016-08-05 18:32:18 -0600736 fprintf(autogen,
737 "__attribute__((weak)) struct chip_operations %s_ops = {};\n",
738 name_underscore);
Martin Roth824255e2016-08-05 17:40:39 -0600739 free(name_underscore);
740 }
741 fprintf(autogen, "#endif\n");
742
Furquan Shaikh79e84122018-05-30 15:09:09 -0700743 emit_chips(autogen);
744
Martin Roth824255e2016-08-05 17:40:39 -0600745 walk_device_tree(autogen, &root, inherit_subsystem_ids, NULL);
746 fprintf(autogen, "\n/* pass 0 */\n");
747 walk_device_tree(autogen, &root, pass0, NULL);
748 fprintf(autogen, "\n/* pass 1 */\n"
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500749 "DEVTREE_CONST struct device * DEVTREE_CONST last_dev = &%s;\n",
Martin Rothbec07532016-08-05 18:32:18 -0600750 lastdev->name);
Martin Roth824255e2016-08-05 17:40:39 -0600751 walk_device_tree(autogen, &root, pass1, NULL);
Sven Schnelle270a9082011-03-01 19:58:15 +0000752
Kyösti Mälkki472d9022011-12-05 20:33:55 +0200753 fclose(autogen);
Stefan Reinauer7c1f6b82010-08-16 18:21:56 +0000754
Patrick Georgi114e7b22010-05-05 11:19:50 +0000755 return 0;
756}