summaryrefslogtreecommitdiff
path: root/src/device
diff options
context:
space:
mode:
authorMarc Jones <marc.jones@se-eng.com>2013-10-29 17:32:00 -0600
committerMarc Jones <marc.jones@se-eng.com>2013-11-08 19:55:17 +0100
commit2a58ecde78350902ac47145a3f2dba063bce3375 (patch)
tree346baf64bf874418a0a1a8d242bfed89959ff1d7 /src/device
parent86655cf835900d54569a867de05e56ccd71db879 (diff)
Add new finalize functions for devices and chips
Many chipset devices require additional configuration after device init. It is not uncommmon for a device early in the devicetree list to need to change a setting after a device later in the tree does PCI init. A final function call has been added to device ops to handle this case. It is called prior to coreboot table setup. Another problem that is often seen is that the chipset or mainboard need to do some final cleanup just before loading the OS. The chip finalize has been added for this case. It is call after all coreboot tables are setup and the payload is ready to be called. Similar functionality could be implemented with the hardwaremain states, but those don't fit well in the device tree function pointer structure and should be used sparingly. Change-Id: Ib37cce104ae41ec225a8502942d85e54d99ea75f Signed-off-by: Marc Jones <marc.jones@se-eng.com> Reviewed-on: http://review.coreboot.org/4012 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@google.com> Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src/device')
-rw-r--r--src/device/device.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/device/device.c b/src/device/device.c
index 3837928743..a2a64b2cae 100644
--- a/src/device/device.c
+++ b/src/device/device.c
@@ -72,6 +72,26 @@ void dev_initialize_chips(void)
}
}
+/**
+ * Finalize all chips of statically known devices.
+ *
+ * This is the last call before calling the payload. This is a good place
+ * to lock registers or other final cleanup.
+ */
+void dev_finalize_chips(void)
+{
+ struct device *dev;
+
+ for (dev = all_devices; dev; dev = dev->next) {
+ /* Initialize chip if we haven't yet. */
+ if (dev->chip_ops && dev->chip_ops->final &&
+ !dev->chip_ops->finalized) {
+ dev->chip_ops->final(dev->chip_info);
+ dev->chip_ops->finalized = 1;
+ }
+ }
+}
+
DECLARE_SPIN_LOCK(dev_lock)
#if CONFIG_GFXUMA
@@ -1167,3 +1187,58 @@ void dev_initialize(void)
printk(BIOS_INFO, "Devices initialized\n");
show_all_devs(BIOS_SPEW, "After init.");
}
+
+/**
+ * Finalize a specific device.
+ *
+ * The parent should be finalized first to avoid having an ordering problem.
+ * This is done by calling the parent's final() method before its childrens'
+ * final() methods.
+ *
+ * @param dev The device to be initialized.
+ */
+static void final_dev(struct device *dev)
+{
+ if (!dev->enabled)
+ return;
+
+ if (dev->ops && dev->ops->final) {
+ printk(BIOS_DEBUG, "%s final\n", dev_path(dev));
+ dev->ops->final(dev);
+ }
+}
+
+static void final_link(struct bus *link)
+{
+ struct device *dev;
+ struct bus *c_link;
+
+ for (dev = link->children; dev; dev = dev->sibling)
+ final_dev(dev);
+
+ for (dev = link->children; dev; dev = dev->sibling) {
+ for (c_link = dev->link_list; c_link; c_link = c_link->next)
+ final_link(c_link);
+ }
+}
+/**
+ * Finalize all devices in the global device tree.
+ *
+ * Starting at the root device, call the device's final() method to do
+ * device-specific cleanup, then call each child's final() method.
+ */
+void dev_finalize(void)
+{
+ struct bus *link;
+
+ printk(BIOS_INFO, "Finalize devices...\n");
+
+ /* First call the mainboard finalize. */
+ final_dev(&dev_root);
+
+ /* Now finalize everything. */
+ for (link = dev_root.link_list; link; link = link->next)
+ final_link(link);
+
+ printk(BIOS_INFO, "Devices finalized\n");
+}