From 724019b0137acf2ea43e5ca854798851f5ebf51f Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Fri, 1 Jul 2011 22:54:00 +0200 Subject: OMAP2+: hwmod: Fix smart-standby + wakeup support The commit 86009eb326afde34ffdc5648cd344aa86b8d58d4 was adding the wakeup support for new OMAP4 IPs. This support is incomplete for busmaster IPs that need as well to use smart-standby with wakeup. This new standbymode is suported on HSI and USB_HOST_FS for the moment. Add the new MSTANDBY_SMART_WKUP flag to mark the IPs that support this capability. Enable this new mode when applicable in _enable_wakeup, _disable_wakeup, _enable_sysc and _idle_sysc. The omap_hwmod_44xx_data.c will have to be updated to add this new flag. Signed-off-by: Benoit Cousson Signed-off-by: Djamil Elaidi Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 293fa6cd50e..384d3c3ec36 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -391,7 +391,8 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) if (!oh->class->sysc || !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || - (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) + (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || + (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP))) return -EINVAL; if (!oh->class->sysc->sysc_fields) { @@ -405,6 +406,8 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); /* XXX test pwrdm_get_wken for this hwmod's subsystem */ @@ -426,7 +429,8 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) if (!oh->class->sysc || !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || - (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) + (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || + (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP))) return -EINVAL; if (!oh->class->sysc->sysc_fields) { @@ -440,6 +444,8 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); /* XXX test pwrdm_get_wken for this hwmod's subsystem */ @@ -781,8 +787,16 @@ static void _enable_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? - HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART; + if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + idlemode = HWMOD_IDLEMODE_NO; + } else { + if (sf & SYSC_HAS_ENAWAKEUP) + _enable_wakeup(oh, &v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + idlemode = HWMOD_IDLEMODE_SMART_WKUP; + else + idlemode = HWMOD_IDLEMODE_SMART; + } _set_master_standbymode(oh, idlemode, &v); } @@ -840,8 +854,16 @@ static void _idle_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? - HWMOD_IDLEMODE_FORCE : HWMOD_IDLEMODE_SMART; + if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + idlemode = HWMOD_IDLEMODE_FORCE; + } else { + if (sf & SYSC_HAS_ENAWAKEUP) + _enable_wakeup(oh, &v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + idlemode = HWMOD_IDLEMODE_SMART_WKUP; + else + idlemode = HWMOD_IDLEMODE_SMART; + } _set_master_standbymode(oh, idlemode, &v); } -- cgit v1.2.3-18-g5258 From 6481c73c22613660a5b791d2b4d0faf60508d731 Mon Sep 17 00:00:00 2001 From: Miguel Vadillo Date: Fri, 1 Jul 2011 22:54:02 +0200 Subject: OMAP2+: hwmod: Enable module in shutdown to access sysconfig When calling the shutdown, the module may be already in idle. Accessing the sysconfig register will then lead to a crash. In that case, re-enable the module in order to allow the access to the sysconfig register. Signed-off-by: Miguel Vadillo Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 384d3c3ec36..cbc2a8a4ce3 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1396,8 +1396,11 @@ static int _shutdown(struct omap_hwmod *oh) } } - if (oh->class->sysc) + if (oh->class->sysc) { + if (oh->_state == _HWMOD_STATE_IDLE) + _enable(oh); _shutdown_sysc(oh); + } /* * If an IP contains only one HW reset line, then assert it -- cgit v1.2.3-18-g5258 From 1fe741139be5acfe3758b53cdbf0b5e3d26db3fe Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Fri, 1 Jul 2011 22:54:03 +0200 Subject: OMAP2+: hwmod: Do not write the enawakeup bit if SYSC_HAS_ENAWAKEUP is not set The Type 2 type of IPs will not have any enawakeup bit in their sysconfig. Writing to that bit will instead trigger a softreset. Check the flag to write this bit only if the module supports it. Reported-by: Miguel Vadillo Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index cbc2a8a4ce3..3800084a1e7 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -387,8 +387,6 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, */ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) { - u32 wakeup_mask; - if (!oh->class->sysc || !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || @@ -400,9 +398,8 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) return -EINVAL; } - wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); - - *v |= wakeup_mask; + if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) + *v |= 0x1 << oh->class->sysc->sysc_fields->enwkup_shift; if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); @@ -425,8 +422,6 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) */ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) { - u32 wakeup_mask; - if (!oh->class->sysc || !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || @@ -438,9 +433,8 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) return -EINVAL; } - wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); - - *v &= ~wakeup_mask; + if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) + *v &= ~(0x1 << oh->class->sysc->sysc_fields->enwkup_shift); if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v); -- cgit v1.2.3-18-g5258 From d24bcaa3fa711f7dd9c4aacf3c58083cf666418f Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Fri, 1 Jul 2011 22:54:04 +0200 Subject: OMAP2+: hwmod: Remove _populate_mpu_rt_base warning It is perfectly valid for some hwmod to not have any register target address for sysconfig. This is especially true for interconnect hwmods. Remove the warning. Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 3800084a1e7..f4014179d60 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1704,9 +1704,6 @@ static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data) return 0; oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); - if (!oh->_mpu_rt_va) - pr_warning("omap_hwmod: %s found no _mpu_rt_va for %s\n", - __func__, oh->name); return 0; } -- cgit v1.2.3-18-g5258 From 31f62866c578b3d47ef7810b336e9e193b90167f Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Fri, 1 Jul 2011 22:54:05 +0200 Subject: OMAP2+: hwmod: Fix the HW reset management The HW reset must be de-assert after the clocks are enabled but before waiting for the target to be ready. Otherwise the reset might not work properly since the clock is not running to proceed the reset. De-assert the reset after _enable_clocks and before _wait_target_ready. Re-assert it only when the clocks are disabled. Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index f4014179d60..df91bb1dc97 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1250,15 +1250,6 @@ static int _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); - /* Mux pins for device runtime if populated */ if (oh->mux && (!oh->mux->enabled || ((oh->_state == _HWMOD_STATE_IDLE) && @@ -1268,6 +1259,15 @@ static int _enable(struct omap_hwmod *oh) _add_initiator_dep(oh, mpu_oh); _enable_clocks(oh); + /* + * If an IP contains only one HW reset line, then de-assert it in order + * to allow the module state transition. 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); + r = _wait_target_ready(oh); if (!r) { oh->_state = _HWMOD_STATE_ENABLED; @@ -1396,13 +1396,6 @@ static int _shutdown(struct omap_hwmod *oh) _shutdown_sysc(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); @@ -1411,6 +1404,13 @@ static int _shutdown(struct omap_hwmod *oh) } /* XXX Should this code also force-disable the optional clocks? */ + /* + * If an IP contains only one HW reset line, then assert it + * after disabling the clocks and before shutting down the IP. + */ + if (oh->rst_lines_cnt == 1) + _assert_hardreset(oh, oh->rst_lines[0].name); + /* Mux pins to safe mode or use populated off mode values */ if (oh->mux) omap_hwmod_mux(oh->mux, _HWMOD_STATE_DISABLED); -- cgit v1.2.3-18-g5258 From 6652271a2556c086c04658dce16de2947e849ffd Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Fri, 1 Jul 2011 22:54:06 +0200 Subject: OMAP: hwmod: Add warnings if enable failed Change the debug into warning to check what IPs are failing. Signed-off-by: Benoit Cousson Cc: Rajendra Nayak Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index df91bb1dc97..64e98304621 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -944,6 +944,8 @@ static int _init_clocks(struct omap_hwmod *oh, void *data) if (!ret) oh->_state = _HWMOD_STATE_CLKS_INITED; + else + pr_warning("omap_hwmod: %s: cannot _init_clocks\n", oh->name); return ret; } -- cgit v1.2.3-18-g5258 From 34617e2a4d331fdd8172077d8c70a0421fc136e6 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Fri, 1 Jul 2011 22:54:07 +0200 Subject: OMAP: hwmod: Move pr_debug to improve the readability Move the pr_debug at the top of the function to trace the entry even if the first test is failing. That help understanding that we entered the function but failed in it. Move the _enable last part out of the test to reduce indentation and improve readability. Signed-off-by: Benoit Cousson Cc: Paul Walmsley Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 64e98304621..e530bcbdebf 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1242,6 +1242,8 @@ static int _enable(struct omap_hwmod *oh) { int r; + pr_debug("omap_hwmod: %s: enabling\n", oh->name); + if (oh->_state != _HWMOD_STATE_INITIALIZED && oh->_state != _HWMOD_STATE_IDLE && oh->_state != _HWMOD_STATE_DISABLED) { @@ -1250,8 +1252,6 @@ static int _enable(struct omap_hwmod *oh) return -EINVAL; } - pr_debug("omap_hwmod: %s: enabling\n", oh->name); - /* Mux pins for device runtime if populated */ if (oh->mux && (!oh->mux->enabled || ((oh->_state == _HWMOD_STATE_IDLE) && @@ -1271,19 +1271,21 @@ static int _enable(struct omap_hwmod *oh) _deassert_hardreset(oh, oh->rst_lines[0].name); r = _wait_target_ready(oh); - if (!r) { - oh->_state = _HWMOD_STATE_ENABLED; - - /* Access the sysconfig only if the target is ready */ - if (oh->class->sysc) { - if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) - _update_sysc_cache(oh); - _enable_sysc(oh); - } - } else { - _disable_clocks(oh); + if (r) { pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", oh->name, r); + _disable_clocks(oh); + + return r; + } + + oh->_state = _HWMOD_STATE_ENABLED; + + /* Access the sysconfig only if the target is ready */ + if (oh->class->sysc) { + if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) + _update_sysc_cache(oh); + _enable_sysc(oh); } return r; @@ -1299,14 +1301,14 @@ static int _enable(struct omap_hwmod *oh) */ static int _idle(struct omap_hwmod *oh) { + pr_debug("omap_hwmod: %s: idling\n", oh->name); + if (oh->_state != _HWMOD_STATE_ENABLED) { WARN(1, "omap_hwmod: %s: idle state can only be entered from " "enabled state\n", oh->name); return -EINVAL; } - pr_debug("omap_hwmod: %s: idling\n", oh->name); - if (oh->class->sysc) _idle_sysc(oh); _del_initiator_dep(oh, mpu_oh); -- cgit v1.2.3-18-g5258 From 78183f3fdf76f422431a81852468be01b36db325 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 9 Jul 2011 19:14:05 -0600 Subject: omap_hwmod: use a null structure record to terminate omap_hwmod_addr_space arrays Previously, struct omap_hwmod_addr_space arrays were unterminated; and users of these arrays used the ARRAY_SIZE() macro to determine the length of the array. However, ARRAY_SIZE() only works when the array is in the same scope as the macro user. So far this hasn't been a problem. However, to reduce duplicated data, a subsequent patch will move common data to a separate, shared file. When this is done, ARRAY_SIZE() will no longer be usable. This patch removes ARRAY_SIZE() usage for struct omap_hwmod_addr_space arrays and uses a null structure member as the array terminator instead. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 45 ++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 9 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 293fa6cd50e..77094d75367 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2,6 +2,7 @@ * omap_hwmod implementation for OMAP2/3/4 * * Copyright (C) 2009-2011 Nokia Corporation + * Copyright (C) 2011 Texas Instruments, Inc. * * Paul Walmsley, BenoƮt Cousson, Kevin Hilman * @@ -677,6 +678,29 @@ static void _disable_optional_clocks(struct omap_hwmod *oh) } } +/** + * _count_ocp_if_addr_spaces - count the number of address space entries for @oh + * @oh: struct omap_hwmod *oh + * + * Count and return the number of address space ranges associated with + * the hwmod @oh. Used to allocate struct resource data. Returns 0 + * if @oh is NULL. + */ +static int _count_ocp_if_addr_spaces(struct omap_hwmod_ocp_if *os) +{ + struct omap_hwmod_addr_space *mem; + int i = 0; + + if (!os || !os->addr) + return 0; + + do { + mem = &os->addr[i++]; + } while (mem->pa_start != mem->pa_end); + + return i; +} + /** * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use * @oh: struct omap_hwmod * @@ -722,8 +746,7 @@ static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index) { struct omap_hwmod_ocp_if *os; struct omap_hwmod_addr_space *mem; - int i; - int found = 0; + int i = 0, found = 0; void __iomem *va_start; if (!oh || oh->slaves_cnt == 0) @@ -731,12 +754,14 @@ static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index) os = oh->slaves[index]; - for (i = 0, mem = os->addr; i < os->addr_cnt; i++, mem++) { - if (mem->flags & ADDR_TYPE_RT) { + if (!os->addr) + return NULL; + + do { + mem = &os->addr[i++]; + if (mem->flags & ADDR_TYPE_RT) found = 1; - break; - } - } + } while (!found && mem->pa_start != mem->pa_end); if (found) { va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); @@ -1942,7 +1967,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) ret = oh->mpu_irqs_cnt + oh->sdma_reqs_cnt; for (i = 0; i < oh->slaves_cnt; i++) - ret += oh->slaves[i]->addr_cnt; + ret += _count_ocp_if_addr_spaces(oh->slaves[i]); return ret; } @@ -1982,10 +2007,12 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) for (i = 0; i < oh->slaves_cnt; i++) { struct omap_hwmod_ocp_if *os; + int addr_cnt; os = oh->slaves[i]; + addr_cnt = _count_ocp_if_addr_spaces(os); - for (j = 0; j < os->addr_cnt; j++) { + for (j = 0; j < addr_cnt; j++) { (res + r)->name = (os->addr + j)->name; (res + r)->start = (os->addr + j)->pa_start; (res + r)->end = (os->addr + j)->pa_end; -- cgit v1.2.3-18-g5258 From 212738a4499d278254ed6fdb400e3b4be4cb1de2 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 9 Jul 2011 19:14:06 -0600 Subject: omap_hwmod: use a terminator record with omap_hwmod_mpu_irqs arrays Previously, struct omap_hwmod_mpu_irqs arrays were unterminated; and users of these arrays used the ARRAY_SIZE() macro to determine the length of the array. However, ARRAY_SIZE() only works when the array is in the same scope as the macro user. So far this hasn't been a problem. However, to reduce duplicated data, a subsequent patch will move common data to a separate, shared file. When this is done, ARRAY_SIZE() will no longer be usable. This patch removes ARRAY_SIZE() usage for struct omap_hwmod_mpu_irqs arrays and uses a sentinel value (irq == -1) as the array terminator instead. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 77094d75367..21e3eb8e83c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -678,6 +678,29 @@ static void _disable_optional_clocks(struct omap_hwmod *oh) } } +/** + * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh + * @oh: struct omap_hwmod *oh + * + * Count and return the number of MPU IRQs associated with the hwmod + * @oh. Used to allocate struct resource data. Returns 0 if @oh is + * NULL. + */ +static int _count_mpu_irqs(struct omap_hwmod *oh) +{ + struct omap_hwmod_irq_info *ohii; + int i = 0; + + if (!oh || !oh->mpu_irqs) + return 0; + + do { + ohii = &oh->mpu_irqs[i++]; + } while (ohii->irq != -1); + + return i; +} + /** * _count_ocp_if_addr_spaces - count the number of address space entries for @oh * @oh: struct omap_hwmod *oh @@ -1964,7 +1987,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) { int ret, i; - ret = oh->mpu_irqs_cnt + oh->sdma_reqs_cnt; + ret = _count_mpu_irqs(oh) + oh->sdma_reqs_cnt; for (i = 0; i < oh->slaves_cnt; i++) ret += _count_ocp_if_addr_spaces(oh->slaves[i]); @@ -1984,12 +2007,13 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) */ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) { - int i, j; + int i, j, mpu_irqs_cnt; int r = 0; /* For each IRQ, DMA, memory area, fill in array.*/ - for (i = 0; i < oh->mpu_irqs_cnt; i++) { + mpu_irqs_cnt = _count_mpu_irqs(oh); + for (i = 0; i < mpu_irqs_cnt; i++) { (res + r)->name = (oh->mpu_irqs + i)->name; (res + r)->start = (oh->mpu_irqs + i)->irq; (res + r)->end = (oh->mpu_irqs + i)->irq; -- cgit v1.2.3-18-g5258 From bc6149587b309e3231e5ac7138b84197813e17ec Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Sat, 9 Jul 2011 19:14:07 -0600 Subject: omap_hwmod: use a terminator record with omap_hwmod_dma_info arrays Previously, struct omap_hwmod_dma_info arrays were unterminated; and users of these arrays used the ARRAY_SIZE() macro to determine the length of the array. However, ARRAY_SIZE() only works when the array is in the same scope as the macro user. So far this hasn't been a problem. However, to reduce duplicated data, a subsequent patch will move common data to a separate, shared file. When this is done, ARRAY_SIZE() will no longer be usable. This patch removes ARRAY_SIZE() usage for struct omap_hwmod_dma_info arrays and uses a sentinel value (irq == -1) as the array terminator instead. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 21e3eb8e83c..d1a8bdefea3 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -701,6 +701,29 @@ static int _count_mpu_irqs(struct omap_hwmod *oh) return i; } +/** + * _count_sdma_reqs - count the number of SDMA request lines associated with @oh + * @oh: struct omap_hwmod *oh + * + * Count and return the number of SDMA request lines associated with + * the hwmod @oh. Used to allocate struct resource data. Returns 0 + * if @oh is NULL. + */ +static int _count_sdma_reqs(struct omap_hwmod *oh) +{ + struct omap_hwmod_dma_info *ohdi; + int i = 0; + + if (!oh || !oh->sdma_reqs) + return 0; + + do { + ohdi = &oh->sdma_reqs[i++]; + } while (ohdi->dma_req != -1); + + return i; +} + /** * _count_ocp_if_addr_spaces - count the number of address space entries for @oh * @oh: struct omap_hwmod *oh @@ -1987,7 +2010,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) { int ret, i; - ret = _count_mpu_irqs(oh) + oh->sdma_reqs_cnt; + ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh); for (i = 0; i < oh->slaves_cnt; i++) ret += _count_ocp_if_addr_spaces(oh->slaves[i]); @@ -2007,7 +2030,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) */ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) { - int i, j, mpu_irqs_cnt; + int i, j, mpu_irqs_cnt, sdma_reqs_cnt; int r = 0; /* For each IRQ, DMA, memory area, fill in array.*/ @@ -2021,7 +2044,8 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) r++; } - for (i = 0; i < oh->sdma_reqs_cnt; i++) { + sdma_reqs_cnt = _count_sdma_reqs(oh); + for (i = 0; i < 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; -- cgit v1.2.3-18-g5258