|  | @@ -46,3 +46,178 @@
 | 
	
		
			
				|  |  |   * Drivers won't call hwmod functions directly.  That is done by the
 | 
	
		
			
				|  |  |   * omap_device code, and in rare occasions, by custom integration code
 | 
	
		
			
				|  |  |   * in arch/arm/ *omap*.  The omap_device code includes functions to
 | 
	
		
			
				|  |  | + * build a struct platform_device using omap_hwmod data, and that is
 | 
	
		
			
				|  |  | + * currently how hwmod data is communicated to drivers and to the
 | 
	
		
			
				|  |  | + * Linux driver model.  Most drivers will call omap_hwmod functions only
 | 
	
		
			
				|  |  | + * indirectly, via pm_runtime*() functions.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * From a layering perspective, here is where the OMAP hwmod code
 | 
	
		
			
				|  |  | + * fits into the kernel software stack:
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + *            +-------------------------------+
 | 
	
		
			
				|  |  | + *            |      Device driver code       |
 | 
	
		
			
				|  |  | + *            |      (e.g., drivers/)         |
 | 
	
		
			
				|  |  | + *            +-------------------------------+
 | 
	
		
			
				|  |  | + *            |      Linux driver model       |
 | 
	
		
			
				|  |  | + *            |     (platform_device /        |
 | 
	
		
			
				|  |  | + *            |  platform_driver data/code)   |
 | 
	
		
			
				|  |  | + *            +-------------------------------+
 | 
	
		
			
				|  |  | + *            | OMAP core-driver integration  |
 | 
	
		
			
				|  |  | + *            |(arch/arm/mach-omap2/devices.c)|
 | 
	
		
			
				|  |  | + *            +-------------------------------+
 | 
	
		
			
				|  |  | + *            |      omap_device code         |
 | 
	
		
			
				|  |  | + *            | (../plat-omap/omap_device.c)  |
 | 
	
		
			
				|  |  | + *            +-------------------------------+
 | 
	
		
			
				|  |  | + *   ---->    |    omap_hwmod code/data       |    <-----
 | 
	
		
			
				|  |  | + *            | (../mach-omap2/omap_hwmod*)   |
 | 
	
		
			
				|  |  | + *            +-------------------------------+
 | 
	
		
			
				|  |  | + *            | OMAP clock/PRCM/register fns  |
 | 
	
		
			
				|  |  | + *            | (__raw_{read,write}l, clk*)   |
 | 
	
		
			
				|  |  | + *            +-------------------------------+
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Device drivers should not contain any OMAP-specific code or data in
 | 
	
		
			
				|  |  | + * them.  They should only contain code to operate the IP block that
 | 
	
		
			
				|  |  | + * the driver is responsible for.  This is because these IP blocks can
 | 
	
		
			
				|  |  | + * also appear in other SoCs, either from TI (such as DaVinci) or from
 | 
	
		
			
				|  |  | + * other manufacturers; and drivers should be reusable across other
 | 
	
		
			
				|  |  | + * platforms.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * The OMAP hwmod code also will attempt to reset and idle all on-chip
 | 
	
		
			
				|  |  | + * devices upon boot.  The goal here is for the kernel to be
 | 
	
		
			
				|  |  | + * completely self-reliant and independent from bootloaders.  This is
 | 
	
		
			
				|  |  | + * to ensure a repeatable configuration, both to ensure consistent
 | 
	
		
			
				|  |  | + * runtime behavior, and to make it easier for others to reproduce
 | 
	
		
			
				|  |  | + * bugs.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * OMAP module activity states
 | 
	
		
			
				|  |  | + * ---------------------------
 | 
	
		
			
				|  |  | + * The hwmod code considers modules to be in one of several activity
 | 
	
		
			
				|  |  | + * states.  IP blocks start out in an UNKNOWN state, then once they
 | 
	
		
			
				|  |  | + * are registered via the hwmod code, proceed to the REGISTERED state.
 | 
	
		
			
				|  |  | + * Once their clock names are resolved to clock pointers, the module
 | 
	
		
			
				|  |  | + * enters the CLKS_INITED state; and finally, once the module has been
 | 
	
		
			
				|  |  | + * reset and the integration registers programmed, the INITIALIZED state
 | 
	
		
			
				|  |  | + * is entered.  The hwmod code will then place the module into either
 | 
	
		
			
				|  |  | + * the IDLE state to save power, or in the case of a critical system
 | 
	
		
			
				|  |  | + * module, the ENABLED state.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * OMAP core integration code can then call omap_hwmod*() functions
 | 
	
		
			
				|  |  | + * directly to move the module between the IDLE, ENABLED, and DISABLED
 | 
	
		
			
				|  |  | + * states, as needed.  This is done during both the PM idle loop, and
 | 
	
		
			
				|  |  | + * in the OMAP core integration code's implementation of the PM runtime
 | 
	
		
			
				|  |  | + * functions.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * References
 | 
	
		
			
				|  |  | + * ----------
 | 
	
		
			
				|  |  | + * This is a partial list.
 | 
	
		
			
				|  |  | + * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
 | 
	
		
			
				|  |  | + * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
 | 
	
		
			
				|  |  | + * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
 | 
	
		
			
				|  |  | + * - OMAP4430 Multimedia Device Silicon Revision 1.0 (SWPU140)
 | 
	
		
			
				|  |  | + * - Open Core Protocol Specification 2.2
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * To do:
 | 
	
		
			
				|  |  | + * - handle IO mapping
 | 
	
		
			
				|  |  | + * - bus throughput & module latency measurement code
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * XXX add tests at the beginning of each function to ensure the hwmod is
 | 
	
		
			
				|  |  | + * in the appropriate state
 | 
	
		
			
				|  |  | + * XXX error return values should be checked to ensure that they are
 | 
	
		
			
				|  |  | + * appropriate
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +#undef DEBUG
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <linux/kernel.h>
 | 
	
		
			
				|  |  | +#include <linux/errno.h>
 | 
	
		
			
				|  |  | +#include <linux/io.h>
 | 
	
		
			
				|  |  | +#include <linux/clk-provider.h>
 | 
	
		
			
				|  |  | +#include <linux/delay.h>
 | 
	
		
			
				|  |  | +#include <linux/err.h>
 | 
	
		
			
				|  |  | +#include <linux/list.h>
 | 
	
		
			
				|  |  | +#include <linux/mutex.h>
 | 
	
		
			
				|  |  | +#include <linux/spinlock.h>
 | 
	
		
			
				|  |  | +#include <linux/slab.h>
 | 
	
		
			
				|  |  | +#include <linux/bootmem.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include "clock.h"
 | 
	
		
			
				|  |  | +#include "omap_hwmod.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include "soc.h"
 | 
	
		
			
				|  |  | +#include "common.h"
 | 
	
		
			
				|  |  | +#include "clockdomain.h"
 | 
	
		
			
				|  |  | +#include "powerdomain.h"
 | 
	
		
			
				|  |  | +#include "cm2xxx.h"
 | 
	
		
			
				|  |  | +#include "cm3xxx.h"
 | 
	
		
			
				|  |  | +#include "cminst44xx.h"
 | 
	
		
			
				|  |  | +#include "cm33xx.h"
 | 
	
		
			
				|  |  | +#include "prm.h"
 | 
	
		
			
				|  |  | +#include "prm3xxx.h"
 | 
	
		
			
				|  |  | +#include "prm44xx.h"
 | 
	
		
			
				|  |  | +#include "prm33xx.h"
 | 
	
		
			
				|  |  | +#include "prminst44xx.h"
 | 
	
		
			
				|  |  | +#include "mux.h"
 | 
	
		
			
				|  |  | +#include "pm.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Name of the OMAP hwmod for the MPU */
 | 
	
		
			
				|  |  | +#define MPU_INITIATOR_NAME		"mpu"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * Number of struct omap_hwmod_link records per struct
 | 
	
		
			
				|  |  | + * omap_hwmod_ocp_if record (master->slave and slave->master)
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +#define LINKS_PER_OCP_IF		2
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations
 | 
	
		
			
				|  |  | + * @enable_module: function to enable a module (via MODULEMODE)
 | 
	
		
			
				|  |  | + * @disable_module: function to disable a module (via MODULEMODE)
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * XXX Eventually this functionality will be hidden inside the PRM/CM
 | 
	
		
			
				|  |  | + * device drivers.  Until then, this should avoid huge blocks of cpu_is_*()
 | 
	
		
			
				|  |  | + * conditionals in this code.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +struct omap_hwmod_soc_ops {
 | 
	
		
			
				|  |  | +	void (*enable_module)(struct omap_hwmod *oh);
 | 
	
		
			
				|  |  | +	int (*disable_module)(struct omap_hwmod *oh);
 | 
	
		
			
				|  |  | +	int (*wait_target_ready)(struct omap_hwmod *oh);
 | 
	
		
			
				|  |  | +	int (*assert_hardreset)(struct omap_hwmod *oh,
 | 
	
		
			
				|  |  | +				struct omap_hwmod_rst_info *ohri);
 | 
	
		
			
				|  |  | +	int (*deassert_hardreset)(struct omap_hwmod *oh,
 | 
	
		
			
				|  |  | +				  struct omap_hwmod_rst_info *ohri);
 | 
	
		
			
				|  |  | +	int (*is_hardreset_asserted)(struct omap_hwmod *oh,
 | 
	
		
			
				|  |  | +				     struct omap_hwmod_rst_info *ohri);
 | 
	
		
			
				|  |  | +	int (*init_clkdm)(struct omap_hwmod *oh);
 | 
	
		
			
				|  |  | +	void (*update_context_lost)(struct omap_hwmod *oh);
 | 
	
		
			
				|  |  | +	int (*get_context_lost)(struct omap_hwmod *oh);
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */
 | 
	
		
			
				|  |  | +static struct omap_hwmod_soc_ops soc_ops;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* omap_hwmod_list contains all registered struct omap_hwmods */
 | 
	
		
			
				|  |  | +static LIST_HEAD(omap_hwmod_list);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
 | 
	
		
			
				|  |  | +static struct omap_hwmod *mpu_oh;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* io_chain_lock: used to serialize reconfigurations of the I/O chain */
 | 
	
		
			
				|  |  | +static DEFINE_SPINLOCK(io_chain_lock);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * linkspace: ptr to a buffer that struct omap_hwmod_link records are
 | 
	
		
			
				|  |  | + * allocated from - used to reduce the number of small memory
 | 
	
		
			
				|  |  | + * allocations, which has a significant impact on performance
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static struct omap_hwmod_link *linkspace;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * free_ls, max_ls: array indexes into linkspace; representing the
 | 
	
		
			
				|  |  | + * next free struct omap_hwmod_link index, and the maximum number of
 | 
	
		
			
				|  |  | + * struct omap_hwmod_link records allocated (respectively)
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static unsigned short free_ls, max_ls, ls_supp;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* inited: set to true once the hwmod code is initialized */
 | 
	
		
			
				|  |  | +static bool inited;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Private functions */
 |