2010-05-05 13:19:50 +02:00
|
|
|
/*
|
|
|
|
* sconfig, coreboot device tree compiler
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010 coresystems GmbH
|
2016-05-07 10:11:14 +02:00
|
|
|
* written by Patrick Georgi <patrick@georgi-clan.de>
|
2010-05-05 13:19:50 +02:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; version 2 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
2012-05-30 16:26:30 +02:00
|
|
|
#include <ctype.h>
|
2010-05-05 13:19:50 +02:00
|
|
|
#include "sconfig.h"
|
|
|
|
#include "sconfig.tab.h"
|
|
|
|
|
2010-07-15 17:59:07 +02:00
|
|
|
extern int linenum;
|
|
|
|
|
2010-05-05 13:19:50 +02:00
|
|
|
struct device *head, *lastdev;
|
|
|
|
|
|
|
|
struct header headers;
|
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
static struct chip *chip_head;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is intentionally shared between chip and device structure ids because it
|
|
|
|
* is easier to track the order of parsing for chip and device.
|
|
|
|
*/
|
|
|
|
static int count = 0;
|
2010-05-05 13:19:50 +02:00
|
|
|
|
2012-03-18 19:19:28 +01:00
|
|
|
typedef enum {
|
|
|
|
UNSLASH,
|
|
|
|
SPLIT_1ST,
|
|
|
|
TO_LOWER,
|
|
|
|
TO_UPPER,
|
|
|
|
} translate_t;
|
|
|
|
|
2010-05-05 13:19:50 +02:00
|
|
|
static struct device root;
|
2018-05-31 00:09:09 +02:00
|
|
|
static struct chip mainboard = {
|
2010-05-05 13:19:50 +02:00
|
|
|
.name = "mainboard",
|
|
|
|
.name_underscore = "mainboard",
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct device root = {
|
|
|
|
.name = "dev_root",
|
|
|
|
.id = 0,
|
|
|
|
.chip = &mainboard,
|
|
|
|
.path = " .type = DEVICE_PATH_ROOT ",
|
|
|
|
.ops = "&default_dev_ops_root",
|
|
|
|
.parent = &root,
|
|
|
|
.bus = &root,
|
|
|
|
.enabled = 1
|
|
|
|
};
|
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
static struct queue {
|
|
|
|
void *data;
|
|
|
|
struct queue *next;
|
|
|
|
struct queue *prev;
|
|
|
|
} *q;
|
|
|
|
|
|
|
|
struct queue *new_queue_entry(void *data)
|
|
|
|
{
|
|
|
|
struct queue *e = malloc(sizeof(*e));
|
|
|
|
|
|
|
|
if (!e) {
|
|
|
|
fprintf(stderr, "%s: malloc failure!\n", __func__);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
e->data = data;
|
|
|
|
e->next = e->prev = e;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
void chip_enqueue_tail(void *data)
|
|
|
|
{
|
|
|
|
struct queue *tmp = new_queue_entry(data);
|
|
|
|
|
|
|
|
if (!q) {
|
|
|
|
q = tmp;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
q->prev->next = tmp;
|
|
|
|
tmp->prev = q->prev;
|
|
|
|
q->prev = tmp;
|
|
|
|
tmp->next = q;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *chip_dequeue_tail(void)
|
|
|
|
{
|
|
|
|
struct queue *tmp = q->prev;
|
|
|
|
void *data;
|
|
|
|
|
|
|
|
if (tmp == q)
|
|
|
|
q = NULL;
|
|
|
|
else {
|
|
|
|
tmp->prev->next = q;
|
|
|
|
q->prev = tmp->prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
data = tmp->data;
|
|
|
|
free(tmp);
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
static struct device *new_dev(struct device *parent, struct device *bus)
|
|
|
|
{
|
2010-05-05 13:19:50 +02:00
|
|
|
struct device *dev = malloc(sizeof(struct device));
|
|
|
|
memset(dev, 0, sizeof(struct device));
|
2018-05-31 00:09:09 +02:00
|
|
|
dev->id = ++count;
|
2010-05-05 14:05:25 +02:00
|
|
|
dev->parent = parent;
|
|
|
|
dev->bus = bus;
|
2011-03-01 20:58:15 +01:00
|
|
|
dev->subsystem_vendor = -1;
|
|
|
|
dev->subsystem_device = -1;
|
2010-05-05 13:19:50 +02:00
|
|
|
head->next = dev;
|
|
|
|
head = dev;
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
static int device_match(struct device *a, struct device *b)
|
|
|
|
{
|
|
|
|
if ((a->bustype == b->bustype) && (a->bus == b->bus)
|
|
|
|
&& (a->path_a == b->path_a) && (a->path_b == b->path_b))
|
2010-05-05 13:19:50 +02:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
void fold_in(struct device *parent)
|
|
|
|
{
|
2010-05-05 13:19:50 +02:00
|
|
|
struct device *child = parent->children;
|
|
|
|
struct device *latest = 0;
|
|
|
|
while (child != latest) {
|
|
|
|
if (child->children) {
|
2016-08-06 02:32:18 +02:00
|
|
|
if (!latest)
|
|
|
|
latest = child->children;
|
2010-05-05 13:19:50 +02:00
|
|
|
parent->latestchild->next_sibling = child->children;
|
|
|
|
parent->latestchild = child->latestchild;
|
|
|
|
}
|
|
|
|
child = child->next_sibling;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
int yywrap(void)
|
|
|
|
{
|
2010-05-05 13:19:50 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
void yyerror(char const *str)
|
2010-05-05 13:19:50 +02:00
|
|
|
{
|
2010-08-16 20:21:56 +02:00
|
|
|
extern char *yytext;
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(stderr, "line %d: %s: %s\n", linenum + 1, yytext, str);
|
2010-08-16 20:21:56 +02:00
|
|
|
exit(1);
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
void postprocess_devtree(void)
|
|
|
|
{
|
2010-05-05 13:19:50 +02:00
|
|
|
root.next_sibling = root.children;
|
2018-05-31 00:09:09 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since root is statically created we need to call fold_in explicitly
|
|
|
|
* here to have the next_sibling and latestchild setup correctly.
|
|
|
|
*/
|
|
|
|
fold_in(&root);
|
2010-05-05 13:19:50 +02:00
|
|
|
|
|
|
|
struct device *dev = &root;
|
|
|
|
while (dev) {
|
2018-05-31 00:09:09 +02:00
|
|
|
/* skip functions of the same device in sibling chain */
|
2016-08-06 02:32:18 +02:00
|
|
|
while (dev->sibling && dev->sibling->used)
|
|
|
|
dev->sibling = dev->sibling->sibling;
|
2010-05-05 13:19:50 +02:00
|
|
|
/* skip duplicate function elements in nextdev chain */
|
2016-08-06 02:32:18 +02:00
|
|
|
while (dev->nextdev && dev->nextdev->used)
|
|
|
|
dev->nextdev = dev->nextdev->nextdev;
|
2010-05-05 13:19:50 +02:00
|
|
|
dev = dev->next_sibling;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
char *translate_name(const char *str, translate_t mode)
|
2011-12-05 19:33:55 +01:00
|
|
|
{
|
2012-03-18 19:19:28 +01:00
|
|
|
char *b, *c;
|
|
|
|
b = c = strdup(str);
|
|
|
|
while (c && *c) {
|
|
|
|
if ((mode == SPLIT_1ST) && (*c == '/')) {
|
|
|
|
*c = 0;
|
|
|
|
break;
|
|
|
|
}
|
2016-08-06 02:32:18 +02:00
|
|
|
if (*c == '/')
|
|
|
|
*c = '_';
|
|
|
|
if (*c == '-')
|
|
|
|
*c = '_';
|
2012-03-18 19:19:28 +01:00
|
|
|
if (mode == TO_UPPER)
|
2011-12-05 19:33:55 +01:00
|
|
|
*c = toupper(*c);
|
2012-03-18 19:19:28 +01:00
|
|
|
if (mode == TO_LOWER)
|
|
|
|
*c = tolower(*c);
|
|
|
|
c++;
|
2011-12-05 19:33:55 +01:00
|
|
|
}
|
2012-03-18 19:19:28 +01:00
|
|
|
return b;
|
2011-12-05 19:33:55 +01:00
|
|
|
}
|
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
struct chip *new_chip(char *path)
|
2016-08-06 02:32:18 +02:00
|
|
|
{
|
2018-05-31 00:09:09 +02:00
|
|
|
struct chip *new_chip = malloc(sizeof(*new_chip));
|
|
|
|
if (!new_chip) {
|
|
|
|
fprintf(stderr, "%s: malloc failure!\n", __func__);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(new_chip, 0, sizeof(*new_chip));
|
|
|
|
|
|
|
|
new_chip->id = ++count;
|
2010-05-05 13:19:50 +02:00
|
|
|
new_chip->chiph_exists = 1;
|
|
|
|
new_chip->name = path;
|
2012-03-18 19:19:28 +01:00
|
|
|
new_chip->name_underscore = translate_name(new_chip->name, UNSLASH);
|
2010-05-05 13:19:50 +02:00
|
|
|
|
|
|
|
struct stat st;
|
2016-08-06 02:32:18 +02:00
|
|
|
char *chip_h = malloc(strlen(path) + 18);
|
2011-10-14 21:41:46 +02:00
|
|
|
sprintf(chip_h, "src/%s", path);
|
|
|
|
if ((stat(chip_h, &st) == -1) && (errno == ENOENT)) {
|
2015-11-13 09:39:22 +01:00
|
|
|
/* root_complex gets away without a separate directory, but
|
|
|
|
* exists on on pretty much all AMD chipsets.
|
|
|
|
*/
|
|
|
|
if (!strstr(path, "/root_complex")) {
|
2013-06-11 16:00:11 +02:00
|
|
|
fprintf(stderr, "ERROR: Chip component %s does not exist.\n",
|
|
|
|
path);
|
|
|
|
exit(1);
|
|
|
|
}
|
2011-10-14 21:41:46 +02:00
|
|
|
}
|
|
|
|
|
2016-08-06 01:40:39 +02:00
|
|
|
sprintf(chip_h, "src/%s/chip.h", path);
|
2011-12-05 19:33:55 +01:00
|
|
|
|
2016-08-06 01:40:39 +02:00
|
|
|
if ((stat(chip_h, &st) == -1) && (errno == ENOENT))
|
2016-08-06 02:32:18 +02:00
|
|
|
new_chip->chiph_exists = 0;
|
2010-05-05 13:19:50 +02:00
|
|
|
|
2014-08-03 15:51:19 +02:00
|
|
|
free(chip_h);
|
2018-05-31 00:09:09 +02:00
|
|
|
|
|
|
|
new_chip->next = chip_head;
|
|
|
|
chip_head = new_chip;
|
|
|
|
|
2010-05-05 13:19:50 +02:00
|
|
|
return new_chip;
|
|
|
|
}
|
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
void add_header(struct chip *chip)
|
2016-08-06 02:32:18 +02:00
|
|
|
{
|
2012-10-07 15:08:32 +02:00
|
|
|
int include_exists = 0;
|
|
|
|
struct header *h = &headers;
|
|
|
|
while (h->next) {
|
2018-05-31 00:09:09 +02:00
|
|
|
int result = strcmp(chip->name, h->next->name);
|
2012-10-07 15:08:32 +02:00
|
|
|
if (result == 0) {
|
|
|
|
include_exists = 1;
|
|
|
|
break;
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
2016-08-06 02:32:18 +02:00
|
|
|
if (result < 0)
|
|
|
|
break;
|
2012-10-07 15:08:32 +02:00
|
|
|
h = h->next;
|
|
|
|
}
|
|
|
|
if (!include_exists) {
|
|
|
|
struct header *tmp = h->next;
|
|
|
|
h->next = malloc(sizeof(struct header));
|
|
|
|
memset(h->next, 0, sizeof(struct header));
|
2018-05-31 00:09:09 +02:00
|
|
|
h->next->chiph_exists = chip->chiph_exists;
|
|
|
|
h->next->name = chip->name;
|
2012-10-07 15:08:32 +02:00
|
|
|
h->next->next = tmp;
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
struct device *new_device(struct device *parent, struct device *busdev,
|
2018-05-31 00:09:09 +02:00
|
|
|
struct chip *chip, const int bus, const char *devnum,
|
|
|
|
int enabled)
|
2016-08-06 02:32:18 +02:00
|
|
|
{
|
2010-05-05 14:05:25 +02:00
|
|
|
struct device *new_d = new_dev(parent, busdev);
|
2010-05-05 13:19:50 +02:00
|
|
|
new_d->bustype = bus;
|
|
|
|
|
|
|
|
char *tmp;
|
2014-08-03 15:51:19 +02:00
|
|
|
new_d->path_a = strtol(devnum, &tmp, 16);
|
2010-05-05 13:19:50 +02:00
|
|
|
if (*tmp == '.') {
|
|
|
|
tmp++;
|
|
|
|
new_d->path_b = strtol(tmp, NULL, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *name = malloc(10);
|
|
|
|
sprintf(name, "_dev%d", new_d->id);
|
|
|
|
new_d->name = name;
|
2018-05-31 00:09:09 +02:00
|
|
|
|
2010-05-05 13:19:50 +02:00
|
|
|
new_d->enabled = enabled;
|
2018-05-31 00:09:09 +02:00
|
|
|
new_d->chip = chip;
|
2010-05-05 13:19:50 +02:00
|
|
|
|
2010-05-05 14:05:25 +02:00
|
|
|
if (parent->latestchild) {
|
|
|
|
parent->latestchild->next_sibling = new_d;
|
|
|
|
parent->latestchild->sibling = new_d;
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
2010-05-05 14:05:25 +02:00
|
|
|
parent->latestchild = new_d;
|
|
|
|
if (!parent->children)
|
|
|
|
parent->children = new_d;
|
2010-05-05 13:19:50 +02:00
|
|
|
|
|
|
|
lastdev->nextdev = new_d;
|
|
|
|
lastdev = new_d;
|
2012-06-21 22:19:48 +02:00
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
switch (bus) {
|
2012-06-21 22:19:48 +02:00
|
|
|
case PCI:
|
2010-05-05 13:19:50 +02:00
|
|
|
new_d->path = ".type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x%x,%d)}}";
|
2012-06-21 22:19:48 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PNP:
|
2010-05-05 13:19:50 +02:00
|
|
|
new_d->path = ".type=DEVICE_PATH_PNP,{.pnp={ .port = 0x%x, .device = 0x%x }}";
|
2012-06-21 22:19:48 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case I2C:
|
2016-05-08 04:49:37 +02:00
|
|
|
new_d->path = ".type=DEVICE_PATH_I2C,{.i2c={ .device = 0x%x, .mode_10bit = %d }}";
|
2012-06-21 22:19:48 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case APIC:
|
2010-05-05 13:19:50 +02:00
|
|
|
new_d->path = ".type=DEVICE_PATH_APIC,{.apic={ .apic_id = 0x%x }}";
|
2012-06-21 22:19:48 +02:00
|
|
|
break;
|
|
|
|
|
2013-02-13 00:20:54 +01:00
|
|
|
case CPU_CLUSTER:
|
|
|
|
new_d->path = ".type=DEVICE_PATH_CPU_CLUSTER,{.cpu_cluster={ .cluster = 0x%x }}";
|
2012-06-21 22:19:48 +02:00
|
|
|
break;
|
|
|
|
|
2014-09-03 19:40:15 +02:00
|
|
|
case CPU:
|
|
|
|
new_d->path = ".type=DEVICE_PATH_CPU,{.cpu={ .id = 0x%x }}";
|
|
|
|
break;
|
|
|
|
|
2013-02-12 23:17:15 +01:00
|
|
|
case DOMAIN:
|
|
|
|
new_d->path = ".type=DEVICE_PATH_DOMAIN,{.domain={ .domain = 0x%x }}";
|
2012-06-21 22:19:48 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IOAPIC:
|
|
|
|
new_d->path = ".type=DEVICE_PATH_IOAPIC,{.ioapic={ .ioapic_id = 0x%x }}";
|
|
|
|
break;
|
2016-05-08 05:01:34 +02:00
|
|
|
|
|
|
|
case GENERIC:
|
|
|
|
new_d->path = ".type=DEVICE_PATH_GENERIC,{.generic={ .id = 0x%x, .subid = 0x%x }}";
|
|
|
|
break;
|
2017-02-11 09:50:38 +01:00
|
|
|
|
|
|
|
case SPI:
|
|
|
|
new_d->path = ".type=DEVICE_PATH_SPI,{.spi={ .cs = 0x%x }}";
|
|
|
|
break;
|
|
|
|
|
2018-05-07 23:18:13 +02:00
|
|
|
case USB:
|
|
|
|
new_d->path = ".type=DEVICE_PATH_USB,{.usb={ .port_type = %d, .port_id = %d }}";
|
|
|
|
break;
|
|
|
|
|
2018-01-18 01:36:30 +01:00
|
|
|
case MMIO:
|
|
|
|
new_d->path = ".type=DEVICE_PATH_MMIO,{.mmio={ .addr = 0x%x }}";
|
|
|
|
break;
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
2018-01-18 01:36:30 +01:00
|
|
|
|
2010-05-05 13:19:50 +02:00
|
|
|
return new_d;
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
void alias_siblings(struct device *d)
|
|
|
|
{
|
2010-05-05 13:19:50 +02:00
|
|
|
while (d) {
|
|
|
|
int link = 0;
|
|
|
|
struct device *cmp = d->next_sibling;
|
2016-08-06 02:32:18 +02:00
|
|
|
while (cmp && (cmp->bus == d->bus) && (cmp->path_a == d->path_a)
|
|
|
|
&& (cmp->path_b == d->path_b)) {
|
2018-05-31 00:09:09 +02:00
|
|
|
if (!cmp->used) {
|
2010-05-05 13:19:50 +02:00
|
|
|
if (device_match(d, cmp)) {
|
|
|
|
d->multidev = 1;
|
|
|
|
|
|
|
|
cmp->id = d->id;
|
|
|
|
cmp->name = d->name;
|
|
|
|
cmp->used = 1;
|
|
|
|
cmp->link = ++link;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cmp = cmp->next_sibling;
|
|
|
|
}
|
|
|
|
d = d->next_sibling;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
void add_resource(struct device *dev, int type, int index, int base)
|
|
|
|
{
|
2010-05-05 13:19:50 +02:00
|
|
|
struct resource *r = malloc(sizeof(struct resource));
|
2016-08-06 02:32:18 +02:00
|
|
|
memset(r, 0, sizeof(struct resource));
|
2010-05-05 13:19:50 +02:00
|
|
|
r->type = type;
|
|
|
|
r->index = index;
|
|
|
|
r->base = base;
|
2010-05-05 14:05:25 +02:00
|
|
|
if (dev->res) {
|
|
|
|
struct resource *head = dev->res;
|
2016-08-06 02:32:18 +02:00
|
|
|
while (head->next)
|
|
|
|
head = head->next;
|
2010-05-05 13:19:50 +02:00
|
|
|
head->next = r;
|
|
|
|
} else {
|
2010-05-05 14:05:25 +02:00
|
|
|
dev->res = r;
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
2010-05-05 14:05:25 +02:00
|
|
|
dev->rescnt++;
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
void add_register(struct chip *chip, char *name, char *val)
|
2016-08-06 02:32:18 +02:00
|
|
|
{
|
2010-05-05 13:19:50 +02:00
|
|
|
struct reg *r = malloc(sizeof(struct reg));
|
2016-08-06 02:32:18 +02:00
|
|
|
memset(r, 0, sizeof(struct reg));
|
2010-05-05 13:19:50 +02:00
|
|
|
r->key = name;
|
|
|
|
r->value = val;
|
2018-05-31 00:09:09 +02:00
|
|
|
if (chip->reg) {
|
|
|
|
struct reg *head = chip->reg;
|
2010-05-05 13:19:50 +02:00
|
|
|
// sorting to be equal to sconfig's behaviour
|
|
|
|
int sort = strcmp(r->key, head->key);
|
|
|
|
if (sort == 0) {
|
|
|
|
printf("ERROR: duplicate 'register' key.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2016-08-06 02:32:18 +02:00
|
|
|
if (sort < 0) {
|
2010-05-05 13:19:50 +02:00
|
|
|
r->next = head;
|
2018-05-31 00:09:09 +02:00
|
|
|
chip->reg = r;
|
2010-05-05 13:19:50 +02:00
|
|
|
} else {
|
2016-08-06 02:32:18 +02:00
|
|
|
while ((head->next)
|
|
|
|
&& (strcmp(head->next->key, r->key) < 0))
|
|
|
|
head = head->next;
|
2010-05-05 13:19:50 +02:00
|
|
|
r->next = head->next;
|
|
|
|
head->next = r;
|
|
|
|
}
|
|
|
|
} else {
|
2018-05-31 00:09:09 +02:00
|
|
|
chip->reg = r;
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
void add_pci_subsystem_ids(struct device *dev, int vendor, int device,
|
|
|
|
int inherit)
|
2011-03-01 20:58:15 +01:00
|
|
|
{
|
2013-02-12 23:17:15 +01:00
|
|
|
if (dev->bustype != PCI && dev->bustype != DOMAIN) {
|
2011-03-01 20:58:15 +01:00
|
|
|
printf("ERROR: 'subsystem' only allowed for PCI devices\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->subsystem_vendor = vendor;
|
|
|
|
dev->subsystem_device = device;
|
|
|
|
dev->inherit_subsystem = inherit;
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
void add_ioapic_info(struct device *dev, int apicid, const char *_srcpin,
|
|
|
|
int irqpin)
|
2012-06-21 22:19:48 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
int srcpin;
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
if (!_srcpin || strlen(_srcpin) < 4 || strncasecmp(_srcpin, "INT", 3) ||
|
|
|
|
_srcpin[3] < 'A' || _srcpin[3] > 'D') {
|
2012-06-21 22:19:48 +02:00
|
|
|
printf("ERROR: malformed ioapic_irq args: %s\n", _srcpin);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
srcpin = _srcpin[3] - 'A';
|
|
|
|
|
2013-02-12 23:17:15 +01:00
|
|
|
if (dev->bustype != PCI && dev->bustype != DOMAIN) {
|
2012-06-21 22:19:48 +02:00
|
|
|
printf("ERROR: ioapic config only allowed for PCI devices\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (srcpin > 3) {
|
2012-07-20 12:47:06 +02:00
|
|
|
printf("ERROR: srcpin '%d' invalid\n", srcpin);
|
2012-06-21 22:19:48 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dev->pci_irq_info[srcpin].ioapic_irq_pin = irqpin;
|
|
|
|
dev->pci_irq_info[srcpin].ioapic_dst_id = apicid;
|
|
|
|
}
|
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
static void pass0(FILE *fil, struct device *ptr)
|
2016-08-06 02:32:18 +02:00
|
|
|
{
|
2018-05-31 00:09:09 +02:00
|
|
|
if (ptr->id == 0)
|
2017-04-17 05:05:36 +02:00
|
|
|
fprintf(fil, "DEVTREE_CONST struct bus %s_links[];\n",
|
2016-08-06 02:32:18 +02:00
|
|
|
ptr->name);
|
Make the device tree available in the rom stage
We thought about two ways to do this change. The way we decided to try
was to
1. drop all ops from devices in romstage
2. constify all devices in romstage (make them read-only) so we can
compile static.c into romstage
3. the device tree "devices" can be used to read configuration from
the device tree (and nothing else, really)
4. the device tree devices are accessed through struct device * in
romstage only. device_t stays the typedef to int in romstage
5. Use the same static.c file in ramstage and romstage
We declare structs as follows:
ROMSTAGE_CONST struct bus dev_root_links[];
ROMSTAGE_CONST is const in romstage and empty in ramstage; This
forces all of the device tree into the text area.
So a struct looks like this:
static ROMSTAGE_CONST struct device _dev21 = {
#ifndef __PRE_RAM__
.ops = 0,
#endif
.bus = &_dev7_links[0],
.path = {.type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x1c,3)}}},
.enabled = 0,
.on_mainboard = 1,
.subsystem_vendor = 0x1ae0,
.subsystem_device = 0xc000,
.link_list = NULL,
.sibling = &_dev22,
#ifndef __PRE_RAM__
.chip_ops = &southbridge_intel_bd82x6x_ops,
#endif
.chip_info = &southbridge_intel_bd82x6x_info_10,
.next=&_dev22
};
Change-Id: I722454d8d3c40baf7df989f5a6891f6ba7db5727
Signed-off-by: Ronald G. Minnich <rminnich@chromium.org>
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/1398
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
2012-08-01 01:47:25 +02:00
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
if ((ptr->id != 0) && (!ptr->used)) {
|
2017-04-17 05:05:36 +02:00
|
|
|
fprintf(fil, "DEVTREE_CONST static struct device %s;\n",
|
2016-08-06 02:32:18 +02:00
|
|
|
ptr->name);
|
2010-05-21 16:33:48 +02:00
|
|
|
if (ptr->rescnt > 0)
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil,
|
2017-04-17 05:05:36 +02:00
|
|
|
"DEVTREE_CONST struct resource %s_res[];\n",
|
2016-08-06 02:32:18 +02:00
|
|
|
ptr->name);
|
2010-06-10 00:41:35 +02:00
|
|
|
if (ptr->children || ptr->multidev)
|
2017-04-17 05:05:36 +02:00
|
|
|
fprintf(fil, "DEVTREE_CONST struct bus %s_links[];\n",
|
2016-08-06 02:32:18 +02:00
|
|
|
ptr->name);
|
2010-05-21 16:33:48 +02:00
|
|
|
}
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
static void pass1(FILE *fil, struct device *ptr)
|
2012-06-21 22:19:48 +02:00
|
|
|
{
|
|
|
|
int pin;
|
2018-05-31 00:09:09 +02:00
|
|
|
|
|
|
|
if (!ptr->used) {
|
2010-08-09 14:02:00 +02:00
|
|
|
if (ptr->id != 0)
|
2012-05-30 16:26:30 +02:00
|
|
|
fprintf(fil, "static ");
|
2017-04-17 05:05:36 +02:00
|
|
|
fprintf(fil, "DEVTREE_CONST struct device %s = {\n",
|
2016-08-06 02:32:18 +02:00
|
|
|
ptr->name);
|
2017-04-17 05:05:36 +02:00
|
|
|
fprintf(fil, "#if !DEVTREE_EARLY\n");
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.ops = %s,\n", (ptr->ops) ? (ptr->ops) : "0");
|
Make the device tree available in the rom stage
We thought about two ways to do this change. The way we decided to try
was to
1. drop all ops from devices in romstage
2. constify all devices in romstage (make them read-only) so we can
compile static.c into romstage
3. the device tree "devices" can be used to read configuration from
the device tree (and nothing else, really)
4. the device tree devices are accessed through struct device * in
romstage only. device_t stays the typedef to int in romstage
5. Use the same static.c file in ramstage and romstage
We declare structs as follows:
ROMSTAGE_CONST struct bus dev_root_links[];
ROMSTAGE_CONST is const in romstage and empty in ramstage; This
forces all of the device tree into the text area.
So a struct looks like this:
static ROMSTAGE_CONST struct device _dev21 = {
#ifndef __PRE_RAM__
.ops = 0,
#endif
.bus = &_dev7_links[0],
.path = {.type=DEVICE_PATH_PCI,{.pci={ .devfn = PCI_DEVFN(0x1c,3)}}},
.enabled = 0,
.on_mainboard = 1,
.subsystem_vendor = 0x1ae0,
.subsystem_device = 0xc000,
.link_list = NULL,
.sibling = &_dev22,
#ifndef __PRE_RAM__
.chip_ops = &southbridge_intel_bd82x6x_ops,
#endif
.chip_info = &southbridge_intel_bd82x6x_info_10,
.next=&_dev22
};
Change-Id: I722454d8d3c40baf7df989f5a6891f6ba7db5727
Signed-off-by: Ronald G. Minnich <rminnich@chromium.org>
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/1398
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
2012-08-01 01:47:25 +02:00
|
|
|
fprintf(fil, "#endif\n");
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.bus = &%s_links[%d],\n", ptr->bus->name,
|
|
|
|
ptr->bus->link);
|
2010-05-05 13:19:50 +02:00
|
|
|
fprintf(fil, "\t.path = {");
|
|
|
|
fprintf(fil, ptr->path, ptr->path_a, ptr->path_b);
|
|
|
|
fprintf(fil, "},\n");
|
|
|
|
fprintf(fil, "\t.enabled = %d,\n", ptr->enabled);
|
|
|
|
fprintf(fil, "\t.on_mainboard = 1,\n");
|
2011-03-01 20:58:15 +01:00
|
|
|
if (ptr->subsystem_vendor > 0)
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.subsystem_vendor = 0x%04x,\n",
|
|
|
|
ptr->subsystem_vendor);
|
2011-03-01 20:58:15 +01:00
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
for (pin = 0; pin < 4; pin++) {
|
2012-06-21 22:19:48 +02:00
|
|
|
if (ptr->pci_irq_info[pin].ioapic_irq_pin > 0)
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.pci_irq_info[%d].ioapic_irq_pin = %d,\n",
|
|
|
|
pin, ptr->pci_irq_info[pin].ioapic_irq_pin);
|
2012-06-21 22:19:48 +02:00
|
|
|
|
|
|
|
if (ptr->pci_irq_info[pin].ioapic_dst_id > 0)
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.pci_irq_info[%d].ioapic_dst_id = %d,\n",
|
|
|
|
pin, ptr->pci_irq_info[pin].ioapic_dst_id);
|
2012-06-21 22:19:48 +02:00
|
|
|
}
|
|
|
|
|
2011-03-01 20:58:15 +01:00
|
|
|
if (ptr->subsystem_device > 0)
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.subsystem_device = 0x%04x,\n",
|
|
|
|
ptr->subsystem_device);
|
2011-03-01 20:58:15 +01:00
|
|
|
|
2010-05-05 13:19:50 +02:00
|
|
|
if (ptr->rescnt > 0) {
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.resource_list = &%s_res[0],\n",
|
|
|
|
ptr->name);
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
2010-06-10 00:41:35 +02:00
|
|
|
if (ptr->children || ptr->multidev)
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.link_list = &%s_links[0],\n",
|
|
|
|
ptr->name);
|
2010-06-10 00:41:35 +02:00
|
|
|
else
|
2012-05-30 16:26:30 +02:00
|
|
|
fprintf(fil, "\t.link_list = NULL,\n");
|
2010-05-05 13:19:50 +02:00
|
|
|
if (ptr->sibling)
|
|
|
|
fprintf(fil, "\t.sibling = &%s,\n", ptr->sibling->name);
|
2017-04-17 05:05:36 +02:00
|
|
|
fprintf(fil, "#if !DEVTREE_EARLY\n");
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.chip_ops = &%s_ops,\n",
|
|
|
|
ptr->chip->name_underscore);
|
2018-05-31 00:09:09 +02:00
|
|
|
if (ptr->chip == &mainboard)
|
2012-10-09 21:28:56 +02:00
|
|
|
fprintf(fil, "\t.name = mainboard_name,\n");
|
2012-10-07 15:08:32 +02:00
|
|
|
fprintf(fil, "#endif\n");
|
|
|
|
if (ptr->chip->chiph_exists)
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t.chip_info = &%s_info_%d,\n",
|
|
|
|
ptr->chip->name_underscore, ptr->chip->id);
|
2010-05-05 13:19:50 +02:00
|
|
|
if (ptr->nextdev)
|
|
|
|
fprintf(fil, "\t.next=&%s\n", ptr->nextdev->name);
|
|
|
|
fprintf(fil, "};\n");
|
|
|
|
}
|
2010-05-21 16:33:48 +02:00
|
|
|
if (ptr->rescnt > 0) {
|
2016-08-06 02:32:18 +02:00
|
|
|
int i = 1;
|
2017-04-17 05:05:36 +02:00
|
|
|
fprintf(fil, "DEVTREE_CONST struct resource %s_res[] = {\n",
|
2016-08-06 02:32:18 +02:00
|
|
|
ptr->name);
|
2010-05-21 16:33:48 +02:00
|
|
|
struct resource *r = ptr->res;
|
|
|
|
while (r) {
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil,
|
|
|
|
"\t\t{ .flags=IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_");
|
|
|
|
if (r->type == IRQ)
|
|
|
|
fprintf(fil, "IRQ");
|
|
|
|
if (r->type == DRQ)
|
|
|
|
fprintf(fil, "DRQ");
|
|
|
|
if (r->type == IO)
|
|
|
|
fprintf(fil, "IO");
|
|
|
|
fprintf(fil, ", .index=0x%x, .base=0x%x,", r->index,
|
|
|
|
r->base);
|
2010-05-21 16:33:48 +02:00
|
|
|
if (r->next)
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, ".next=&%s_res[%d]},\n", ptr->name,
|
|
|
|
i++);
|
2010-05-21 16:33:48 +02:00
|
|
|
else
|
|
|
|
fprintf(fil, ".next=NULL },\n");
|
|
|
|
r = r->next;
|
|
|
|
}
|
|
|
|
fprintf(fil, "\t };\n");
|
|
|
|
}
|
2018-05-31 00:09:09 +02:00
|
|
|
if (!ptr->used && (ptr->children || ptr->multidev)) {
|
2017-04-17 05:05:36 +02:00
|
|
|
fprintf(fil, "DEVTREE_CONST struct bus %s_links[] = {\n",
|
2016-08-06 02:32:18 +02:00
|
|
|
ptr->name);
|
2010-06-10 00:41:35 +02:00
|
|
|
if (ptr->multidev) {
|
|
|
|
struct device *d = ptr;
|
|
|
|
while (d) {
|
|
|
|
if (device_match(d, ptr)) {
|
|
|
|
fprintf(fil, "\t\t[%d] = {\n", d->link);
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t\t\t.link_num = %d,\n",
|
|
|
|
d->link);
|
|
|
|
fprintf(fil, "\t\t\t.dev = &%s,\n",
|
|
|
|
d->name);
|
2010-06-10 00:41:35 +02:00
|
|
|
if (d->children)
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil,
|
|
|
|
"\t\t\t.children = &%s,\n",
|
|
|
|
d->children->name);
|
|
|
|
if (d->next_sibling
|
|
|
|
&& device_match(d->next_sibling,
|
|
|
|
ptr))
|
|
|
|
fprintf(fil,
|
|
|
|
"\t\t\t.next=&%s_links[%d],\n",
|
|
|
|
d->name, d->link + 1);
|
2010-06-10 00:41:35 +02:00
|
|
|
else
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil,
|
|
|
|
"\t\t\t.next = NULL,\n");
|
2010-06-10 00:41:35 +02:00
|
|
|
fprintf(fil, "\t\t},\n");
|
|
|
|
}
|
|
|
|
d = d->next_sibling;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ptr->children) {
|
|
|
|
fprintf(fil, "\t\t[0] = {\n");
|
|
|
|
fprintf(fil, "\t\t\t.link_num = 0,\n");
|
|
|
|
fprintf(fil, "\t\t\t.dev = &%s,\n", ptr->name);
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil, "\t\t\t.children = &%s,\n",
|
|
|
|
ptr->children->name);
|
2010-06-10 00:41:35 +02:00
|
|
|
fprintf(fil, "\t\t\t.next = NULL,\n");
|
|
|
|
fprintf(fil, "\t\t},\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fprintf(fil, "\t};\n");
|
|
|
|
}
|
2018-05-31 00:09:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void walk_device_tree(FILE *fil, struct device *ptr,
|
|
|
|
void (*func)(FILE *, struct device *),
|
|
|
|
struct device *chips)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
func(fil, ptr);
|
|
|
|
ptr = ptr->next_sibling;
|
|
|
|
} while (ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void emit_chips(FILE *fil)
|
|
|
|
{
|
|
|
|
struct chip *chip;
|
|
|
|
|
|
|
|
for (chip = chip_head; chip; chip = chip->next) {
|
|
|
|
if (!chip->chiph_exists)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (chip->reg) {
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil,
|
2017-04-17 05:05:36 +02:00
|
|
|
"DEVTREE_CONST struct %s_config %s_info_%d = {\n",
|
2018-05-31 00:09:09 +02:00
|
|
|
chip->name_underscore, chip->name_underscore,
|
|
|
|
chip->id);
|
|
|
|
struct reg *r = chip->reg;
|
2010-05-05 13:19:50 +02:00
|
|
|
while (r) {
|
|
|
|
fprintf(fil, "\t.%s = %s,\n", r->key, r->value);
|
|
|
|
r = r->next;
|
|
|
|
}
|
|
|
|
fprintf(fil, "};\n\n");
|
|
|
|
} else {
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(fil,
|
2017-04-17 05:05:36 +02:00
|
|
|
"DEVTREE_CONST struct %s_config %s_info_%d = { };\n",
|
2018-05-31 00:09:09 +02:00
|
|
|
chip->name_underscore, chip->name_underscore,
|
|
|
|
chip->id);
|
2010-05-05 13:19:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
static void inherit_subsystem_ids(FILE *file, struct device *dev)
|
2011-03-01 20:58:15 +01:00
|
|
|
{
|
|
|
|
struct device *p;
|
|
|
|
|
|
|
|
if (dev->subsystem_vendor != -1 && dev->subsystem_device != -1) {
|
|
|
|
/* user already gave us a subsystem vendor/device */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
for (p = dev; p && p != p->parent; p = p->parent) {
|
2011-03-01 20:58:15 +01:00
|
|
|
|
2013-02-12 23:17:15 +01:00
|
|
|
if (p->bustype != PCI && p->bustype != DOMAIN)
|
2011-03-01 20:58:15 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (p->inherit_subsystem) {
|
|
|
|
dev->subsystem_vendor = p->subsystem_vendor;
|
|
|
|
dev->subsystem_device = p->subsystem_device;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-05 19:33:55 +01:00
|
|
|
static void usage(void)
|
|
|
|
{
|
2016-08-06 02:15:06 +02:00
|
|
|
printf("usage: sconfig devicetree_file output_file\n");
|
2016-08-06 02:32:18 +02:00
|
|
|
exit(1);
|
2011-12-05 19:33:55 +01:00
|
|
|
}
|
|
|
|
|
2015-11-24 20:34:16 +01:00
|
|
|
enum {
|
2016-08-06 02:15:06 +02:00
|
|
|
DEVICEFILE_ARG = 1,
|
2016-08-06 02:32:18 +02:00
|
|
|
OUTPUTFILE_ARG
|
|
|
|
};
|
2015-11-24 20:34:16 +01:00
|
|
|
|
2016-08-06 02:15:06 +02:00
|
|
|
#define ARG_COUNT 3
|
2011-12-05 19:33:55 +01:00
|
|
|
|
2016-08-06 02:32:18 +02:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2016-08-06 01:40:39 +02:00
|
|
|
if (argc != ARG_COUNT)
|
2011-12-05 19:33:55 +01:00
|
|
|
usage();
|
|
|
|
|
2016-08-05 23:46:56 +02:00
|
|
|
char *devtree = argv[DEVICEFILE_ARG];
|
|
|
|
char *outputc = argv[OUTPUTFILE_ARG];
|
2010-05-05 13:19:50 +02:00
|
|
|
|
2011-12-05 19:33:55 +01:00
|
|
|
headers.next = 0;
|
2010-05-05 13:19:50 +02:00
|
|
|
|
|
|
|
FILE *filec = fopen(devtree, "r");
|
2010-08-16 20:21:56 +02:00
|
|
|
if (!filec) {
|
|
|
|
perror(NULL);
|
|
|
|
exit(1);
|
|
|
|
}
|
2010-05-05 13:19:50 +02:00
|
|
|
|
2010-08-16 20:21:56 +02:00
|
|
|
yyrestart(filec);
|
2010-05-05 13:19:50 +02:00
|
|
|
|
2010-05-05 14:05:25 +02:00
|
|
|
lastdev = head = &root;
|
2010-08-16 20:21:56 +02:00
|
|
|
|
2010-05-05 13:19:50 +02:00
|
|
|
yyparse();
|
2010-08-16 20:21:56 +02:00
|
|
|
|
2010-05-05 13:19:50 +02:00
|
|
|
fclose(filec);
|
|
|
|
|
2011-12-05 19:33:55 +01:00
|
|
|
FILE *autogen = fopen(outputc, "w");
|
|
|
|
if (!autogen) {
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(stderr, "Could not open file '%s' for writing: ",
|
|
|
|
outputc);
|
2010-08-16 20:21:56 +02:00
|
|
|
perror(NULL);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2011-12-05 19:33:55 +01:00
|
|
|
struct header *h;
|
2016-08-06 01:40:39 +02:00
|
|
|
fprintf(autogen, "#include <device/device.h>\n");
|
|
|
|
fprintf(autogen, "#include <device/pci.h>\n");
|
|
|
|
h = &headers;
|
|
|
|
while (h->next) {
|
|
|
|
h = h->next;
|
|
|
|
if (h->chiph_exists)
|
|
|
|
fprintf(autogen, "#include \"%s/chip.h\"\n", h->name);
|
|
|
|
}
|
2017-04-17 05:05:36 +02:00
|
|
|
fprintf(autogen, "\n#if !DEVTREE_EARLY\n");
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(autogen,
|
|
|
|
"__attribute__((weak)) struct chip_operations mainboard_ops = {};\n");
|
2016-08-06 01:40:39 +02:00
|
|
|
h = &headers;
|
|
|
|
while (h->next) {
|
|
|
|
h = h->next;
|
|
|
|
char *name_underscore = translate_name(h->name, UNSLASH);
|
2016-08-06 02:32:18 +02:00
|
|
|
fprintf(autogen,
|
|
|
|
"__attribute__((weak)) struct chip_operations %s_ops = {};\n",
|
|
|
|
name_underscore);
|
2016-08-06 01:40:39 +02:00
|
|
|
free(name_underscore);
|
|
|
|
}
|
|
|
|
fprintf(autogen, "#endif\n");
|
2011-03-01 20:58:15 +01:00
|
|
|
|
2018-05-31 00:09:09 +02:00
|
|
|
emit_chips(autogen);
|
|
|
|
|
2016-08-06 01:40:39 +02:00
|
|
|
walk_device_tree(autogen, &root, inherit_subsystem_ids, NULL);
|
|
|
|
fprintf(autogen, "\n/* pass 0 */\n");
|
|
|
|
walk_device_tree(autogen, &root, pass0, NULL);
|
|
|
|
fprintf(autogen, "\n/* pass 1 */\n"
|
2017-04-17 05:05:36 +02:00
|
|
|
"DEVTREE_CONST struct device * DEVTREE_CONST last_dev = &%s;\n",
|
2016-08-06 02:32:18 +02:00
|
|
|
lastdev->name);
|
2016-08-06 01:40:39 +02:00
|
|
|
walk_device_tree(autogen, &root, pass1, NULL);
|
2010-05-05 13:19:50 +02:00
|
|
|
|
2011-12-05 19:33:55 +01:00
|
|
|
fclose(autogen);
|
2010-08-16 20:21:56 +02:00
|
|
|
|
2010-05-05 13:19:50 +02:00
|
|
|
return 0;
|
|
|
|
}
|