aboutsummaryrefslogtreecommitdiff
path: root/util/sconfig/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/sconfig/main.c')
-rw-r--r--util/sconfig/main.c115
1 files changed, 103 insertions, 12 deletions
diff --git a/util/sconfig/main.c b/util/sconfig/main.c
index b0c32f677a..170acadec7 100644
--- a/util/sconfig/main.c
+++ b/util/sconfig/main.c
@@ -669,16 +669,41 @@ static void set_new_child(struct bus *parent, struct device *child)
child->parent = parent;
}
+static const struct device *find_alias(const struct device *const parent,
+ const char *const alias)
+{
+ if (parent->alias && !strcmp(parent->alias, alias))
+ return parent;
+
+ const struct bus *bus;
+ for (bus = parent->bus; bus; bus = bus->next_bus) {
+ const struct device *child;
+ for (child = bus->children; child; child = child->sibling) {
+ const struct device *const ret = find_alias(child, alias);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return NULL;
+}
+
struct device *new_device(struct bus *parent,
struct chip_instance *chip_instance,
const int bustype, const char *devnum,
- int status)
+ char *alias, int status)
{
char *tmp;
int path_a;
int path_b = 0;
struct device *new_d;
+ /* Check for alias name conflicts. */
+ if (alias && find_alias(&base_root_dev, alias)) {
+ printf("ERROR: Alias already exists: %s\n", alias);
+ exit(1);
+ }
+
path_a = strtol(devnum, &tmp, 16);
if (*tmp == '.') {
tmp++;
@@ -698,6 +723,7 @@ struct device *new_device(struct bus *parent,
new_d->path_a = path_a;
new_d->path_b = path_b;
+ new_d->alias = alias;
new_d->enabled = status & 0x01;
new_d->hidden = (status >> 1) & 0x01;
@@ -819,6 +845,35 @@ void add_register(struct chip_instance *chip_instance, char *name, char *val)
add_reg(&chip_instance->reg, name, val);
}
+void add_reference(struct chip_instance *const chip_instance,
+ char *const name, char *const alias)
+{
+ add_reg(&chip_instance->ref, name, alias);
+}
+
+static void set_reference(struct chip_instance *const chip_instance,
+ char *const name, char *const alias)
+{
+ const struct device *const dev = find_alias(&base_root_dev, alias);
+ if (!dev) {
+ printf("ERROR: Cannot find device alias '%s'.\n", alias);
+ exit(1);
+ }
+
+ char *const ref_name = S_ALLOC(strlen(dev->name) + 2);
+ sprintf(ref_name, "&%s", dev->name);
+ add_register(chip_instance, name, ref_name);
+}
+
+static void update_references(FILE *file, FILE *head, struct device *dev,
+ struct device *next)
+{
+ struct reg *ref;
+
+ for (ref = dev->chip_instance->ref; ref; ref = ref->next)
+ set_reference(dev->chip_instance, ref->key, ref->value);
+}
+
void add_slot_desc(struct bus *bus, char *type, char *length, char *designation,
char *data_width)
{
@@ -1203,16 +1258,12 @@ static void emit_chip_instance(FILE *fil, struct chip_instance *instance)
fprintf(fil, "};\n\n");
}
-static void emit_chips(FILE *fil)
+static void emit_chip_configs(FILE *fil)
{
struct chip *chip = chip_header.next;
struct chip_instance *instance;
int chip_id;
- emit_chip_headers(fil, chip);
-
- fprintf(fil, "\n#define STORAGE static __unused DEVTREE_CONST\n\n");
-
for (; chip; chip = chip->next) {
if (!chip->chiph_exists)
continue;
@@ -1337,9 +1388,9 @@ static void update_resource(struct device *dev, struct resource *res)
* Add register to chip instance. If register is already present, then update
* its value. If not, then add a new register to the chip instance.
*/
-static void update_register(struct chip_instance *c, struct reg *reg)
+static void update_register(struct reg **const head, struct reg *reg)
{
- struct reg *base_reg = c->reg;
+ struct reg *base_reg = *head;
while (base_reg) {
if (!strcmp(base_reg->key, reg->key)) {
@@ -1349,7 +1400,7 @@ static void update_register(struct chip_instance *c, struct reg *reg)
base_reg = base_reg->next;
}
- add_register(c, reg->key, reg->value);
+ add_reg(head, reg->key, reg->value);
}
static void override_devicetree(struct bus *base_parent,
@@ -1422,6 +1473,19 @@ static void override_devicetree(struct bus *base_parent,
* | | |
* +-----------------------------------------------------------------+
* | | |
+ * | ref | Each reference that is present in override |
+ * | | device is copied over to base device with |
+ * | | the same rules as registers. |
+ * | | |
+ * +-----------------------------------------------------------------+
+ * | | |
+ * | alias | Base device alias is copied to override. |
+ * | | Override devices cannot change/remove an |
+ * | | existing alias, but they can add an alias |
+ * | | if one does not exist. |
+ * | | |
+ * +-----------------------------------------------------------------+
+ * | | |
* | chip_instance | Each register of chip_instance is copied |
* | | over from override device to base device: |
* | | 1. If register with same key is present in |
@@ -1492,10 +1556,34 @@ static void update_device(struct device *base_dev, struct device *override_dev)
*/
struct reg *reg = override_dev->chip_instance->reg;
while (reg) {
- update_register(base_dev->chip_instance, reg);
+ update_register(&base_dev->chip_instance->reg, reg);
reg = reg->next;
}
+ /* Copy references just as with registers. */
+ reg = override_dev->chip_instance->ref;
+ while (reg) {
+ update_register(&base_dev->chip_instance->ref, reg);
+ reg = reg->next;
+ }
+
+ /* Check for alias name conflicts. */
+ if (override_dev->alias && find_alias(&base_root_dev, override_dev->alias)) {
+ printf("ERROR: alias already exists: %s\n", override_dev->alias);
+ exit(1);
+ }
+
+ /*
+ * Copy alias from base device.
+ *
+ * Override devices cannot change/remove an existing alias,
+ * but they can add an alias to a device if one does not exist yet.
+ */
+ if (base_dev->alias)
+ override_dev->alias = base_dev->alias;
+ else
+ base_dev->alias = override_dev->alias;
+
/*
* Use probe list from override device in place of base device, in order
* to allow an override to remove a probe from the base device.
@@ -1631,12 +1719,15 @@ int main(int argc, char **argv)
fprintf(autogen, "#include <device/device.h>\n");
fprintf(autogen, "#include <device/pci.h>\n\n");
fprintf(autogen, "#include <static.h>\n");
-
- emit_chips(autogen);
+ emit_chip_headers(autogen, chip_header.next);
+ fprintf(autogen, "\n#define STORAGE static __unused DEVTREE_CONST\n\n");
walk_device_tree(autogen, autohead, &base_root_dev, inherit_subsystem_ids);
fprintf(autogen, "\n/* pass 0 */\n");
walk_device_tree(autogen, autohead, &base_root_dev, pass0);
+ walk_device_tree(autogen, autohead, &base_root_dev, update_references);
+ fprintf(autogen, "\n/* chip configs */\n");
+ emit_chip_configs(autogen);
fprintf(autogen, "\n/* pass 1 */\n");
walk_device_tree(autogen, autohead, &base_root_dev, pass1);