dm: core: Add macros to access the new linker lists

Add macros which work with instantiated devices and uclasses, as created
at build time by dtoc. Include variants that can be used in data
structures.

These are mostly used by dtoc but it is worth documenting them fully for
the occasional case where they might come up in user code.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 39406c3..71e5c75 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -10,11 +10,86 @@
 #ifndef _DM_DEVICE_INTERNAL_H
 #define _DM_DEVICE_INTERNAL_H
 
+#include <linker_lists.h>
 #include <dm/ofnode.h>
 
 struct device_node;
 struct udevice;
 
+/*
+ * These two macros DM_DEVICE_INST and DM_DEVICE_REF are only allowed in code
+ * generated by dtoc, because the ordering is important and if other instances
+ * creep in then they may mess up the ordering expected by dtoc.
+ *
+ * It is OK to use them with 'extern' though, since that does not actually
+ * add a new record to the linker_list.
+ */
+
+/**
+ * DM_DEVICE_INST() - Declare a bound device ready for run-time use
+ *
+ * This adds an actual struct udevice to a list which is found by driver model
+ * on start-up.
+ *
+ * For example:
+ *
+ * extern U_BOOT_DRIVER(sandbox_fixed_clock);
+ * extern DM_UCLASS_INST(clk);
+ *
+ * DM_DEVICE_INST(clk_fixed) = {
+ *	.driver		= DM_DRIVER_REF(sandbox_fixed_clock),
+ *	.name		= "sandbox_fixed_clock",
+ *	.plat_		= &_sandbox_fixed_clock_plat_clk_fixed,
+ *	.uclass		= DM_UCLASS_REF(clk),
+ *	...
+ *	.seq_		= 0,
+ * };
+ *
+ * @_name: Name of the udevice. This must be a valid C identifier, used by the
+ *	linker_list.
+ */
+#define DM_DEVICE_INST(_name)						\
+	ll_entry_declare(struct udevice, _name, udevice)
+
+/**
+ * DM_DEVICE_REF() - Get a reference to a device
+ *
+ * This is useful in data structures and code for referencing a udevice at
+ * build time. Before this is used, an extern DM_DEVICE_INST() must have been
+ * declared.
+ *
+ * For example:
+ *
+ * extern DM_DEVICE_INST(clk_fixed);
+ *
+ * struct udevice *devs[] = {
+ *	DM_DEVICE_REF(clk_fixed),
+ * };
+ *
+ * @_name: Name of the udevice. This must be a valid C identifier, used by the
+ *	linker_list
+ * @returns struct udevice * for the device
+ */
+#define DM_DEVICE_REF(_name)						\
+	ll_entry_ref(struct udevice, _name, udevice)
+
+/**
+ * DM_DEVICE_GET() - Get a pointer to a given device
+ *
+ * This is similar to DM_DEVICE_REF() except that it does not need the extern
+ * declaration before it. However it cannot be used in a data structures, only
+ * in code within a function.
+ *
+ * For example:
+ *
+ * void some_function() {
+ *	struct udevice *dev = DM_DEVICE_GET(clk_fixed);
+ * ...
+ * }
+ */
+#define DM_DEVICE_GET(__name)						\
+	ll_entry_get(struct udevice, __name, udevice)
+
 /**
  * device_bind() - Create a device and bind it to a driver
  *