summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/asm-generic/global_data.h8
-rw-r--r--include/dm.h14
-rw-r--r--include/dm/device-internal.h87
-rw-r--r--include/dm/device.h159
-rw-r--r--include/dm/lists.h39
-rw-r--r--include/dm/platdata.h22
-rw-r--r--include/dm/root.h53
-rw-r--r--include/dm/uclass-id.h28
-rw-r--r--include/dm/uclass-internal.h85
-rw-r--r--include/dm/uclass.h142
-rw-r--r--include/dm/util.h29
11 files changed, 666 insertions, 0 deletions
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 0de0bea..707400e 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -21,6 +21,8 @@
*/
#ifndef __ASSEMBLY__
+#include <linux/list.h>
+
typedef struct global_data {
bd_t *bd;
unsigned long flags;
@@ -61,6 +63,12 @@ typedef struct global_data {
unsigned long start_addr_sp; /* start_addr_stackpointer */
unsigned long reloc_off;
struct global_data *new_gd; /* relocated global data */
+
+#ifdef CONFIG_DM
+ struct device *dm_root; /* Root instance for Driver Model */
+ struct list_head uclass_root; /* Head of core tree */
+#endif
+
const void *fdt_blob; /* Our device tree, NULL if none */
void *new_fdt; /* Relocated FDT */
unsigned long fdt_size; /* Space reserved for relocated FDT */
diff --git a/include/dm.h b/include/dm.h
new file mode 100644
index 0000000..8bbb21b
--- /dev/null
+++ b/include/dm.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DM_H_
+#define _DM_H
+
+#include <dm/device.h>
+#include <dm/platdata.h>
+#include <dm/uclass.h>
+
+#endif
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
new file mode 100644
index 0000000..c026e8e
--- /dev/null
+++ b/include/dm/device-internal.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ * Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DM_DEVICE_INTERNAL_H
+#define _DM_DEVICE_INTERNAL_H
+
+struct device;
+
+/**
+ * device_bind() - Create a device and bind it to a driver
+ *
+ * Called to set up a new device attached to a driver. The device will either
+ * have platdata, or a device tree node which can be used to create the
+ * platdata.
+ *
+ * Once bound a device exists but is not yet active until device_probe() is
+ * called.
+ *
+ * @parent: Pointer to device's parent, under which this driver will exist
+ * @drv: Device's driver
+ * @name: Name of device (e.g. device tree node name)
+ * @platdata: Pointer to data for this device - the structure is device-
+ * specific but may include the device's I/O address, etc.. This is NULL for
+ * devices which use device tree.
+ * @of_offset: Offset of device tree node for this device. This is -1 for
+ * devices which don't use device tree.
+ * @devp: Returns a pointer to the bound device
+ * @return 0 if OK, -ve on error
+ */
+int device_bind(struct device *parent, struct driver *drv,
+ const char *name, void *platdata, int of_offset,
+ struct device **devp);
+
+/**
+ * device_bind_by_name: Create a device and bind it to a driver
+ *
+ * This is a helper function used to bind devices which do not use device
+ * tree.
+ *
+ * @parent: Pointer to device's parent
+ * @info: Name and platdata for this device
+ * @devp: Returns a pointer to the bound device
+ * @return 0 if OK, -ve on error
+ */
+int device_bind_by_name(struct device *parent, const struct driver_info *info,
+ struct device **devp);
+
+/**
+ * device_probe() - Probe a device, activating it
+ *
+ * Activate a device so that it is ready for use. All its parents are probed
+ * first.
+ *
+ * @dev: Pointer to device to probe
+ * @return 0 if OK, -ve on error
+ */
+int device_probe(struct device *dev);
+
+/**
+ * device_remove() - Remove a device, de-activating it
+ *
+ * De-activate a device so that it is no longer ready for use. All its
+ * children are deactivated first.
+ *
+ * @dev: Pointer to device to remove
+ * @return 0 if OK, -ve on error (an error here is normally a very bad thing)
+ */
+int device_remove(struct device *dev);
+
+/**
+ * device_unbind() - Unbind a device, destroying it
+ *
+ * Unbind a device and remove all memory used by it
+ *
+ * @dev: Pointer to device to unbind
+ * @return 0 if OK, -ve on error
+ */
+int device_unbind(struct device *dev);
+
+#endif
diff --git a/include/dm/device.h b/include/dm/device.h
new file mode 100644
index 0000000..4cd38ed
--- /dev/null
+++ b/include/dm/device.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ * Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DM_DEVICE_H
+#define _DM_DEVICE_H
+
+#include <dm/uclass-id.h>
+#include <linker_lists.h>
+#include <linux/list.h>
+
+struct driver_info;
+
+/* Driver is active (probed). Cleared when it is removed */
+#define DM_FLAG_ACTIVATED (1 << 0)
+
+/* DM is responsible for allocating and freeing platdata */
+#define DM_FLAG_ALLOC_PDATA (2 << 0)
+
+/**
+ * struct device - An instance of a driver
+ *
+ * This holds information about a device, which is a driver bound to a
+ * particular port or peripheral (essentially a driver instance).
+ *
+ * A device will come into existence through a 'bind' call, either due to
+ * a U_BOOT_DEVICE() macro (in which case platdata is non-NULL) or a node
+ * in the device tree (in which case of_offset is >= 0). In the latter case
+ * we translate the device tree information into platdata in a function
+ * implemented by the driver ofdata_to_platdata method (called just before the
+ * probe method if the device has a device tree node.
+ *
+ * All three of platdata, priv and uclass_priv can be allocated by the
+ * driver, or you can use the auto_alloc_size members of struct driver and
+ * struct uclass_driver to have driver model do this automatically.
+ *
+ * @driver: The driver used by this device
+ * @name: Name of device, typically the FDT node name
+ * @platdata: Configuration data for this device
+ * @of_offset: Device tree node offset for this device (- for none)
+ * @parent: Parent of this device, or NULL for the top level device
+ * @priv: Private data for this device
+ * @uclass: Pointer to uclass for this device
+ * @uclass_priv: The uclass's private data for this device
+ * @uclass_node: Used by uclass to link its devices
+ * @child_head: List of children of this device
+ * @sibling_node: Next device in list of all devices
+ * @flags: Flags for this device DM_FLAG_...
+ */
+struct device {
+ struct driver *driver;
+ const char *name;
+ void *platdata;
+ int of_offset;
+ struct device *parent;
+ void *priv;
+ struct uclass *uclass;
+ void *uclass_priv;
+ struct list_head uclass_node;
+ struct list_head child_head;
+ struct list_head sibling_node;
+ uint32_t flags;
+};
+
+/* Returns the operations for a device */
+#define device_get_ops(dev) (dev->driver->ops)
+
+/* Returns non-zero if the device is active (probed and not removed) */
+#define device_active(dev) ((dev)->flags & DM_FLAG_ACTIVATED)
+
+/**
+ * struct device_id - Lists the compatible strings supported by a driver
+ * @compatible: Compatible string
+ * @data: Data for this compatible string
+ */
+struct device_id {
+ const char *compatible;
+ ulong data;
+};
+
+/**
+ * struct driver - A driver for a feature or peripheral
+ *
+ * This holds methods for setting up a new device, and also removing it.
+ * The device needs information to set itself up - this is provided either
+ * by platdata or a device tree node (which we find by looking up
+ * matching compatible strings with of_match).
+ *
+ * Drivers all belong to a uclass, representing a class of devices of the
+ * same type. Common elements of the drivers can be implemented in the uclass,
+ * or the uclass can provide a consistent interface to the drivers within
+ * it.
+ *
+ * @name: Device name
+ * @id: Identiies the uclass we belong to
+ * @of_match: List of compatible strings to match, and any identifying data
+ * for each.
+ * @bind: Called to bind a device to its driver
+ * @probe: Called to probe a device, i.e. activate it
+ * @remove: Called to remove a device, i.e. de-activate it
+ * @unbind: Called to unbind a device from its driver
+ * @ofdata_to_platdata: Called before probe to decode device tree data
+ * @priv_auto_alloc_size: If non-zero this is the size of the private data
+ * to be allocated in the device's ->priv pointer. If zero, then the driver
+ * is responsible for allocating any data required.
+ * @platdata_auto_alloc_size: If non-zero this is the size of the
+ * platform data to be allocated in the device's ->platdata pointer.
+ * This is typically only useful for device-tree-aware drivers (those with
+ * an of_match), since drivers which use platdata will have the data
+ * provided in the U_BOOT_DEVICE() instantiation.
+ * ops: Driver-specific operations. This is typically a list of function
+ * pointers defined by the driver, to implement driver functions required by
+ * the uclass.
+ */
+struct driver {
+ char *name;
+ enum uclass_id id;
+ const struct device_id *of_match;
+ int (*bind)(struct device *dev);
+ int (*probe)(struct device *dev);
+ int (*remove)(struct device *dev);
+ int (*unbind)(struct device *dev);
+ int (*ofdata_to_platdata)(struct device *dev);
+ int priv_auto_alloc_size;
+ int platdata_auto_alloc_size;
+ const void *ops; /* driver-specific operations */
+};
+
+/* Declare a new U-Boot driver */
+#define U_BOOT_DRIVER(__name) \
+ ll_entry_declare(struct driver, __name, driver)
+
+/**
+ * dev_get_platdata() - Get the platform data for a device
+ *
+ * This checks that dev is not NULL, but no other checks for now
+ *
+ * @dev Device to check
+ * @return platform data, or NULL if none
+ */
+void *dev_get_platdata(struct device *dev);
+
+/**
+ * dev_get_priv() - Get the private data for a device
+ *
+ * This checks that dev is not NULL, but no other checks for now
+ *
+ * @dev Device to check
+ * @return private data, or NULL if none
+ */
+void *dev_get_priv(struct device *dev);
+
+#endif
diff --git a/include/dm/lists.h b/include/dm/lists.h
new file mode 100644
index 0000000..0d09f9a
--- /dev/null
+++ b/include/dm/lists.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DM_LISTS_H_
+#define _DM_LISTS_H_
+
+#include <dm/uclass-id.h>
+
+/**
+ * lists_driver_lookup_name() - Return u_boot_driver corresponding to name
+ *
+ * This function returns a pointer to a driver given its name. This is used
+ * for binding a driver given its name and platdata.
+ *
+ * @name: Name of driver to look up
+ * @return pointer to driver, or NULL if not found
+ */
+struct driver *lists_driver_lookup_name(const char *name);
+
+/**
+ * lists_uclass_lookup() - Return uclass_driver based on ID of the class
+ * id: ID of the class
+ *
+ * This function returns the pointer to uclass_driver, which is the class's
+ * base structure based on the ID of the class. Returns NULL on error.
+ */
+struct uclass_driver *lists_uclass_lookup(enum uclass_id id);
+
+int lists_bind_drivers(struct device *parent);
+
+int lists_bind_fdt(struct device *parent, const void *blob, int offset);
+
+#endif
diff --git a/include/dm/platdata.h b/include/dm/platdata.h
new file mode 100644
index 0000000..0ef3353
--- /dev/null
+++ b/include/dm/platdata.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ * Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DM_PLATDATA_H
+#define _DM_PLATDATA_H
+
+struct driver_info {
+ const char *name;
+ const void *platdata;
+};
+
+#define U_BOOT_DEVICE(__name) \
+ ll_entry_declare(struct driver_info, __name, driver_info)
+
+#endif
diff --git a/include/dm/root.h b/include/dm/root.h
new file mode 100644
index 0000000..0ebccda
--- /dev/null
+++ b/include/dm/root.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DM_ROOT_H_
+#define _DM_ROOT_H_
+
+struct device;
+
+/**
+ * dm_root() - Return pointer to the top of the driver tree
+ *
+ * This function returns pointer to the root node of the driver tree,
+ *
+ * @return pointer to root device, or NULL if not inited yet
+ */
+struct device *dm_root(void);
+
+/**
+ * dm_scan_platdata() - Scan all platform data and bind drivers
+ *
+ * This scans all available platdata and creates drivers for each
+ *
+ * @return 0 if OK, -ve on error
+ */
+int dm_scan_platdata(void);
+
+/**
+ * dm_scan_fdt() - Scan the device tree and bind drivers
+ *
+ * This scans the device tree and creates a driver for each node
+ *
+ * @blob: Pointer to device tree blob
+ * @return 0 if OK, -ve on error
+ */
+int dm_scan_fdt(const void *blob);
+
+/**
+ * dm_init() - Initialize Driver Model structures
+ *
+ * This function will initialize roots of driver tree and class tree.
+ * This needs to be called before anything uses the DM
+ *
+ * @return 0 if OK, -ve on error
+ */
+int dm_init(void);
+
+#endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
new file mode 100644
index 0000000..f0e691c
--- /dev/null
+++ b/include/dm/uclass-id.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DM_UCLASS_ID_H
+#define _DM_UCLASS_ID_H
+
+/* TODO(sjg@chromium.org): this could be compile-time generated */
+enum uclass_id {
+ /* These are used internally by driver model */
+ UCLASS_ROOT = 0,
+ UCLASS_DEMO,
+ UCLASS_TEST,
+ UCLASS_TEST_FDT,
+
+ /* U-Boot uclasses start here */
+ UCLASS_GPIO,
+
+ UCLASS_COUNT,
+ UCLASS_INVALID = -1,
+};
+
+#endif
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
new file mode 100644
index 0000000..cc65d52
--- /dev/null
+++ b/include/dm/uclass-internal.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DM_UCLASS_INTERNAL_H
+#define _DM_UCLASS_INTERNAL_H
+
+/**
+ * uclass_find_device() - Return n-th child of uclass
+ * @id: Id number of the uclass
+ * @index: Position of the child in uclass's list
+ * #devp: Returns pointer to device, or NULL on error
+ *
+ * The device is not prepared for use - this is an internal function
+ *
+ * @return the uclass pointer of a child at the given index or
+ * return NULL on error.
+ */
+int uclass_find_device(enum uclass_id id, int index, struct device **devp);
+
+/**
+ * uclass_bind_device() - Associate device with a uclass
+ *
+ * Connect the device into uclass's list of devices.
+ *
+ * @dev: Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_bind_device(struct device *dev);
+
+/**
+ * uclass_unbind_device() - Deassociate device with a uclass
+ *
+ * Disconnect the device from uclass's list of devices.
+ *
+ * @dev: Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_unbind_device(struct device *dev);
+
+/**
+ * uclass_post_probe_device() - Deal with a device that has just been probed
+ *
+ * Perform any post-processing of a probed device that is needed by the
+ * uclass.
+ *
+ * @dev: Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_post_probe_device(struct device *dev);
+
+/**
+ * uclass_pre_remove_device() - Handle a device which is about to be removed
+ *
+ * Perform any pre-processing of a device that is about to be removed.
+ *
+ * @dev: Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_pre_remove_device(struct device *dev);
+
+/**
+ * uclass_find() - Find uclass by its id
+ *
+ * @id: Id to serach for
+ * @return pointer to uclass, or NULL if not found
+ */
+struct uclass *uclass_find(enum uclass_id key);
+
+/**
+ * uclass_destroy() - Destroy a uclass
+ *
+ * Destroy a uclass and all its devices
+ *
+ * @uc: uclass to destroy
+ * @return 0 on success, -ve on error
+ */
+int uclass_destroy(struct uclass *uc);
+
+#endif
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
new file mode 100644
index 0000000..cd23cfe
--- /dev/null
+++ b/include/dm/uclass.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _DM_UCLASS_H
+#define _DM_UCLASS_H
+
+#include <dm/uclass-id.h>
+#include <linux/list.h>
+
+/**
+ * struct uclass - a U-Boot drive class, collecting together similar drivers
+ *
+ * A uclass provides an interface to a particular function, which is
+ * implemented by one or more drivers. Every driver belongs to a uclass even
+ * if it is the only driver in that uclass. An example uclass is GPIO, which
+ * provides the ability to change read inputs, set and clear outputs, etc.
+ * There may be drivers for on-chip SoC GPIO banks, I2C GPIO expanders and
+ * PMIC IO lines, all made available in a unified way through the uclass.
+ *
+ * @priv: Private data for this uclass
+ * @uc_drv: The driver for the uclass itself, not to be confused with a
+ * 'struct driver'
+ * dev_head: List of devices in this uclass (devices are attached to their
+ * uclass when their bind method is called)
+ * @sibling_node: Next uclass in the linked list of uclasses
+ */
+struct uclass {
+ void *priv;
+ struct uclass_driver *uc_drv;
+ struct list_head dev_head;
+ struct list_head sibling_node;
+};
+
+struct device;
+
+/**
+ * struct uclass_driver - Driver for the uclass
+ *
+ * A uclass_driver provides a consistent interface to a set of related
+ * drivers.
+ *
+ * @name: Name of uclass driver
+ * @id: ID number of this uclass
+ * @post_bind: Called after a new device is bound to this uclass
+ * @pre_unbind: Called before a device is unbound from this uclass
+ * @post_probe: Called after a new device is probed
+ * @pre_remove: Called before a device is removed
+ * @init: Called to set up the uclass
+ * @destroy: Called to destroy the uclass
+ * @priv_auto_alloc_size: If non-zero this is the size of the private data
+ * to be allocated in the uclass's ->priv pointer. If zero, then the uclass
+ * driver is responsible for allocating any data required.
+ * @per_device_auto_alloc_size: Each device can hold private data owned
+ * by the uclass. If required this will be automatically allocated if this
+ * value is non-zero.
+ * @ops: Uclass operations, providing the consistent interface to devices
+ * within the uclass.
+ */
+struct uclass_driver {
+ const char *name;
+ enum uclass_id id;
+ int (*post_bind)(struct device *dev);
+ int (*pre_unbind)(struct device *dev);
+ int (*post_probe)(struct device *dev);
+ int (*pre_remove)(struct device *dev);
+ int (*init)(struct uclass *class);
+ int (*destroy)(struct uclass *class);
+ int priv_auto_alloc_size;
+ int per_device_auto_alloc_size;
+ const void *ops;
+};
+
+/* Declare a new uclass_driver */
+#define UCLASS_DRIVER(__name) \
+ ll_entry_declare(struct uclass_driver, __name, uclass)
+
+/**
+ * uclass_get() - Get a uclass based on an ID, creating it if needed
+ *
+ * Every uclass is identified by an ID, a number from 0 to n-1 where n is
+ * the number of uclasses. This function allows looking up a uclass by its
+ * ID.
+ *
+ * @key: ID to look up
+ * @ucp: Returns pointer to uclass (there is only one per ID)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_get(enum uclass_id key, struct uclass **ucp);
+
+/**
+ * uclass_get_device() - Get a uclass device based on an ID and index
+ *
+ * id: ID to look up
+ * @index: Device number within that uclass (0=first)
+ * @ucp: Returns pointer to uclass (there is only one per for each ID)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_get_device(enum uclass_id id, int index, struct device **ucp);
+
+/**
+ * uclass_first_device() - Get the first device in a uclass
+ *
+ * @id: Uclass ID to look up
+ * @devp: Returns pointer to the first device in that uclass, or NULL if none
+ * @return 0 if OK (found or not found), -1 on error
+ */
+int uclass_first_device(enum uclass_id id, struct device **devp);
+
+/**
+ * uclass_next_device() - Get the next device in a uclass
+ *
+ * @devp: On entry, pointer to device to lookup. On exit, returns pointer
+ * to the next device in the same uclass, or NULL if none
+ * @return 0 if OK (found or not found), -1 on error
+ */
+int uclass_next_device(struct device **devp);
+
+/**
+ * uclass_foreach_dev() - Helper function to iteration through devices
+ *
+ * This creates a for() loop which works through the available devices in
+ * a uclass in order from start to end.
+ *
+ * @pos: struct device * to hold the current device. Set to NULL when there
+ * are no more devices.
+ * uc: uclass to scan
+ */
+#define uclass_foreach_dev(pos, uc) \
+ for (pos = list_entry((&(uc)->dev_head)->next, typeof(*pos), \
+ uclass_node); \
+ prefetch(pos->uclass_node.next), \
+ &pos->uclass_node != (&(uc)->dev_head); \
+ pos = list_entry(pos->uclass_node.next, typeof(*pos), \
+ uclass_node))
+
+#endif
diff --git a/include/dm/util.h b/include/dm/util.h
new file mode 100644
index 0000000..8be64a9
--- /dev/null
+++ b/include/dm/util.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __DM_UTIL_H
+
+void dm_warn(const char *fmt, ...);
+
+#ifdef DEBUG
+void dm_dbg(const char *fmt, ...);
+#else
+static inline void dm_dbg(const char *fmt, ...)
+{
+}
+#endif
+
+struct list_head;
+
+/**
+ * list_count_items() - Count number of items in a list
+ *
+ * @param head: Head of list
+ * @return number of items, or 0 if empty
+ */
+int list_count_items(struct list_head *head);
+
+#endif