aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorKishon Vijay Abraham I <kishon@ti.com>2012-07-04 07:09:21 -0400
committerPaul Walmsley <paul@pwsan.com>2012-07-04 07:09:21 -0400
commit6668546f3bb4cc0dde75ac1ef1d436b67e4ef638 (patch)
treedc14b9f2dcfdd095fcd3ba632c8e4ab81f179c93 /arch
parent3f4990f44a5dcf15a053a041c813fa73ffa75608 (diff)
ARM: OMAP2+: hwmod code: add support to set dmadisable in hwmod framework
The DMADISABLE bit is a semi-automatic bit present in sysconfig register of some modules. When the DMA must perform read/write accesses, the DMADISABLE bit is cleared by the hardware. But when the DMA must stop for power management, software must set the DMADISABLE bit back to 1. In cases where the ROMCODE/BOOTLOADER uses dma, the hardware clears the DMADISABLE bit (but the romcode/bootloader might not set it back to 1). In order for the kernel to start in a clean state, it is necessary for the kernel to set DMADISABLE bit back to 1 (irrespective of whether it's been set to 1 in romcode or bootloader). During _reset of the (hwmod)device, the DMADISABLE bit is set so that it does not prevent idling of the system. (NOTE: having DMADISABLE to 0, prevents the system to idle) DMADISABLE bit is present in usbotgss module of omap5. Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> [paul@pwsan.com: updated to apply; fixed checkpatch warnings] Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c61
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_common_data.c1
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h5
3 files changed, 62 insertions, 5 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index a89214ee4694..98cde62c0cac 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -388,6 +388,49 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v)
388} 388}
389 389
390/** 390/**
391 * _set_dmadisable: set OCP_SYSCONFIG.DMADISABLE bit in @v
392 * @oh: struct omap_hwmod *
393 *
394 * The DMADISABLE bit is a semi-automatic bit present in sysconfig register
395 * of some modules. When the DMA must perform read/write accesses, the
396 * DMADISABLE bit is cleared by the hardware. But when the DMA must stop
397 * for power management, software must set the DMADISABLE bit back to 1.
398 *
399 * Set the DMADISABLE bit in @v for hwmod @oh. Returns -EINVAL upon
400 * error or 0 upon success.
401 */
402static int _set_dmadisable(struct omap_hwmod *oh)
403{
404 u32 v;
405 u32 dmadisable_mask;
406
407 if (!oh->class->sysc ||
408 !(oh->class->sysc->sysc_flags & SYSC_HAS_DMADISABLE))
409 return -EINVAL;
410
411 if (!oh->class->sysc->sysc_fields) {
412 WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
413 return -EINVAL;
414 }
415
416 /* clocks must be on for this operation */
417 if (oh->_state != _HWMOD_STATE_ENABLED) {
418 pr_warn("omap_hwmod: %s: dma can be disabled only from enabled state\n", oh->name);
419 return -EINVAL;
420 }
421
422 pr_debug("omap_hwmod: %s: setting DMADISABLE\n", oh->name);
423
424 v = oh->_sysc_cache;
425 dmadisable_mask =
426 (0x1 << oh->class->sysc->sysc_fields->dmadisable_shift);
427 v |= dmadisable_mask;
428 _write_sysconfig(v, oh);
429
430 return 0;
431}
432
433/**
391 * _set_module_autoidle: set the OCP_SYSCONFIG AUTOIDLE field in @v 434 * _set_module_autoidle: set the OCP_SYSCONFIG AUTOIDLE field in @v
392 * @oh: struct omap_hwmod * 435 * @oh: struct omap_hwmod *
393 * @autoidle: desired AUTOIDLE bitfield value (0 or 1) 436 * @autoidle: desired AUTOIDLE bitfield value (0 or 1)
@@ -1698,11 +1741,17 @@ dis_opt_clks:
1698 * therefore have no OCP header registers to access. Others (like the 1741 * therefore have no OCP header registers to access. Others (like the
1699 * IVA) have idiosyncratic reset sequences. So for these relatively 1742 * IVA) have idiosyncratic reset sequences. So for these relatively
1700 * rare cases, custom reset code can be supplied in the struct 1743 * rare cases, custom reset code can be supplied in the struct
1701 * omap_hwmod_class .reset function pointer. Passes along the return 1744 * omap_hwmod_class .reset function pointer.
1702 * value from either _ocp_softreset() or the custom reset function - 1745 *
1703 * these must return -EINVAL if the hwmod cannot be reset this way or 1746 * _set_dmadisable() is called to set the DMADISABLE bit so that it
1704 * if the hwmod is in the wrong state, -ETIMEDOUT if the module did 1747 * does not prevent idling of the system. This is necessary for cases
1705 * not reset in time, or 0 upon success. 1748 * where ROMCODE/BOOTLOADER uses dma and transfers control to the
1749 * kernel without disabling dma.
1750 *
1751 * Passes along the return value from either _ocp_softreset() or the
1752 * custom reset function - these must return -EINVAL if the hwmod
1753 * cannot be reset this way or if the hwmod is in the wrong state,
1754 * -ETIMEDOUT if the module did not reset in time, or 0 upon success.
1706 */ 1755 */
1707static int _reset(struct omap_hwmod *oh) 1756static int _reset(struct omap_hwmod *oh)
1708{ 1757{
@@ -1724,6 +1773,8 @@ static int _reset(struct omap_hwmod *oh)
1724 } 1773 }
1725 } 1774 }
1726 1775
1776 _set_dmadisable(oh);
1777
1727 /* 1778 /*
1728 * OCP_SYSCONFIG bits need to be reprogrammed after a 1779 * OCP_SYSCONFIG bits need to be reprogrammed after a
1729 * softreset. The _enable() function should be split to avoid 1780 * softreset. The _enable() function should be split to avoid
diff --git a/arch/arm/mach-omap2/omap_hwmod_common_data.c b/arch/arm/mach-omap2/omap_hwmod_common_data.c
index 51e5418899fb..aff613852911 100644
--- a/arch/arm/mach-omap2/omap_hwmod_common_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_common_data.c
@@ -47,6 +47,7 @@ struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2 = {
47 .midle_shift = SYSC_TYPE2_MIDLEMODE_SHIFT, 47 .midle_shift = SYSC_TYPE2_MIDLEMODE_SHIFT,
48 .sidle_shift = SYSC_TYPE2_SIDLEMODE_SHIFT, 48 .sidle_shift = SYSC_TYPE2_SIDLEMODE_SHIFT,
49 .srst_shift = SYSC_TYPE2_SOFTRESET_SHIFT, 49 .srst_shift = SYSC_TYPE2_SOFTRESET_SHIFT,
50 .dmadisable_shift = SYSC_TYPE2_DMADISABLE_SHIFT,
50}; 51};
51 52
52struct omap_dss_dispc_dev_attr omap2_3_dss_dispc_dev_attr = { 53struct omap_dss_dispc_dev_attr omap2_3_dss_dispc_dev_attr = {
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index da22acd0ce7a..27455ed0a2ab 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -69,6 +69,8 @@ extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2;
69#define SYSC_TYPE2_SIDLEMODE_MASK (0x3 << SYSC_TYPE2_SIDLEMODE_SHIFT) 69#define SYSC_TYPE2_SIDLEMODE_MASK (0x3 << SYSC_TYPE2_SIDLEMODE_SHIFT)
70#define SYSC_TYPE2_MIDLEMODE_SHIFT 4 70#define SYSC_TYPE2_MIDLEMODE_SHIFT 4
71#define SYSC_TYPE2_MIDLEMODE_MASK (0x3 << SYSC_TYPE2_MIDLEMODE_SHIFT) 71#define SYSC_TYPE2_MIDLEMODE_MASK (0x3 << SYSC_TYPE2_MIDLEMODE_SHIFT)
72#define SYSC_TYPE2_DMADISABLE_SHIFT 16
73#define SYSC_TYPE2_DMADISABLE_MASK (0x1 << SYSC_TYPE2_DMADISABLE_SHIFT)
72 74
73/* OCP SYSSTATUS bit shifts/masks */ 75/* OCP SYSSTATUS bit shifts/masks */
74#define SYSS_RESETDONE_SHIFT 0 76#define SYSS_RESETDONE_SHIFT 0
@@ -283,6 +285,7 @@ struct omap_hwmod_ocp_if {
283#define SYSS_HAS_RESET_STATUS (1 << 7) 285#define SYSS_HAS_RESET_STATUS (1 << 7)
284#define SYSC_NO_CACHE (1 << 8) /* XXX SW flag, belongs elsewhere */ 286#define SYSC_NO_CACHE (1 << 8) /* XXX SW flag, belongs elsewhere */
285#define SYSC_HAS_RESET_STATUS (1 << 9) 287#define SYSC_HAS_RESET_STATUS (1 << 9)
288#define SYSC_HAS_DMADISABLE (1 << 10)
286 289
287/* omap_hwmod_sysconfig.clockact flags */ 290/* omap_hwmod_sysconfig.clockact flags */
288#define CLOCKACT_TEST_BOTH 0x0 291#define CLOCKACT_TEST_BOTH 0x0
@@ -298,6 +301,7 @@ struct omap_hwmod_ocp_if {
298 * @enwkup_shift: Offset of the enawakeup bit 301 * @enwkup_shift: Offset of the enawakeup bit
299 * @srst_shift: Offset of the softreset bit 302 * @srst_shift: Offset of the softreset bit
300 * @autoidle_shift: Offset of the autoidle bit 303 * @autoidle_shift: Offset of the autoidle bit
304 * @dmadisable_shift: Offset of the dmadisable bit
301 */ 305 */
302struct omap_hwmod_sysc_fields { 306struct omap_hwmod_sysc_fields {
303 u8 midle_shift; 307 u8 midle_shift;
@@ -306,6 +310,7 @@ struct omap_hwmod_sysc_fields {
306 u8 enwkup_shift; 310 u8 enwkup_shift;
307 u8 srst_shift; 311 u8 srst_shift;
308 u8 autoidle_shift; 312 u8 autoidle_shift;
313 u8 dmadisable_shift;
309}; 314};
310 315
311/** 316/**