Add initialization hook for chips

Add an init() function to the chip_operations which will be called
before bus enumeration. This allows to disable unused devices before
they get enumerated.

Change-Id: I63dd9cbfc7b5995ccafb7bf7a81dc71fc67906a0
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: http://review.coreboot.org/1623
Tested-by: build bot (Jenkins)
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Marc Jones <marcj303@gmail.com>
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
diff --git a/src/boot/hardwaremain.c b/src/boot/hardwaremain.c
index 95dd988..206e82b 100644
--- a/src/boot/hardwaremain.c
+++ b/src/boot/hardwaremain.c
@@ -82,6 +82,10 @@
 	init_timer();
 
 	timestamp_stash(TS_DEVICE_ENUMERATE);
+
+	/* Initialize chips early, they might disable unused devices. */
+	dev_initialize_chips();
+
 	/* Find the devices we don't have hard coded knowledge about. */
 	dev_enumerate();
 	post_code(POST_DEVICE_ENUMERATION_COMPLETE);
diff --git a/src/devices/device.c b/src/devices/device.c
index f021c9b..03e7ea7 100644
--- a/src/devices/device.c
+++ b/src/devices/device.c
@@ -52,6 +52,26 @@
 /** Linked list of free resources */
 struct resource *free_resources = NULL;
 
+/**
+ * Initialize all chips of statically known devices.
+ *
+ * Will be called before bus enumeration to initialize chips stated in the
+ * device tree.
+ */
+void dev_initialize_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->init &&
+				!dev->chip_ops->initialized) {
+			dev->chip_ops->init(dev->chip_info);
+			dev->chip_ops->initialized = 1;
+		}
+	}
+}
+
 DECLARE_SPIN_LOCK(dev_lock)
 
 #if CONFIG_GFXUMA
diff --git a/src/include/device/device.h b/src/include/device/device.h
index 1cd2a8b..b248aaf 100644
--- a/src/include/device/device.h
+++ b/src/include/device/device.h
@@ -16,6 +16,8 @@
 /* Chip operations */
 struct chip_operations {
 	void (*enable_dev)(struct device *dev);
+	void (*init)(void *chip_info);
+	unsigned int initialized : 1;
 	const char *name;
 };
 
@@ -100,7 +102,7 @@
 
 	struct device_operations *ops;
 #ifndef __PRE_RAM__
-	const struct chip_operations *chip_ops;
+	struct chip_operations *chip_ops;
 	const char *name;
 #endif
 	ROMSTAGE_CONST void *chip_info;
@@ -125,6 +127,7 @@
 
 /* Generic device interface functions */
 device_t alloc_dev(struct bus *parent, struct device_path *path);
+void dev_initialize_chips(void);
 void dev_enumerate(void);
 void dev_configure(void);
 void dev_enable(void);