Skip to content

Commit 5365efb

Browse files
Benoît CoussonPaul Walmsley
authored andcommitted
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 <[email protected]> [[email protected]: 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 <[email protected]> Cc: Kevin Hilman <[email protected]> Cc: Rajendra Nayak <[email protected]>
1 parent cf21405 commit 5365efb

File tree

2 files changed

+177
-8
lines changed

2 files changed

+177
-8
lines changed

arch/arm/mach-omap2/omap_hwmod.c

Lines changed: 160 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,13 @@
5050
#include <plat/powerdomain.h>
5151
#include <plat/clock.h>
5252
#include <plat/omap_hwmod.h>
53+
#include <plat/prcm.h>
5354

5455
#include "cm.h"
56+
#include "prm.h"
5557

56-
/* Maximum microseconds to wait for OMAP module to reset */
57-
#define MAX_MODULE_RESET_WAIT 10000
58+
/* Maximum microseconds to wait for OMAP module to softreset */
59+
#define MAX_MODULE_SOFTRESET_WAIT 10000
5860

5961
/* Name of the OMAP hwmod for the MPU */
6062
#define MPU_INITIATOR_NAME "mpu"
@@ -833,6 +835,130 @@ static int _wait_target_ready(struct omap_hwmod *oh)
833835
return ret;
834836
}
835837

838+
/**
839+
* _lookup_hardreset - return the register bit shift for this hwmod/reset line
840+
* @oh: struct omap_hwmod *
841+
* @name: name of the reset line in the context of this hwmod
842+
*
843+
* Return the bit position of the reset line that match the
844+
* input name. Return -ENOENT if not found.
845+
*/
846+
static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name)
847+
{
848+
int i;
849+
850+
for (i = 0; i < oh->rst_lines_cnt; i++) {
851+
const char *rst_line = oh->rst_lines[i].name;
852+
if (!strcmp(rst_line, name)) {
853+
u8 shift = oh->rst_lines[i].rst_shift;
854+
pr_debug("omap_hwmod: %s: _lookup_hardreset: %s: %d\n",
855+
oh->name, rst_line, shift);
856+
857+
return shift;
858+
}
859+
}
860+
861+
return -ENOENT;
862+
}
863+
864+
/**
865+
* _assert_hardreset - assert the HW reset line of submodules
866+
* contained in the hwmod module.
867+
* @oh: struct omap_hwmod *
868+
* @name: name of the reset line to lookup and assert
869+
*
870+
* Some IP like dsp, ipu or iva contain processor that require
871+
* an HW reset line to be assert / deassert in order to enable fully
872+
* the IP.
873+
*/
874+
static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
875+
{
876+
u8 shift;
877+
878+
if (!oh)
879+
return -EINVAL;
880+
881+
shift = _lookup_hardreset(oh, name);
882+
if (IS_ERR_VALUE(shift))
883+
return shift;
884+
885+
if (cpu_is_omap24xx() || cpu_is_omap34xx())
886+
return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs,
887+
shift);
888+
else if (cpu_is_omap44xx())
889+
return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg,
890+
shift);
891+
else
892+
return -EINVAL;
893+
}
894+
895+
/**
896+
* _deassert_hardreset - deassert the HW reset line of submodules contained
897+
* in the hwmod module.
898+
* @oh: struct omap_hwmod *
899+
* @name: name of the reset line to look up and deassert
900+
*
901+
* Some IP like dsp, ipu or iva contain processor that require
902+
* an HW reset line to be assert / deassert in order to enable fully
903+
* the IP.
904+
*/
905+
static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
906+
{
907+
u8 shift;
908+
int r;
909+
910+
if (!oh)
911+
return -EINVAL;
912+
913+
shift = _lookup_hardreset(oh, name);
914+
if (IS_ERR_VALUE(shift))
915+
return shift;
916+
917+
if (cpu_is_omap24xx() || cpu_is_omap34xx())
918+
r = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs,
919+
shift);
920+
else if (cpu_is_omap44xx())
921+
r = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg,
922+
shift);
923+
else
924+
return -EINVAL;
925+
926+
if (r == -EBUSY)
927+
pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name);
928+
929+
return r;
930+
}
931+
932+
/**
933+
* _read_hardreset - read the HW reset line state of submodules
934+
* contained in the hwmod module
935+
* @oh: struct omap_hwmod *
936+
* @name: name of the reset line to look up and read
937+
*
938+
* Return the state of the reset line.
939+
*/
940+
static int _read_hardreset(struct omap_hwmod *oh, const char *name)
941+
{
942+
u8 shift;
943+
944+
if (!oh)
945+
return -EINVAL;
946+
947+
shift = _lookup_hardreset(oh, name);
948+
if (IS_ERR_VALUE(shift))
949+
return shift;
950+
951+
if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
952+
return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs,
953+
shift);
954+
} else if (cpu_is_omap44xx()) {
955+
return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg,
956+
shift);
957+
} else {
958+
return -EINVAL;
959+
}
960+
}
961+
836962
/**
837963
* _reset - reset an omap_hwmod
838964
* @oh: struct omap_hwmod *
@@ -869,20 +995,20 @@ static int _reset(struct omap_hwmod *oh)
869995

870996
omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) &
871997
SYSS_RESETDONE_MASK),
872-
MAX_MODULE_RESET_WAIT, c);
998+
MAX_MODULE_SOFTRESET_WAIT, c);
873999

874-
if (c == MAX_MODULE_RESET_WAIT)
875-
WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n",
876-
oh->name, MAX_MODULE_RESET_WAIT);
1000+
if (c == MAX_MODULE_SOFTRESET_WAIT)
1001+
WARN(1, "omap_hwmod: %s: softreset failed (waited %d usec)\n",
1002+
oh->name, MAX_MODULE_SOFTRESET_WAIT);
8771003
else
878-
pr_debug("omap_hwmod: %s: reset in %d usec\n", oh->name, c);
1004+
pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
8791005

8801006
/*
8811007
* XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
8821008
* _wait_target_ready() or _reset()
8831009
*/
8841010

885-
return (c == MAX_MODULE_RESET_WAIT) ? -ETIMEDOUT : 0;
1011+
return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
8861012
}
8871013

8881014
/**
@@ -907,6 +1033,15 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
9071033

9081034
pr_debug("omap_hwmod: %s: enabling\n", oh->name);
9091035

1036+
/*
1037+
* If an IP contains only one HW reset line, then de-assert it in order
1038+
* to allow to enable the clocks. Otherwise the PRCM will return
1039+
* Intransition status, and the init will failed.
1040+
*/
1041+
if ((oh->_state == _HWMOD_STATE_INITIALIZED ||
1042+
oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
1043+
_deassert_hardreset(oh, oh->rst_lines[0].name);
1044+
9101045
/* XXX mux balls */
9111046

9121047
_add_initiator_dep(oh, mpu_oh);
@@ -981,6 +1116,13 @@ static int _shutdown(struct omap_hwmod *oh)
9811116
if (oh->class->sysc)
9821117
_sysc_shutdown(oh);
9831118

1119+
/*
1120+
* If an IP contains only one HW reset line, then assert it
1121+
* before disabling the clocks and shutting down the IP.
1122+
*/
1123+
if (oh->rst_lines_cnt == 1)
1124+
_assert_hardreset(oh, oh->rst_lines[0].name);
1125+
9841126
/* clocks and deps are already disabled in idle */
9851127
if (oh->_state == _HWMOD_STATE_ENABLED) {
9861128
_del_initiator_dep(oh, mpu_oh);
@@ -1038,6 +1180,16 @@ static int _setup(struct omap_hwmod *oh, void *data)
10381180
mutex_init(&oh->_mutex);
10391181
oh->_state = _HWMOD_STATE_INITIALIZED;
10401182

1183+
/*
1184+
* In the case of hwmod with hardreset that should not be
1185+
* de-assert at boot time, we have to keep the module
1186+
* initialized, because we cannot enable it properly with the
1187+
* reset asserted. Exit without warning because that behavior is
1188+
* expected.
1189+
*/
1190+
if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1)
1191+
return 0;
1192+
10411193
r = _omap_hwmod_enable(oh);
10421194
if (r) {
10431195
pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",

arch/arm/plat-omap/include/plat/omap_hwmod.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,19 @@ struct omap_hwmod_dma_info {
108108
u16 dma_req;
109109
};
110110

111+
/**
112+
* struct omap_hwmod_rst_info - IPs reset lines use by hwmod
113+
* @name: name of the reset line (module local name)
114+
* @rst_shift: Offset of the reset bit
115+
*
116+
* @name should be something short, e.g., "cpu0" or "rst". It is defined
117+
* locally to the hwmod.
118+
*/
119+
struct omap_hwmod_rst_info {
120+
const char *name;
121+
u8 rst_shift;
122+
};
123+
111124
/**
112125
* struct omap_hwmod_opt_clk - optional clocks used by this hwmod
113126
* @role: "sys", "32k", "tv", etc -- for use in clk_get()
@@ -328,10 +341,12 @@ struct omap_hwmod_omap2_prcm {
328341
/**
329342
* struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data
330343
* @clkctrl_reg: PRCM address of the clock control register
344+
* @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM
331345
* @submodule_wkdep_bit: bit shift of the WKDEP range
332346
*/
333347
struct omap_hwmod_omap4_prcm {
334348
void __iomem *clkctrl_reg;
349+
void __iomem *rstctrl_reg;
335350
u8 submodule_wkdep_bit;
336351
};
337352

@@ -451,6 +466,7 @@ struct omap_hwmod {
451466
struct omap_device *od;
452467
struct omap_hwmod_irq_info *mpu_irqs;
453468
struct omap_hwmod_dma_info *sdma_reqs;
469+
struct omap_hwmod_rst_info *rst_lines;
454470
union {
455471
struct omap_hwmod_omap2_prcm omap2;
456472
struct omap_hwmod_omap4_prcm omap4;
@@ -472,6 +488,7 @@ struct omap_hwmod {
472488
u8 response_lat;
473489
u8 mpu_irqs_cnt;
474490
u8 sdma_reqs_cnt;
491+
u8 rst_lines_cnt;
475492
u8 opt_clks_cnt;
476493
u8 masters_cnt;
477494
u8 slaves_cnt;

0 commit comments

Comments
 (0)