aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2012-04-19 02:49:09 -0400
committerPaul Walmsley <paul@pwsan.com>2012-04-19 02:49:09 -0400
commit30e105c000abbac55602b37f4831437bca5487b0 (patch)
treefdbfdb8ad21db6289d875c690d643d6a73c989d0 /arch/arm
parentf2f5736cf83fff7e95991390b2a4b481818e29b5 (diff)
ARM: OMAP2+: hwmod: revise the IP block reset process
Revise the IP block reset process. This patch ensures that the OCP_SYSCONFIG registers are reloaded after a custom reset. Since OCP_SYSCONFIG bits are cleared during reset, they should be reprogrammed unless the IP block is being left in reset. (The only IP blocks that are left in reset are IP blocks with hardreset lines and no custom reset function.) If the IP block is left in reset, then it is inaccessible to the MPU, and an access to the OCP_SYSCONFIG register will cause an abort. This version incorporates comments from Omar Ramirez Luna <omar.ramirez@ti.com> to skip the OCP_SYSCONFIG access after asserting hardreset lines. This allows the MMU (IOMMU) IP block, which has both hardreset lines and an OCP_SYSCONFIG register. Also, ignore _ocp_softreset() errors if the IP block doesn't include a softreset bit. This is needed since a subsequent patch will start taking the return value of the _reset() function seriously. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Benoît Cousson <b-cousson@ti.com> Cc: Omar Ramirez Luna <omar.ramirez@ti.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c69
1 files changed, 46 insertions, 23 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 4997c1a8b59d..5b07ad0251d7 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2,7 +2,7 @@
2 * omap_hwmod implementation for OMAP2/3/4 2 * omap_hwmod implementation for OMAP2/3/4
3 * 3 *
4 * Copyright (C) 2009-2011 Nokia Corporation 4 * Copyright (C) 2009-2011 Nokia Corporation
5 * Copyright (C) 2011 Texas Instruments, Inc. 5 * Copyright (C) 2011-2012 Texas Instruments, Inc.
6 * 6 *
7 * Paul Walmsley, Benoît Cousson, Kevin Hilman 7 * Paul Walmsley, Benoît Cousson, Kevin Hilman
8 * 8 *
@@ -1382,9 +1382,9 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
1382 * @oh: struct omap_hwmod * 1382 * @oh: struct omap_hwmod *
1383 * 1383 *
1384 * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be 1384 * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be
1385 * enabled for this to work. Returns -EINVAL if the hwmod cannot be 1385 * enabled for this to work. Returns -ENOENT if the hwmod cannot be
1386 * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if 1386 * reset this way, -EINVAL if the hwmod is in the wrong state,
1387 * the module did not reset in time, or 0 upon success. 1387 * -ETIMEDOUT if the module did not reset in time, or 0 upon success.
1388 * 1388 *
1389 * In OMAP3 a specific SYSSTATUS register is used to get the reset status. 1389 * In OMAP3 a specific SYSSTATUS register is used to get the reset status.
1390 * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead 1390 * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead
@@ -1401,7 +1401,7 @@ static int _ocp_softreset(struct omap_hwmod *oh)
1401 1401
1402 if (!oh->class->sysc || 1402 if (!oh->class->sysc ||
1403 !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) 1403 !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
1404 return -EINVAL; 1404 return -ENOENT;
1405 1405
1406 /* clocks must be on for this operation */ 1406 /* clocks must be on for this operation */
1407 if (oh->_state != _HWMOD_STATE_ENABLED) { 1407 if (oh->_state != _HWMOD_STATE_ENABLED) {
@@ -1462,37 +1462,60 @@ dis_opt_clks:
1462 * _reset - reset an omap_hwmod 1462 * _reset - reset an omap_hwmod
1463 * @oh: struct omap_hwmod * 1463 * @oh: struct omap_hwmod *
1464 * 1464 *
1465 * Resets an omap_hwmod @oh. The default software reset mechanism for 1465 * Resets an omap_hwmod @oh. If the module has a custom reset
1466 * most OMAP IP blocks is triggered via the OCP_SYSCONFIG.SOFTRESET 1466 * function pointer defined, then call it to reset the IP block, and
1467 * bit. However, some hwmods cannot be reset via this method: some 1467 * pass along its return value to the caller. Otherwise, if the IP
1468 * are not targets and therefore have no OCP header registers to 1468 * block has an OCP_SYSCONFIG register with a SOFTRESET bitfield
1469 * access; others (like the IVA) have idiosyncratic reset sequences. 1469 * associated with it, call a function to reset the IP block via that
1470 * So for these relatively rare cases, custom reset code can be 1470 * method, and pass along the return value to the caller. Finally, if
1471 * supplied in the struct omap_hwmod_class .reset function pointer. 1471 * the IP block has some hardreset lines associated with it, assert
1472 * Passes along the return value from either _reset() or the custom 1472 * all of those, but do _not_ deassert them. (This is because driver
1473 * reset function - these must return -EINVAL if the hwmod cannot be 1473 * authors have expressed an apparent requirement to control the
1474 * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if 1474 * deassertion of the hardreset lines themselves.)
1475 * the module did not reset in time, or 0 upon success. 1475 *
1476 * The default software reset mechanism for most OMAP IP blocks is
1477 * triggered via the OCP_SYSCONFIG.SOFTRESET bit. However, some
1478 * hwmods cannot be reset via this method. Some are not targets and
1479 * therefore have no OCP header registers to access. Others (like the
1480 * IVA) have idiosyncratic reset sequences. So for these relatively
1481 * rare cases, custom reset code can be supplied in the struct
1482 * omap_hwmod_class .reset function pointer. Passes along the return
1483 * value from either _ocp_softreset() or the custom reset function -
1484 * these must return -EINVAL if the hwmod cannot be reset this way or
1485 * if the hwmod is in the wrong state, -ETIMEDOUT if the module did
1486 * not reset in time, or 0 upon success.
1476 */ 1487 */
1477static int _reset(struct omap_hwmod *oh) 1488static int _reset(struct omap_hwmod *oh)
1478{ 1489{
1479 int ret; 1490 int i, r;
1480 1491
1481 pr_debug("omap_hwmod: %s: resetting\n", oh->name); 1492 pr_debug("omap_hwmod: %s: resetting\n", oh->name);
1482 1493
1494 if (oh->class->reset) {
1495 r = oh->class->reset(oh);
1496 } else {
1497 if (oh->rst_lines_cnt > 0) {
1498 for (i = 0; i < oh->rst_lines_cnt; i++)
1499 _assert_hardreset(oh, oh->rst_lines[i].name);
1500 return 0;
1501 } else {
1502 r = _ocp_softreset(oh);
1503 if (r == -ENOENT)
1504 r = 0;
1505 }
1506 }
1507
1483 /* 1508 /*
1484 * XXX We're not resetting modules with hardreset lines 1509 * OCP_SYSCONFIG bits need to be reprogrammed after a
1485 * automatically here. Should we do this also, or just expect 1510 * softreset. The _enable() function should be split to avoid
1486 * those modules to define custom reset functions? 1511 * the rewrite of the OCP_SYSCONFIG register.
1487 */ 1512 */
1488 ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh);
1489
1490 if (oh->class->sysc) { 1513 if (oh->class->sysc) {
1491 _update_sysc_cache(oh); 1514 _update_sysc_cache(oh);
1492 _enable_sysc(oh); 1515 _enable_sysc(oh);
1493 } 1516 }
1494 1517
1495 return ret; 1518 return r;
1496} 1519}
1497 1520
1498/** 1521/**