From 9ee9fff92e02e8c5f84794b3a5ce47646c2dfc39 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 21 Sep 2010 10:34:08 -0600 Subject: OMAP: hwmod: Rename dma_ch to dma_req The dma request line attribute was named dma channel, which leads to confusion with the real dma channel definition. Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley Tested-by: Kevin Hilman --- arch/arm/mach-omap2/omap_hwmod.c | 10 +++++----- arch/arm/plat-omap/include/plat/omap_hwmod.h | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index cb911d7..8bf19a7 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1468,7 +1468,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) { int ret, i; - ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt; + ret = oh->mpu_irqs_cnt + oh->sdma_reqs_cnt; for (i = 0; i < oh->slaves_cnt; i++) ret += oh->slaves[i]->addr_cnt; @@ -1501,10 +1501,10 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) r++; } - for (i = 0; i < oh->sdma_chs_cnt; i++) { - (res + r)->name = (oh->sdma_chs + i)->name; - (res + r)->start = (oh->sdma_chs + i)->dma_ch; - (res + r)->end = (oh->sdma_chs + i)->dma_ch; + for (i = 0; i < oh->sdma_reqs_cnt; i++) { + (res + r)->name = (oh->sdma_reqs + i)->name; + (res + r)->start = (oh->sdma_reqs + i)->dma_req; + (res + r)->end = (oh->sdma_reqs + i)->dma_req; (res + r)->flags = IORESOURCE_DMA; r++; } diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index a4e508d..5506d80 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -96,7 +96,7 @@ struct omap_hwmod_irq_info { /** * struct omap_hwmod_dma_info - DMA channels used by the hwmod * @name: name of the DMA channel (module local name) - * @dma_ch: DMA channel ID + * @dma_req: DMA request ID * * @name should be something short, e.g., "tx" or "rx". It is for use * by platform_get_resource_byname(). It is defined locally to the @@ -104,7 +104,7 @@ struct omap_hwmod_irq_info { */ struct omap_hwmod_dma_info { const char *name; - u16 dma_ch; + u16 dma_req; }; /** @@ -410,7 +410,7 @@ struct omap_hwmod_class { * @class: struct omap_hwmod_class * to the class of this hwmod * @od: struct omap_device currently associated with this hwmod (internal use) * @mpu_irqs: ptr to an array of MPU IRQs (see also mpu_irqs_cnt) - * @sdma_chs: ptr to an array of SDMA channel IDs (see also sdma_chs_cnt) + * @sdma_reqs: ptr to an array of System DMA request IDs (see sdma_reqs_cnt) * @prcm: PRCM data pertaining to this hwmod * @main_clk: main clock: OMAP clock name * @_clk: pointer to the main struct clk (filled in at runtime) @@ -424,7 +424,7 @@ struct omap_hwmod_class { * @msuspendmux_reg_id: CONTROL_MSUSPENDMUX register ID (1-6) * @msuspendmux_shift: CONTROL_MSUSPENDMUX register bit shift * @mpu_irqs_cnt: number of @mpu_irqs - * @sdma_chs_cnt: number of @sdma_chs + * @sdma_reqs_cnt: number of @sdma_reqs * @opt_clks_cnt: number of @opt_clks * @master_cnt: number of @master entries * @slaves_cnt: number of @slave entries @@ -448,7 +448,7 @@ struct omap_hwmod { struct omap_hwmod_class *class; struct omap_device *od; struct omap_hwmod_irq_info *mpu_irqs; - struct omap_hwmod_dma_info *sdma_chs; + struct omap_hwmod_dma_info *sdma_reqs; union { struct omap_hwmod_omap2_prcm omap2; struct omap_hwmod_omap4_prcm omap4; @@ -468,7 +468,7 @@ struct omap_hwmod { u8 msuspendmux_shift; u8 response_lat; u8 mpu_irqs_cnt; - u8 sdma_chs_cnt; + u8 sdma_reqs_cnt; u8 opt_clks_cnt; u8 masters_cnt; u8 slaves_cnt; -- cgit v1.1 From 3827f9492bdff045ae57fe67e65ce7e259ed4219 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 21 Sep 2010 10:34:08 -0600 Subject: OMAP: hwmod: Do not disable clocks if hwmod already in idle The disable function was disabling clocks and dependencies from both enable and idle state. Since idle function is already disabling both, an enable -> idle -> disable sequence will try to disable twice the clocks and thus generate a "Trying disable clock XXX with 0 usecount" warning. Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley Tested-by: Kevin Hilman --- arch/arm/mach-omap2/omap_hwmod.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 8bf19a7..5bb25e3 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -982,9 +982,13 @@ static int _shutdown(struct omap_hwmod *oh) if (oh->class->sysc) _sysc_shutdown(oh); - _del_initiator_dep(oh, mpu_oh); - /* XXX what about the other system initiators here? DMA, tesla, d2d */ - _disable_clocks(oh); + + /* clocks and deps are already disabled in idle */ + if (oh->_state == _HWMOD_STATE_ENABLED) { + _del_initiator_dep(oh, mpu_oh); + /* XXX what about the other system initiators here? dma, dsp */ + _disable_clocks(oh); + } /* XXX Should this code also force-disable the optional clocks? */ /* XXX mux any associated balls to safe mode */ -- cgit v1.1 From 9b579114efc4bd00532de33c783b4cb4638910ff Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 21 Sep 2010 10:34:09 -0600 Subject: OMAP: hwmod: Fix omap_hwmod_reset wrong state test The reset function wrongly used the state flag as a bit mask and was trying to re-enable after a reset. hwmod is still enabled for the PRCM point of view after a softreset so there is no need to re-enable. Remove the state check from omap_hwmod_reset since the _reset function is checking that as well and in addition can generate a warning Signed-off-by: Liam Girdwood [b-cousson@ti.com: remove the wrong test, remove the re-enable] Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley Tested-by: Kevin Hilman Cc: Rajendra Nayak --- arch/arm/mach-omap2/omap_hwmod.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 5bb25e3..100115f 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1434,19 +1434,17 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh) * * Under some conditions, a driver may wish to reset the entire device. * Called from omap_device code. Returns -EINVAL on error or passes along - * the return value from _reset()/_enable(). + * the return value from _reset(). */ int omap_hwmod_reset(struct omap_hwmod *oh) { int r; - if (!oh || !(oh->_state & _HWMOD_STATE_ENABLED)) + if (!oh) return -EINVAL; mutex_lock(&omap_hwmod_mutex); r = _reset(oh); - if (!r) - r = _omap_hwmod_enable(oh); mutex_unlock(&omap_hwmod_mutex); return r; -- cgit v1.1 From ff4d3e186b7b92c74a4f64360f723c603193f344 Mon Sep 17 00:00:00 2001 From: Rajeev Kulkarni Date: Tue, 21 Sep 2010 10:34:09 -0600 Subject: OMAP4: prcm: Fix global warm reset bit position OMAP4 platform has different register bits for Warm and Cold Resets. Write one into appropriate bits. Signed-off-by: Rajeev Kulkarni Cc: Leed Aguilar [b-cousson@ti.com: Change the define with the proper one from omap4 headers] Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley Tested-by: Kevin Hilman --- arch/arm/mach-omap2/prcm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index c201374..96f4616 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -33,6 +33,7 @@ #include "cm.h" #include "prm.h" #include "prm-regbits-24xx.h" +#include "prm-regbits-44xx.h" static void __iomem *prm_base; static void __iomem *cm_base; @@ -161,8 +162,8 @@ void omap_prcm_arch_reset(char mode, const char *cmd) prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs, OMAP2_RM_RSTCTRL); if (cpu_is_omap44xx()) - prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs, - OMAP4_RM_RSTCTRL); + prm_set_mod_reg_bits(OMAP4430_RST_GLOBAL_WARM_SW_MASK, + prcm_offs, OMAP4_RM_RSTCTRL); } static inline u32 __omap_prcm_read(void __iomem *base, s16 module, u16 reg) -- cgit v1.1 From 12b1fdb45c2594070bb36e39cd89a33547aad8fb Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 21 Sep 2010 10:34:09 -0600 Subject: OMAP: hwmod: separate list locking and hwmod hardware locking Currently omap_hwmod_mutex is being used to protect both the list access/modification and concurrent access to hwmod functions. This patch separates these two types of locking. First, omap_hwmod_mutex is used only to protect access and modification of omap_hwmod_list. Also cleaned up some comments referring to this mutex that are no longer needed. Then, for protecting concurrent access to hwmod functions, use a per-hwmod mutex. This protects concurrent access to a single hwmod, but would allow concurrent access to different hwmods. Signed-off-by: Kevin Hilman [paul@pwsan.com: added structure documentation; changed mutex variable name] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 62 ++++++++++++++-------------- arch/arm/plat-omap/include/plat/omap_hwmod.h | 3 ++ 2 files changed, 33 insertions(+), 32 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 100115f..3084409 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -767,10 +767,10 @@ static struct omap_hwmod *_lookup(const char *name) * @data: not used; pass NULL * * Called by omap_hwmod_late_init() (after omap2_clk_init()). - * Resolves all clock names embedded in the hwmod. Must be called - * with omap_hwmod_mutex held. Returns -EINVAL if the omap_hwmod - * has not yet been registered or if the clocks have already been - * initialized, 0 on success, or a non-zero error on failure. + * Resolves all clock names embedded in the hwmod. Returns -EINVAL if + * the omap_hwmod has not yet been registered or if the clocks have + * already been initialized, 0 on success, or a non-zero error on + * failure. */ static int _init_clocks(struct omap_hwmod *oh, void *data) { @@ -838,10 +838,9 @@ static int _wait_target_ready(struct omap_hwmod *oh) * @oh: struct omap_hwmod * * * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be - * enabled for this to work. Must be called with omap_hwmod_mutex - * held. Returns -EINVAL if the hwmod cannot be reset this way or if - * the hwmod is in the wrong state, -ETIMEDOUT if the module did not - * reset in time, or 0 upon success. + * enabled for this to work. Returns -EINVAL if the hwmod cannot be + * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if + * the module did not reset in time, or 0 upon success. */ static int _reset(struct omap_hwmod *oh) { @@ -891,9 +890,8 @@ static int _reset(struct omap_hwmod *oh) * @oh: struct omap_hwmod * * * Enables an omap_hwmod @oh such that the MPU can access the hwmod's - * register target. Must be called with omap_hwmod_mutex held. - * Returns -EINVAL if the hwmod is in the wrong state or passes along - * the return value of _wait_target_ready(). + * register target. Returns -EINVAL if the hwmod is in the wrong + * state or passes along the return value of _wait_target_ready(). */ int _omap_hwmod_enable(struct omap_hwmod *oh) { @@ -1004,11 +1002,10 @@ static int _shutdown(struct omap_hwmod *oh) * @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1 * * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh - * OCP_SYSCONFIG register. Must be called with omap_hwmod_mutex held. - * @skip_setup_idle is intended to be used on a system that will not - * call omap_hwmod_enable() to enable devices (e.g., a system without - * PM runtime). Returns -EINVAL if the hwmod is in the wrong state or - * returns 0. + * OCP_SYSCONFIG register. @skip_setup_idle is intended to be used on + * a system that will not call omap_hwmod_enable() to enable devices + * (e.g., a system without PM runtime). Returns -EINVAL if the hwmod + * is in the wrong state or returns 0. */ static int _setup(struct omap_hwmod *oh, void *data) { @@ -1038,6 +1035,7 @@ static int _setup(struct omap_hwmod *oh, void *data) } } + mutex_init(&oh->_mutex); oh->_state = _HWMOD_STATE_INITIALIZED; r = _omap_hwmod_enable(oh); @@ -1323,9 +1321,9 @@ int omap_hwmod_enable(struct omap_hwmod *oh) if (!oh) return -EINVAL; - mutex_lock(&omap_hwmod_mutex); + mutex_lock(&oh->_mutex); r = _omap_hwmod_enable(oh); - mutex_unlock(&omap_hwmod_mutex); + mutex_unlock(&oh->_mutex); return r; } @@ -1343,9 +1341,9 @@ int omap_hwmod_idle(struct omap_hwmod *oh) if (!oh) return -EINVAL; - mutex_lock(&omap_hwmod_mutex); + mutex_lock(&oh->_mutex); _omap_hwmod_idle(oh); - mutex_unlock(&omap_hwmod_mutex); + mutex_unlock(&oh->_mutex); return 0; } @@ -1363,9 +1361,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh) if (!oh) return -EINVAL; - mutex_lock(&omap_hwmod_mutex); + mutex_lock(&oh->_mutex); _shutdown(oh); - mutex_unlock(&omap_hwmod_mutex); + mutex_unlock(&oh->_mutex); return 0; } @@ -1378,9 +1376,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh) */ int omap_hwmod_enable_clocks(struct omap_hwmod *oh) { - mutex_lock(&omap_hwmod_mutex); + mutex_lock(&oh->_mutex); _enable_clocks(oh); - mutex_unlock(&omap_hwmod_mutex); + mutex_unlock(&oh->_mutex); return 0; } @@ -1393,9 +1391,9 @@ int omap_hwmod_enable_clocks(struct omap_hwmod *oh) */ int omap_hwmod_disable_clocks(struct omap_hwmod *oh) { - mutex_lock(&omap_hwmod_mutex); + mutex_lock(&oh->_mutex); _disable_clocks(oh); - mutex_unlock(&omap_hwmod_mutex); + mutex_unlock(&oh->_mutex); return 0; } @@ -1443,9 +1441,9 @@ int omap_hwmod_reset(struct omap_hwmod *oh) if (!oh) return -EINVAL; - mutex_lock(&omap_hwmod_mutex); + mutex_lock(&oh->_mutex); r = _reset(oh); - mutex_unlock(&omap_hwmod_mutex); + mutex_unlock(&oh->_mutex); return r; } @@ -1646,9 +1644,9 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) return -EINVAL; - mutex_lock(&omap_hwmod_mutex); + mutex_lock(&oh->_mutex); _enable_wakeup(oh); - mutex_unlock(&omap_hwmod_mutex); + mutex_unlock(&oh->_mutex); return 0; } @@ -1671,9 +1669,9 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) return -EINVAL; - mutex_lock(&omap_hwmod_mutex); + mutex_lock(&oh->_mutex); _disable_wakeup(oh); - mutex_unlock(&omap_hwmod_mutex); + mutex_unlock(&oh->_mutex); return 0; } diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 5506d80..03350ba 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -35,6 +35,7 @@ #include #include #include +#include #include struct omap_device; @@ -433,6 +434,7 @@ struct omap_hwmod_class { * @_state: internal-use hwmod state * @flags: hwmod flags (documented below) * @omap_chip: OMAP chips this hwmod is present on + * @_mutex: mutex serializing operations on this hwmod * @node: list node for hwmod list (internal use) * * @main_clk refers to this module's "main clock," which for our @@ -461,6 +463,7 @@ struct omap_hwmod { void *dev_attr; u32 _sysc_cache; void __iomem *_mpu_rt_va; + struct mutex _mutex; struct list_head node; u16 flags; u8 _mpu_port_index; -- cgit v1.1 From 16b040129e324598d13ff2e2b3469dc2e909ce12 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 21 Sep 2010 10:34:10 -0600 Subject: OMAP4: prcm: Add temporarily helper functions for rmw and read inside the PRM Since OMAP4 is using an absolute address, the current PRM accessors are not useable. OMAP4 adaptation for these API are currently ongoing, so define temp version until the proper ones are defined. Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley Tested-by: Kevin Hilman --- arch/arm/mach-omap2/prcm.c | 24 ++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/prcm.h | 2 ++ 2 files changed, 26 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index 96f4616..d4388d34 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -216,6 +216,30 @@ u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask) return v; } +/* Read a PRM register, AND it, and shift the result down to bit 0 */ +u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask) +{ + u32 v; + + v = __raw_readl(reg); + v &= mask; + v >>= __ffs(mask); + + return v; +} + +/* Read-modify-write a register in a PRM module. Caller must lock */ +u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg) +{ + u32 v; + + v = __raw_readl(reg); + v &= ~mask; + v |= bits; + __raw_writel(v, reg); + + return v; +} /* Read a register in a CM module */ u32 cm_read_mod_reg(s16 module, u16 idx) { diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h index 9fbd914..ab77442 100644 --- a/arch/arm/plat-omap/include/plat/prcm.h +++ b/arch/arm/plat-omap/include/plat/prcm.h @@ -38,6 +38,8 @@ u32 prm_read_mod_reg(s16 module, u16 idx); void prm_write_mod_reg(u32 val, s16 module, u16 idx); u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx); u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask); +u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask); +u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg); u32 cm_read_mod_reg(s16 module, u16 idx); void cm_write_mod_reg(u32 val, s16 module, u16 idx); u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx); -- cgit v1.1 From 0be1621a749907ada0101e4139a1f57168c5410b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Cousson?= Date: Tue, 21 Sep 2010 10:34:10 -0600 Subject: OMAP4: PRM: add module hard reset support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most processor modules (e.g., DSP, IVA, IPU) on OMAPs can be reset under the control of the PRM. This patch adds an API for this purpose for OMAP4 devices: int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift); int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift); int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift); This API is intended to be used only by the hwmod code - a subsequent patch will add that support to hwmod. This patch is a collaboration between Benoît Cousson and Paul Walmsley . Signed-off-by: Paul Walmsley Signed-off-by: Benoît Cousson Tested-by: Kevin Hilman --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/prm.h | 13 ++++- arch/arm/mach-omap2/prm44xx.c | 116 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-omap2/prm44xx.c (limited to 'arch') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 88d3a1e..c0da784 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -15,7 +15,7 @@ clock-common = clock.o clock_common_data.o \ obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(hwmod-common) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(hwmod-common) -obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) $(hwmod-common) +obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) prm44xx.o $(hwmod-common) obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 588873b..bc7e6e6 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -5,7 +5,7 @@ * OMAP2/3 Power/Reset Management (PRM) register definitions * * Copyright (C) 2007-2009 Texas Instruments, Inc. - * Copyright (C) 2009 Nokia Corporation + * Copyright (C) 2010 Nokia Corporation * * Written by Paul Walmsley * @@ -246,6 +246,10 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) return prm_rmw_mod_reg_bits(bits, 0x0, module, idx); } +int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift); +int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift); +int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift); + #endif /* @@ -398,4 +402,11 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) #define OMAP_POWERSTATE_MASK (0x3 << 0) +/* + * MAX_MODULE_HARDRESET_WAIT: Maximum microseconds to wait for an OMAP + * submodule to exit hardreset + */ +#define MAX_MODULE_HARDRESET_WAIT 10000 + + #endif diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c new file mode 100644 index 0000000..a1ff918 --- /dev/null +++ b/arch/arm/mach-omap2/prm44xx.c @@ -0,0 +1,116 @@ +/* + * OMAP4 PRM module functions + * + * Copyright (C) 2010 Texas Instruments, Inc. + * Copyright (C) 2010 Nokia Corporation + * Benoît Cousson + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "prm.h" +#include "prm-regbits-44xx.h" + +/* + * Address offset (in bytes) between the reset control and the reset + * status registers: 4 bytes on OMAP4 + */ +#define OMAP4_RST_CTRL_ST_OFFSET 4 + +/** + * omap4_prm_is_hardreset_asserted - read the HW reset line state of + * submodules contained in the hwmod module + * @rstctrl_reg: RM_RSTCTRL register address for this module + * @shift: register bit shift corresponding to the reset line to check + * + * Returns 1 if the (sub)module hardreset line is currently asserted, + * 0 if the (sub)module hardreset line is not currently asserted, or + * -EINVAL upon parameter error. + */ +int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift) +{ + if (!cpu_is_omap44xx() || !rstctrl_reg) + return -EINVAL; + + return omap4_prm_read_bits_shift(rstctrl_reg, (1 << shift)); +} + +/** + * omap4_prm_assert_hardreset - assert the HW reset line of a submodule + * @rstctrl_reg: RM_RSTCTRL register address for this module + * @shift: register bit shift corresponding to the reset line to assert + * + * Some IPs like dsp, ipu or iva contain processors that require an HW + * reset line to be asserted / deasserted in order to fully enable the + * IP. These modules may have multiple hard-reset lines that reset + * different 'submodules' inside the IP block. This function will + * place the submodule into reset. Returns 0 upon success or -EINVAL + * upon an argument error. + */ +int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift) +{ + u32 mask; + + if (!cpu_is_omap44xx() || !rstctrl_reg) + return -EINVAL; + + mask = 1 << shift; + omap4_prm_rmw_reg_bits(mask, mask, rstctrl_reg); + + return 0; +} + +/** + * omap4_prm_deassert_hardreset - deassert a submodule hardreset line and wait + * @rstctrl_reg: RM_RSTCTRL register address for this module + * @shift: register bit shift corresponding to the reset line to deassert + * + * Some IPs like dsp, ipu or iva contain processors that require an HW + * reset line to be asserted / deasserted in order to fully enable the + * IP. These modules may have multiple hard-reset lines that reset + * different 'submodules' inside the IP block. This function will + * take the submodule out of reset and wait until the PRCM indicates + * that the reset has completed before returning. Returns 0 upon success or + * -EINVAL upon an argument error, -EEXIST if the submodule was already out + * of reset, or -EBUSY if the submodule did not exit reset promptly. + */ +int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift) +{ + u32 mask; + void __iomem *rstst_reg; + int c; + + if (!cpu_is_omap44xx() || !rstctrl_reg) + return -EINVAL; + + rstst_reg = rstctrl_reg + OMAP4_RST_CTRL_ST_OFFSET; + + mask = 1 << shift; + + /* Check the current status to avoid de-asserting the line twice */ + if (omap4_prm_read_bits_shift(rstctrl_reg, mask) == 0) + return -EEXIST; + + /* Clear the reset status by writing 1 to the status bit */ + omap4_prm_rmw_reg_bits(0xffffffff, mask, rstst_reg); + /* de-assert the reset control line */ + omap4_prm_rmw_reg_bits(mask, 0, rstctrl_reg); + /* wait the status to be set */ + omap_test_timeout(omap4_prm_read_bits_shift(rstst_reg, mask), + MAX_MODULE_HARDRESET_WAIT, c); + + return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; +} + -- cgit v1.1 From cf21405fd51b416f071edb546631a6ecd2112263 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 21 Sep 2010 10:34:10 -0600 Subject: OMAP2/3: PRM: add module hard reset support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds hard-reset support for processor modules (e.g., DSP, IVA) on OMAP2/3 platforms. It's based on the OMAP4 hard-reset support that Benoît developed in the previous patch. This patch is a collaboration between Benoît Cousson and Paul Walmsley . Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/prm.h | 5 ++ arch/arm/mach-omap2/prm2xxx_3xxx.c | 110 +++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-omap2/prm2xxx_3xxx.c (limited to 'arch') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index c0da784..eb2504a 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -5,7 +5,7 @@ # Common support obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o -omap-2-3-common = irq.o sdrc.o +omap-2-3-common = irq.o sdrc.o prm2xxx_3xxx.o hwmod-common = omap_hwmod.o \ omap_hwmod_common_data.o prcm-common = prcm.o powerdomain.o diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index bc7e6e6..7be040b 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -246,6 +246,11 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) return prm_rmw_mod_reg_bits(bits, 0x0, module, idx); } +/* These omap2_ PRM functions apply to both OMAP2 and 3 */ +int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); +int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); +int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift); + int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift); int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift); int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift); diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c new file mode 100644 index 0000000..421771e --- /dev/null +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -0,0 +1,110 @@ +/* + * OMAP2/3 PRM module functions + * + * Copyright (C) 2010 Texas Instruments, Inc. + * Copyright (C) 2010 Nokia Corporation + * Benoît Cousson + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "prm.h" +#include "prm-regbits-24xx.h" +#include "prm-regbits-34xx.h" + +/** + * omap2_prm_is_hardreset_asserted - read the HW reset line state of + * submodules contained in the hwmod module + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @shift: register bit shift corresponding to the reset line to check + * + * Returns 1 if the (sub)module hardreset line is currently asserted, + * 0 if the (sub)module hardreset line is not currently asserted, or + * -EINVAL if called while running on a non-OMAP2/3 chip. + */ +int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) +{ + if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) + return -EINVAL; + + return prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, + (1 << shift)); +} + +/** + * omap2_prm_assert_hardreset - assert the HW reset line of a submodule + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @shift: register bit shift corresponding to the reset line to assert + * + * Some IPs like dsp or iva contain processors that require an HW + * reset line to be asserted / deasserted in order to fully enable the + * IP. These modules may have multiple hard-reset lines that reset + * different 'submodules' inside the IP block. This function will + * place the submodule into reset. Returns 0 upon success or -EINVAL + * upon an argument error. + */ +int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) +{ + u32 mask; + + if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) + return -EINVAL; + + mask = 1 << shift; + prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL); + + return 0; +} + +/** + * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @shift: register bit shift corresponding to the reset line to deassert + * + * Some IPs like dsp or iva contain processors that require an HW + * reset line to be asserted / deasserted in order to fully enable the + * IP. These modules may have multiple hard-reset lines that reset + * different 'submodules' inside the IP block. This function will + * take the submodule out of reset and wait until the PRCM indicates + * that the reset has completed before returning. Returns 0 upon success or + * -EINVAL upon an argument error, -EEXIST if the submodule was already out + * of reset, or -EBUSY if the submodule did not exit reset promptly. + */ +int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift) +{ + u32 mask; + int c; + + if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) + return -EINVAL; + + mask = 1 << shift; + + /* Check the current status to avoid de-asserting the line twice */ + if (prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, mask) == 0) + return -EEXIST; + + /* Clear the reset status by writing 1 to the status bit */ + prm_rmw_mod_reg_bits(0xffffffff, mask, prm_mod, OMAP2_RM_RSTST); + /* de-assert the reset control line */ + prm_rmw_mod_reg_bits(mask, 0, prm_mod, OMAP2_RM_RSTCTRL); + /* wait the status to be set */ + omap_test_timeout(prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST, + mask), + MAX_MODULE_HARDRESET_WAIT, c); + + return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; +} + -- cgit v1.1 From 5365efbe29250a227502256cc912351fe2157b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Cousson?= Date: Tue, 21 Sep 2010 10:34:11 -0600 Subject: OMAP: hwmod: Add hardreset management support Most processor IPs does have a hardreset signal controlled by the PRM. This is different of the softreset used for local IP reset from the SYSCONFIG register. The granularity can be much finer than orginal HWMOD, for ex, the IVA hwmod contains 3 reset lines, the IPU 3 as well, the DSP 2... Since this granularity is needed by the driver, we have to ensure than one hwmod exist for each hardreset line. - Store reset lines as hwmod resources that a driver can query by name like an irq or sdma line. - Add two functions for asserting / deasserting reset lines in hwmods processor that require manual reset control. - Add one functions to get the current reset state. - If an hwmod contains only one line, an automatic assertion / de-assertion is done. -> de-assert the hardreset line only during enable from disable transition -> assert the hardreset line only during shutdown Note: The hwmods with hardreset line and HWMOD_INIT_NO_RESET flag must be kept in INITIALIZED state. They can be properly enabled only if the hardreset line is de-asserted before. For information here is the list of IPs with HW reset control on an OMAP4430 device: RM_DSP_RSTCTRL 1,1,'RST2','RW','1','DSP - MMU, cache and slave interface reset control' 0,0,'RST1','RW','1','DSP - DSP reset control' RM_IVA_RSTCTRL 2,2,'RST3','RW','1','IVA logic and SL2 reset control' 1,1,'RST2','RW','1','IVA Sequencer2 reset control' 0,0,'RST1','RW','1','IVA sequencer1 reset control' RM_IPU_RSTCTRL 2,2,'RST3','RW','1','IPU MMU and CACHE interface reset control.' 1,1,'RST2','RW','1','IPU Cortex M3 CPU2 reset control.' 0,0,'RST1','RW','1','IPU Cortex M3 CPU1 reset control.' PRM_RSTCTRL 1,1,'RST_GLOBAL_COLD_SW','RW','0','Global COLD software reset control.' 0,0,'RST_GLOBAL_WARM_SW','RW','0','Global WARM software reset control.' RM_CPU0_CPU0_RSTCTRL RM_CPU1_CPU1_RSTCTRL 0,0,'RST','RW','0','Cortex A9 CPU0&1 warm local reset control' Signed-off-by: Benoit Cousson [paul@pwsan.com: made the hardreset functions static; moved the register twiddling into prm*.c functions in previous patches; changed the function names to conform with hwmod practice] Signed-off-by: Paul Walmsley Cc: Kevin Hilman Cc: Rajendra Nayak --- arch/arm/mach-omap2/omap_hwmod.c | 168 +++++++++++++++++++++++++-- arch/arm/plat-omap/include/plat/omap_hwmod.h | 17 +++ 2 files changed, 177 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 3084409..f4a569c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -50,11 +50,13 @@ #include #include #include +#include #include "cm.h" +#include "prm.h" -/* Maximum microseconds to wait for OMAP module to reset */ -#define MAX_MODULE_RESET_WAIT 10000 +/* Maximum microseconds to wait for OMAP module to softreset */ +#define MAX_MODULE_SOFTRESET_WAIT 10000 /* Name of the OMAP hwmod for the MPU */ #define MPU_INITIATOR_NAME "mpu" @@ -834,6 +836,130 @@ static int _wait_target_ready(struct omap_hwmod *oh) } /** + * _lookup_hardreset - return the register bit shift for this hwmod/reset line + * @oh: struct omap_hwmod * + * @name: name of the reset line in the context of this hwmod + * + * Return the bit position of the reset line that match the + * input name. Return -ENOENT if not found. + */ +static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name) +{ + int i; + + for (i = 0; i < oh->rst_lines_cnt; i++) { + const char *rst_line = oh->rst_lines[i].name; + if (!strcmp(rst_line, name)) { + u8 shift = oh->rst_lines[i].rst_shift; + pr_debug("omap_hwmod: %s: _lookup_hardreset: %s: %d\n", + oh->name, rst_line, shift); + + return shift; + } + } + + return -ENOENT; +} + +/** + * _assert_hardreset - assert the HW reset line of submodules + * contained in the hwmod module. + * @oh: struct omap_hwmod * + * @name: name of the reset line to lookup and assert + * + * Some IP like dsp, ipu or iva contain processor that require + * an HW reset line to be assert / deassert in order to enable fully + * the IP. + */ +static int _assert_hardreset(struct omap_hwmod *oh, const char *name) +{ + u8 shift; + + if (!oh) + return -EINVAL; + + shift = _lookup_hardreset(oh, name); + if (IS_ERR_VALUE(shift)) + return shift; + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) + return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, + shift); + else if (cpu_is_omap44xx()) + return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg, + shift); + else + return -EINVAL; +} + +/** + * _deassert_hardreset - deassert the HW reset line of submodules contained + * in the hwmod module. + * @oh: struct omap_hwmod * + * @name: name of the reset line to look up and deassert + * + * Some IP like dsp, ipu or iva contain processor that require + * an HW reset line to be assert / deassert in order to enable fully + * the IP. + */ +static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) +{ + u8 shift; + int r; + + if (!oh) + return -EINVAL; + + shift = _lookup_hardreset(oh, name); + if (IS_ERR_VALUE(shift)) + return shift; + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) + r = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, + shift); + else if (cpu_is_omap44xx()) + r = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg, + shift); + else + return -EINVAL; + + if (r == -EBUSY) + pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name); + + return r; +} + +/** + * _read_hardreset - read the HW reset line state of submodules + * contained in the hwmod module + * @oh: struct omap_hwmod * + * @name: name of the reset line to look up and read + * + * Return the state of the reset line. + */ +static int _read_hardreset(struct omap_hwmod *oh, const char *name) +{ + u8 shift; + + if (!oh) + return -EINVAL; + + shift = _lookup_hardreset(oh, name); + if (IS_ERR_VALUE(shift)) + return shift; + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, + shift); + } else if (cpu_is_omap44xx()) { + return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg, + shift); + } else { + return -EINVAL; + } +} + +/** * _reset - reset an omap_hwmod * @oh: struct omap_hwmod * * @@ -869,20 +995,20 @@ static int _reset(struct omap_hwmod *oh) omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) & SYSS_RESETDONE_MASK), - MAX_MODULE_RESET_WAIT, c); + MAX_MODULE_SOFTRESET_WAIT, c); - if (c == MAX_MODULE_RESET_WAIT) - WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n", - oh->name, MAX_MODULE_RESET_WAIT); + if (c == MAX_MODULE_SOFTRESET_WAIT) + WARN(1, "omap_hwmod: %s: softreset failed (waited %d usec)\n", + oh->name, MAX_MODULE_SOFTRESET_WAIT); else - pr_debug("omap_hwmod: %s: reset in %d usec\n", oh->name, c); + pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c); /* * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from * _wait_target_ready() or _reset() */ - return (c == MAX_MODULE_RESET_WAIT) ? -ETIMEDOUT : 0; + return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0; } /** @@ -907,6 +1033,15 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: enabling\n", oh->name); + /* + * If an IP contains only one HW reset line, then de-assert it in order + * to allow to enable the clocks. Otherwise the PRCM will return + * Intransition status, and the init will failed. + */ + if ((oh->_state == _HWMOD_STATE_INITIALIZED || + oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) + _deassert_hardreset(oh, oh->rst_lines[0].name); + /* XXX mux balls */ _add_initiator_dep(oh, mpu_oh); @@ -981,6 +1116,13 @@ static int _shutdown(struct omap_hwmod *oh) if (oh->class->sysc) _sysc_shutdown(oh); + /* + * If an IP contains only one HW reset line, then assert it + * before disabling the clocks and shutting down the IP. + */ + if (oh->rst_lines_cnt == 1) + _assert_hardreset(oh, oh->rst_lines[0].name); + /* clocks and deps are already disabled in idle */ if (oh->_state == _HWMOD_STATE_ENABLED) { _del_initiator_dep(oh, mpu_oh); @@ -1038,6 +1180,16 @@ static int _setup(struct omap_hwmod *oh, void *data) mutex_init(&oh->_mutex); oh->_state = _HWMOD_STATE_INITIALIZED; + /* + * In the case of hwmod with hardreset that should not be + * de-assert at boot time, we have to keep the module + * initialized, because we cannot enable it properly with the + * reset asserted. Exit without warning because that behavior is + * expected. + */ + if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) + return 0; + r = _omap_hwmod_enable(oh); if (r) { pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 03350ba..590bfae 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -109,6 +109,19 @@ struct omap_hwmod_dma_info { }; /** + * struct omap_hwmod_rst_info - IPs reset lines use by hwmod + * @name: name of the reset line (module local name) + * @rst_shift: Offset of the reset bit + * + * @name should be something short, e.g., "cpu0" or "rst". It is defined + * locally to the hwmod. + */ +struct omap_hwmod_rst_info { + const char *name; + u8 rst_shift; +}; + +/** * struct omap_hwmod_opt_clk - optional clocks used by this hwmod * @role: "sys", "32k", "tv", etc -- for use in clk_get() * @clk: opt clock: OMAP clock name @@ -328,10 +341,12 @@ struct omap_hwmod_omap2_prcm { /** * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data * @clkctrl_reg: PRCM address of the clock control register + * @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM * @submodule_wkdep_bit: bit shift of the WKDEP range */ struct omap_hwmod_omap4_prcm { void __iomem *clkctrl_reg; + void __iomem *rstctrl_reg; u8 submodule_wkdep_bit; }; @@ -451,6 +466,7 @@ struct omap_hwmod { struct omap_device *od; struct omap_hwmod_irq_info *mpu_irqs; struct omap_hwmod_dma_info *sdma_reqs; + struct omap_hwmod_rst_info *rst_lines; union { struct omap_hwmod_omap2_prcm omap2; struct omap_hwmod_omap4_prcm omap4; @@ -472,6 +488,7 @@ struct omap_hwmod { u8 response_lat; u8 mpu_irqs_cnt; u8 sdma_reqs_cnt; + u8 rst_lines_cnt; u8 opt_clks_cnt; u8 masters_cnt; u8 slaves_cnt; -- cgit v1.1 From 76e5589e5b7cd0fd589264ab193f10550e1d8ab6 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 21 Sep 2010 10:34:11 -0600 Subject: OMAP: hwmod: Force a softreset during _setup Force the softreset of every IPs during the _setup phase. IPs that cannot support softreset or that should not be reset must set the HWMOD_INIT_NO_RESET flag in the hwmod struct. Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley Tested-by: Kevin Hilman --- arch/arm/mach-omap2/omap_hwmod.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index f4a569c..3e90984 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -980,8 +980,8 @@ static int _reset(struct omap_hwmod *oh) /* clocks must be on for this operation */ if (oh->_state != _HWMOD_STATE_ENABLED) { - WARN(1, "omap_hwmod: %s: reset can only be entered from " - "enabled state\n", oh->name); + pr_warning("omap_hwmod: %s: reset can only be entered from " + "enabled state\n", oh->name); return -EINVAL; } @@ -998,8 +998,8 @@ static int _reset(struct omap_hwmod *oh) MAX_MODULE_SOFTRESET_WAIT, c); if (c == MAX_MODULE_SOFTRESET_WAIT) - WARN(1, "omap_hwmod: %s: softreset failed (waited %d usec)\n", - oh->name, MAX_MODULE_SOFTRESET_WAIT); + pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n", + oh->name, MAX_MODULE_SOFTRESET_WAIT); else pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c); @@ -1198,12 +1198,12 @@ static int _setup(struct omap_hwmod *oh, void *data) } if (!(oh->flags & HWMOD_INIT_NO_RESET)) { + _reset(oh); + /* - * XXX Do the OCP_SYSCONFIG bits need to be - * reprogrammed after a reset? If not, then this can - * be removed. If they do, then probably the - * _omap_hwmod_enable() function should be split to avoid the - * rewrite of the OCP_SYSCONFIG register. + * OCP_SYSCONFIG bits need to be reprogrammed after a softreset. + * The _omap_hwmod_enable() function should be split to + * avoid the rewrite of the OCP_SYSCONFIG register. */ if (oh->class->sysc) { _update_sysc_cache(oh); -- cgit v1.1 From aee48e3c9cee3698d17b4cf4203551de0a804760 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 21 Sep 2010 10:34:11 -0600 Subject: OMAP: hwmod: add an hardreset API for use by other core code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose an hardreset API from hwmod in order to assert / deassert all the individual reset lines that belong to an hwmod. This API is needed by some of the more complicated processor drivers, e.g., DSP/Bridge, Syslink, etc. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 78 ++++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/omap_hwmod.h | 4 ++ 2 files changed, 82 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 3e90984..8c27923 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1829,6 +1829,84 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) } /** + * omap_hwmod_assert_hardreset - assert the HW reset line of submodules + * contained in the hwmod module. + * @oh: struct omap_hwmod * + * @name: name of the reset line to lookup and assert + * + * Some IP like dsp, ipu or iva contain processor that require + * an HW reset line to be assert / deassert in order to enable fully + * the IP. Returns -EINVAL if @oh is null or if the operation is not + * yet supported on this OMAP; otherwise, passes along the return value + * from _assert_hardreset(). + */ +int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name) +{ + int ret; + + if (!oh) + return -EINVAL; + + mutex_lock(&oh->_mutex); + ret = _assert_hardreset(oh, name); + mutex_unlock(&oh->_mutex); + + return ret; +} + +/** + * omap_hwmod_deassert_hardreset - deassert the HW reset line of submodules + * contained in the hwmod module. + * @oh: struct omap_hwmod * + * @name: name of the reset line to look up and deassert + * + * Some IP like dsp, ipu or iva contain processor that require + * an HW reset line to be assert / deassert in order to enable fully + * the IP. Returns -EINVAL if @oh is null or if the operation is not + * yet supported on this OMAP; otherwise, passes along the return value + * from _deassert_hardreset(). + */ +int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name) +{ + int ret; + + if (!oh) + return -EINVAL; + + mutex_lock(&oh->_mutex); + ret = _deassert_hardreset(oh, name); + mutex_unlock(&oh->_mutex); + + return ret; +} + +/** + * omap_hwmod_read_hardreset - read the HW reset line state of submodules + * contained in the hwmod module + * @oh: struct omap_hwmod * + * @name: name of the reset line to look up and read + * + * Return the current state of the hwmod @oh's reset line named @name: + * returns -EINVAL upon parameter error or if this operation + * is unsupported on the current OMAP; otherwise, passes along the return + * value from _read_hardreset(). + */ +int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name) +{ + int ret; + + if (!oh) + return -EINVAL; + + mutex_lock(&oh->_mutex); + ret = _read_hardreset(oh, name); + mutex_unlock(&oh->_mutex); + + return ret; +} + + +/** * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname * @classname: struct omap_hwmod_class name to search for * @fn: callback function pointer to call for each hwmod in class @classname diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 590bfae..7fde44d 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -512,6 +512,10 @@ int omap_hwmod_idle(struct omap_hwmod *oh); int _omap_hwmod_idle(struct omap_hwmod *oh); int omap_hwmod_shutdown(struct omap_hwmod *oh); +int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name); +int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name); +int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name); + int omap_hwmod_enable_clocks(struct omap_hwmod *oh); int omap_hwmod_disable_clocks(struct omap_hwmod *oh); -- cgit v1.1 From 2cb068149c365f1c2b10f2ece6786139527dcc16 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 21 Sep 2010 18:57:59 +0200 Subject: OMAP: hwmod: Fix softreset status check for some new OMAP4 IPs In OMAP3 a specific SYSSTATUS register was used to get the softreset status. Starting in OMAP4, some IPs does not have SYSSTATUS register and instead use the SYSC softreset bit to provide the status. Other cases might exist: - Some IPs like McBSP does have a softreset control but no reset status. - Some IPs that represent subsystem, like the DSS, can contains a reset status without softreset control. The status is the aggregation of all the sub modules reset status. - Add a new flag (SYSC_HAS_RESET_STATUS) to identify the new programming model and replace the previous SYSS_MISSING, that was used to flag IP with softreset control but without the SYSSTATUS register, with a specific SYSS_HAS_RESET_STATUS flag. - MCSPI and MMC contains both programming models, so the legacy one will be prevented by removing the syss offset field that become useless. Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley Cc: Kevin Hilman Cc: Rajendra Nayak --- arch/arm/mach-omap2/omap_hwmod.c | 22 +++++++++++++++++----- arch/arm/plat-omap/include/plat/omap_hwmod.h | 3 ++- 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 8c27923..5027879b 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -967,6 +967,12 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) * enabled for this to work. Returns -EINVAL if the hwmod cannot be * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if * the module did not reset in time, or 0 upon success. + * + * In OMAP3 a specific SYSSTATUS register is used to get the reset status. + * Starting in OMAP4, some IPs does not have SYSSTATUS register and instead + * use the SYSCONFIG softreset bit to provide the status. + * + * Note that some IP like McBSP does have a reset control but no reset status. */ static int _reset(struct omap_hwmod *oh) { @@ -974,8 +980,7 @@ static int _reset(struct omap_hwmod *oh) int c = 0; if (!oh->class->sysc || - !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET) || - (oh->class->sysc->sysc_flags & SYSS_MISSING)) + !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) return -EINVAL; /* clocks must be on for this operation */ @@ -993,9 +998,16 @@ static int _reset(struct omap_hwmod *oh) return r; _write_sysconfig(v, oh); - omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) & - SYSS_RESETDONE_MASK), - MAX_MODULE_SOFTRESET_WAIT, c); + if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS) + omap_test_timeout((omap_hwmod_readl(oh, + oh->class->sysc->syss_offs) + & SYSS_RESETDONE_MASK), + MAX_MODULE_SOFTRESET_WAIT, c); + else if (oh->class->sysc->sysc_flags & SYSC_HAS_RESET_STATUS) + omap_test_timeout(!(omap_hwmod_readl(oh, + oh->class->sysc->sysc_offs) + & SYSC_TYPE2_SOFTRESET_MASK), + MAX_MODULE_SOFTRESET_WAIT, c); if (c == MAX_MODULE_SOFTRESET_WAIT) pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n", diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 7fde44d..faa0827 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -251,8 +251,9 @@ struct omap_hwmod_ocp_if { #define SYSC_HAS_CLOCKACTIVITY (1 << 4) #define SYSC_HAS_SIDLEMODE (1 << 5) #define SYSC_HAS_MIDLEMODE (1 << 6) -#define SYSS_MISSING (1 << 7) +#define SYSS_HAS_RESET_STATUS (1 << 7) #define SYSC_NO_CACHE (1 << 8) /* XXX SW flag, belongs elsewhere */ +#define SYSC_HAS_RESET_STATUS (1 << 9) /* omap_hwmod_sysconfig.clockact flags */ #define CLOCKACT_TEST_BOTH 0x0 -- cgit v1.1 From 96835af970e5d6aeedf868e53590a947be5e4a7a Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 21 Sep 2010 18:57:58 +0200 Subject: OMAP: hwmod: Fix softreset for modules with optional clocks Some modules (like GPIO, DSS...) require optionals clock to be enabled in order to complete the sofreset properly. Add a HWMOD_CONTROL_OPT_CLKS_IN_RESET flag to force all optional clocks to be enabled before reset. Disabled them once the reset is done. TODO: For the moment it is very hard to understand from the HW spec, which optional clock is needed and which one is not. So the current approach will enable all the optional clocks. Paul proposed a much finer approach that will allow to tag only the needed clock in the optional clock table. This might be doable as soon as we have a clear understanding of these dependencies. Reported-by: Partha Basak Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/omap_hwmod.c | 51 +++++++++++++++++++++++++--- arch/arm/plat-omap/include/plat/omap_hwmod.h | 5 +++ 2 files changed, 51 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 5027879b..f320cfb 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -546,6 +546,36 @@ static int _disable_clocks(struct omap_hwmod *oh) return 0; } +static void _enable_optional_clocks(struct omap_hwmod *oh) +{ + struct omap_hwmod_opt_clk *oc; + int i; + + pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name); + + for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) + if (oc->_clk) { + pr_debug("omap_hwmod: enable %s:%s\n", oc->role, + oc->_clk->name); + clk_enable(oc->_clk); + } +} + +static void _disable_optional_clocks(struct omap_hwmod *oh) +{ + struct omap_hwmod_opt_clk *oc; + int i; + + pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name); + + for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) + if (oc->_clk) { + pr_debug("omap_hwmod: disable %s:%s\n", oc->role, + oc->_clk->name); + clk_disable(oc->_clk); + } +} + /** * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use * @oh: struct omap_hwmod * @@ -976,8 +1006,9 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) */ static int _reset(struct omap_hwmod *oh) { - u32 r, v; + u32 v; int c = 0; + int ret = 0; if (!oh->class->sysc || !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) @@ -990,12 +1021,16 @@ static int _reset(struct omap_hwmod *oh) return -EINVAL; } + /* For some modules, all optionnal clocks need to be enabled as well */ + if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET) + _enable_optional_clocks(oh); + pr_debug("omap_hwmod: %s: resetting\n", oh->name); v = oh->_sysc_cache; - r = _set_softreset(oh, &v); - if (r) - return r; + ret = _set_softreset(oh, &v); + if (ret) + goto dis_opt_clks; _write_sysconfig(v, oh); if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS) @@ -1020,7 +1055,13 @@ static int _reset(struct omap_hwmod *oh) * _wait_target_ready() or _reset() */ - return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0; + ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0; + +dis_opt_clks: + if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET) + _disable_optional_clocks(oh); + + return ret; } /** diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index faa0827..ee53758 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -369,6 +369,10 @@ struct omap_hwmod_omap4_prcm { * HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup * HWMOD_NO_IDLEST : this module does not have idle status - this is the case * only for few initiator modules on OMAP2 & 3. + * HWMOD_CONTROL_OPT_CLKS_IN_RESET: Enable all optional clocks during reset. + * This is needed for devices like DSS that require optional clocks enabled + * in order to complete the reset. Optional clocks will be disabled + * again after the reset. */ #define HWMOD_SWSUP_SIDLE (1 << 0) #define HWMOD_SWSUP_MSTANDBY (1 << 1) @@ -377,6 +381,7 @@ struct omap_hwmod_omap4_prcm { #define HWMOD_NO_OCP_AUTOIDLE (1 << 4) #define HWMOD_SET_DEFAULT_CLOCKACT (1 << 5) #define HWMOD_NO_IDLEST (1 << 6) +#define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7) /* * omap_hwmod._int_flags definitions -- cgit v1.1 From 9980ce53c97392a3dbdc9d1ac3e455d79b4167ed Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 21 Sep 2010 19:58:30 +0530 Subject: OMAP: hwmod: Enable module wakeup if in smartidle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a module's OCP slave port is programmed to be in smartidle, its also necessary that they have module level wakeup enabled. Update _sysc_enable in hwmod framework to do this. The thread "[PATCH 7/8] : Hwmod api changes" archived here: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg34212.html has additional technical information on the rationale of this patch. Sergei Shtylyov identified an indentation problem with this patch - thanks, Sergei. Signed-off-by: Rajendra Nayak Signed-off-by: Partha Basak Signed-off-by: Benoît Cousson [paul@pwsan.com: revised patch description] Signed-off-by: Paul Walmsley Cc: Kevin Hilman Cc: Sergei Shtylyov --- arch/arm/mach-omap2/omap_hwmod.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index f320cfb..d694067 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -691,8 +691,6 @@ static void _sysc_enable(struct omap_hwmod *oh) _set_module_autoidle(oh, idlemode, &v); } - /* XXX OCP ENAWAKEUP bit? */ - /* * XXX The clock framework should handle this, by * calling into this code. But this must wait until the @@ -703,6 +701,10 @@ static void _sysc_enable(struct omap_hwmod *oh) _set_clockactivity(oh, oh->class->sysc->clockact, &v); _write_sysconfig(v, oh); + + /* If slave is in SMARTIDLE, also enable wakeup */ + if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE)) + _enable_wakeup(oh); } /** -- cgit v1.1 From 4ef7aca895b2d06c07ff9d5f378af84bbf757e43 Mon Sep 17 00:00:00 2001 From: Partha Basak Date: Tue, 21 Sep 2010 19:23:04 +0200 Subject: OMAP: hwmod: Handle opt clocks node using clk_add_alias For every optional clock present per hwmod per omap-device, this function adds an entry in the clocks list of the form , if an entry is already present in the list of the form . The function is called from within the framework inside omap_device_build_ss(), after omap_device_register. This allows drivers to get a pointer to its optional clocks based on its role by calling clk_get(, ). Link to discussions related to this patch: http://www.spinics.net/lists/linux-omap/msg34809.html Signed-off-by: Charulatha V Signed-off-by: Partha Basak Signed-off-by: Benoit Cousson Signed-off-by: Rajendra Nayak [paul@pwsan.com: simplified loop iterator; removed the superfluous clk_get(), using the clk_get() in clk_add_alias() instead] Signed-off-by: Paul Walmsley Acked-by: Kevin Hilman --- arch/arm/plat-omap/omap_device.c | 43 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index d2b1609..ceba58a 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -82,6 +82,7 @@ #include #include #include +#include #include #include @@ -243,6 +244,44 @@ static inline struct omap_device *_find_by_pdev(struct platform_device *pdev) return container_of(pdev, struct omap_device, pdev); } +/** + * _add_optional_clock_alias - Add clock alias for hwmod optional clocks + * @od: struct omap_device *od + * + * For every optional clock present per hwmod per omap_device, this function + * adds an entry in the clocks list of the form + * if an entry is already present in it with the form + * + * The function is called from inside omap_device_build_ss(), after + * omap_device_register. + * + * This allows drivers to get a pointer to its optional clocks based on its role + * by calling clk_get(, ). + * + * No return value. + */ +static void _add_optional_clock_alias(struct omap_device *od, + struct omap_hwmod *oh) +{ + int i; + + for (i = 0; i < oh->opt_clks_cnt; i++) { + struct omap_hwmod_opt_clk *oc; + int r; + + oc = &oh->opt_clks[i]; + + if (!oc->_clk) + continue; + + r = clk_add_alias(oc->role, dev_name(&od->pdev.dev), + (char *)oc->clk, &od->pdev.dev); + if (r) + pr_err("omap_device: %s: clk_add_alias for %s failed\n", + dev_name(&od->pdev.dev), oc->role); + } +} + /* Public functions for use by core code */ @@ -421,8 +460,10 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id, else ret = omap_device_register(od); - for (i = 0; i < oh_cnt; i++) + for (i = 0; i < oh_cnt; i++) { hwmods[i]->od = od; + _add_optional_clock_alias(od, hwmods[i]); + } if (ret) goto odbs_exit4; -- cgit v1.1 From 74ff3a68ed11f1e9eede4fe301f42cc3cdf7396a Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 21 Sep 2010 15:02:23 -0600 Subject: OMAP: hwmod: improve documentation, clean up function names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch: - adds more documentation to the hwmod code - fixes some documentation typos elsewhere in the file - changes the _sysc_*() function names to appear in (verb, noun) order, to match the rest of the function names. This patch should not result in any functional change. Signed-off-by: Paul Walmsley Cc: Kevin Hilman Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 141 ++++++++++++++++++++++----- arch/arm/plat-omap/include/plat/omap_hwmod.h | 11 +-- 2 files changed, 123 insertions(+), 29 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index d694067..c3a5889 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -13,10 +13,102 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * This code manages "OMAP modules" (on-chip devices) and their - * integration with Linux device driver and bus code. - * - * References: + * Introduction + * ------------ + * One way to view an OMAP SoC is as a collection of largely unrelated + * IP blocks connected by interconnects. The IP blocks include + * devices such as ARM processors, audio serial interfaces, UARTs, + * etc. Some of these devices, like the DSP, are created by TI; + * others, like the SGX, largely originate from external vendors. In + * TI's documentation, on-chip devices are referred to as "OMAP + * modules." Some of these IP blocks are identical across several + * OMAP versions. Others are revised frequently. + * + * These OMAP modules are tied together by various interconnects. + * Most of the address and data flow between modules is via OCP-based + * interconnects such as the L3 and L4 buses; but there are other + * interconnects that distribute the hardware clock tree, handle idle + * and reset signaling, supply power, and connect the modules to + * various pads or balls on the OMAP package. + * + * OMAP hwmod provides a consistent way to describe the on-chip + * hardware blocks and their integration into the rest of the chip. + * This description can be automatically generated from the TI + * hardware database. OMAP hwmod provides a standard, consistent API + * to reset, enable, idle, and disable these hardware blocks. And + * hwmod provides a way for other core code, such as the Linux device + * code or the OMAP power management and address space mapping code, + * to query the hardware database. + * + * Using hwmod + * ----------- + * 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) @@ -654,7 +746,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index) } /** - * _sysc_enable - try to bring a module out of idle via OCP_SYSCONFIG + * _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG * @oh: struct omap_hwmod * * * If module is marked as SWSUP_SIDLE, force the module out of slave @@ -662,7 +754,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index) * as SWSUP_MSUSPEND, force the module out of master standby; * otherwise, configure it for smart-standby. No return value. */ -static void _sysc_enable(struct omap_hwmod *oh) +static void _enable_sysc(struct omap_hwmod *oh) { u8 idlemode, sf; u32 v; @@ -708,7 +800,7 @@ static void _sysc_enable(struct omap_hwmod *oh) } /** - * _sysc_idle - try to put a module into idle via OCP_SYSCONFIG + * _idle_sysc - try to put a module into idle via OCP_SYSCONFIG * @oh: struct omap_hwmod * * * If module is marked as SWSUP_SIDLE, force the module into slave @@ -716,7 +808,7 @@ static void _sysc_enable(struct omap_hwmod *oh) * as SWSUP_MSUSPEND, force the module into master standby; otherwise, * configure it for smart-standby. No return value. */ -static void _sysc_idle(struct omap_hwmod *oh) +static void _idle_sysc(struct omap_hwmod *oh) { u8 idlemode, sf; u32 v; @@ -743,13 +835,13 @@ static void _sysc_idle(struct omap_hwmod *oh) } /** - * _sysc_shutdown - force a module into idle via OCP_SYSCONFIG + * _shutdown_sysc - force a module into idle via OCP_SYSCONFIG * @oh: struct omap_hwmod * * * Force the module into slave idle and master suspend. No return * value. */ -static void _sysc_shutdown(struct omap_hwmod *oh) +static void _shutdown_sysc(struct omap_hwmod *oh) { u32 v; u8 sf; @@ -1071,8 +1163,11 @@ dis_opt_clks: * @oh: struct omap_hwmod * * * Enables an omap_hwmod @oh such that the MPU can access the hwmod's - * register target. Returns -EINVAL if the hwmod is in the wrong - * state or passes along the return value of _wait_target_ready(). + * register target. (This function has a full name -- + * _omap_hwmod_enable() rather than simply _enable() -- because it is + * currently required by the pm34xx.c idle loop.) Returns -EINVAL if + * the hwmod is in the wrong state or passes along the return value of + * _wait_target_ready(). */ int _omap_hwmod_enable(struct omap_hwmod *oh) { @@ -1110,7 +1205,7 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) if (oh->class->sysc) { if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) _update_sysc_cache(oh); - _sysc_enable(oh); + _enable_sysc(oh); } } else { pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", @@ -1121,12 +1216,14 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) } /** - * _idle - idle an omap_hwmod + * _omap_hwmod_idle - idle an omap_hwmod * @oh: struct omap_hwmod * * * Idles an omap_hwmod @oh. This should be called once the hwmod has - * no further work. Returns -EINVAL if the hwmod is in the wrong - * state or returns 0. + * no further work. (This function has a full name -- + * _omap_hwmod_idle() rather than simply _idle() -- because it is + * currently required by the pm34xx.c idle loop.) Returns -EINVAL if + * the hwmod is in the wrong state or returns 0. */ int _omap_hwmod_idle(struct omap_hwmod *oh) { @@ -1139,7 +1236,7 @@ int _omap_hwmod_idle(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: idling\n", oh->name); if (oh->class->sysc) - _sysc_idle(oh); + _idle_sysc(oh); _del_initiator_dep(oh, mpu_oh); _disable_clocks(oh); @@ -1169,7 +1266,7 @@ static int _shutdown(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: disabling\n", oh->name); if (oh->class->sysc) - _sysc_shutdown(oh); + _shutdown_sysc(oh); /* * If an IP contains only one HW reset line, then assert it @@ -1262,7 +1359,7 @@ static int _setup(struct omap_hwmod *oh, void *data) */ if (oh->class->sysc) { _update_sysc_cache(oh); - _sysc_enable(oh); + _enable_sysc(oh); } } @@ -1518,7 +1615,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh) * omap_hwmod_enable - enable an omap_hwmod * @oh: struct omap_hwmod * * - * Enable an omap_hwomd @oh. Intended to be called by omap_device_enable(). + * Enable an omap_hwmod @oh. Intended to be called by omap_device_enable(). * Returns -EINVAL on error or passes along the return value from _enable(). */ int omap_hwmod_enable(struct omap_hwmod *oh) @@ -1540,7 +1637,7 @@ int omap_hwmod_enable(struct omap_hwmod *oh) * omap_hwmod_idle - idle an omap_hwmod * @oh: struct omap_hwmod * * - * Idle an omap_hwomd @oh. Intended to be called by omap_device_idle(). + * Idle an omap_hwmod @oh. Intended to be called by omap_device_idle(). * Returns -EINVAL on error or passes along the return value from _idle(). */ int omap_hwmod_idle(struct omap_hwmod *oh) @@ -1559,7 +1656,7 @@ int omap_hwmod_idle(struct omap_hwmod *oh) * omap_hwmod_shutdown - shutdown an omap_hwmod * @oh: struct omap_hwmod * * - * Shutdown an omap_hwomd @oh. Intended to be called by + * Shutdown an omap_hwmod @oh. Intended to be called by * omap_device_shutdown(). Returns -EINVAL on error or passes along * the return value from _shutdown(). */ diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index ee53758..7290281 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -14,19 +14,16 @@ * * These headers and macros are used to define OMAP on-chip module * data and their integration with other OMAP modules and Linux. - * - * References: - * - 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 + * Copious documentation and references can also be found in the + * omap_hwmod code, in arch/arm/mach-omap2/omap_hwmod.c (as of this + * writing). * * To do: * - add interconnect error log structures * - add pinmuxing * - init_conn_id_bit (CONNID_BIT_VECTOR) * - implement default hwmod SMS/SDRC flags? + * - remove unused fields * */ #ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H -- cgit v1.1