aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorBenoƮt Cousson <b-cousson@ti.com>2010-09-21 12:34:11 -0400
committerPaul Walmsley <paul@pwsan.com>2010-09-21 17:12:40 -0400
commit5365efbe29250a227502256cc912351fe2157b42 (patch)
treebfa7ab23b7070e37806aeaba39e2dc7d589f45df /arch/arm
parentcf21405fd51b416f071edb546631a6ecd2112263 (diff)
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 <b-cousson@ti.com> [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 <paul@pwsan.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Rajendra Nayak <rnayak@ti.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c168
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h17
2 files changed, 177 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 3084409ad1dc..f4a569c74700 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -50,11 +50,13 @@
50#include <plat/powerdomain.h> 50#include <plat/powerdomain.h>
51#include <plat/clock.h> 51#include <plat/clock.h>
52#include <plat/omap_hwmod.h> 52#include <plat/omap_hwmod.h>
53#include <plat/prcm.h>
53 54
54#include "cm.h" 55#include "cm.h"
56#include "prm.h"
55 57
56/* Maximum microseconds to wait for OMAP module to reset */ 58/* Maximum microseconds to wait for OMAP module to softreset */
57#define MAX_MODULE_RESET_WAIT 10000 59#define MAX_MODULE_SOFTRESET_WAIT 10000
58 60
59/* Name of the OMAP hwmod for the MPU */ 61/* Name of the OMAP hwmod for the MPU */
60#define MPU_INITIATOR_NAME "mpu" 62#define MPU_INITIATOR_NAME "mpu"
@@ -834,6 +836,130 @@ static int _wait_target_ready(struct omap_hwmod *oh)
834} 836}
835 837
836/** 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 */
846static 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 */
874static 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 */
905static 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 */
940static 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
962/**
837 * _reset - reset an omap_hwmod 963 * _reset - reset an omap_hwmod
838 * @oh: struct omap_hwmod * 964 * @oh: struct omap_hwmod *
839 * 965 *
@@ -869,20 +995,20 @@ static int _reset(struct omap_hwmod *oh)
869 995
870 omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) & 996 omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) &
871 SYSS_RESETDONE_MASK), 997 SYSS_RESETDONE_MASK),
872 MAX_MODULE_RESET_WAIT, c); 998 MAX_MODULE_SOFTRESET_WAIT, c);
873 999
874 if (c == MAX_MODULE_RESET_WAIT) 1000 if (c == MAX_MODULE_SOFTRESET_WAIT)
875 WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n", 1001 WARN(1, "omap_hwmod: %s: softreset failed (waited %d usec)\n",
876 oh->name, MAX_MODULE_RESET_WAIT); 1002 oh->name, MAX_MODULE_SOFTRESET_WAIT);
877 else 1003 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);
879 1005
880 /* 1006 /*
881 * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from 1007 * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
882 * _wait_target_ready() or _reset() 1008 * _wait_target_ready() or _reset()
883 */ 1009 */
884 1010
885 return (c == MAX_MODULE_RESET_WAIT) ? -ETIMEDOUT : 0; 1011 return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
886} 1012}
887 1013
888/** 1014/**
@@ -907,6 +1033,15 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
907 1033
908 pr_debug("omap_hwmod: %s: enabling\n", oh->name); 1034 pr_debug("omap_hwmod: %s: enabling\n", oh->name);
909 1035
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
910 /* XXX mux balls */ 1045 /* XXX mux balls */
911 1046
912 _add_initiator_dep(oh, mpu_oh); 1047 _add_initiator_dep(oh, mpu_oh);
@@ -981,6 +1116,13 @@ static int _shutdown(struct omap_hwmod *oh)
981 if (oh->class->sysc) 1116 if (oh->class->sysc)
982 _sysc_shutdown(oh); 1117 _sysc_shutdown(oh);
983 1118
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
984 /* clocks and deps are already disabled in idle */ 1126 /* clocks and deps are already disabled in idle */
985 if (oh->_state == _HWMOD_STATE_ENABLED) { 1127 if (oh->_state == _HWMOD_STATE_ENABLED) {
986 _del_initiator_dep(oh, mpu_oh); 1128 _del_initiator_dep(oh, mpu_oh);
@@ -1038,6 +1180,16 @@ static int _setup(struct omap_hwmod *oh, void *data)
1038 mutex_init(&oh->_mutex); 1180 mutex_init(&oh->_mutex);
1039 oh->_state = _HWMOD_STATE_INITIALIZED; 1181 oh->_state = _HWMOD_STATE_INITIALIZED;
1040 1182
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
1041 r = _omap_hwmod_enable(oh); 1193 r = _omap_hwmod_enable(oh);
1042 if (r) { 1194 if (r) {
1043 pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", 1195 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 03350bac01d8..590bfae250e8 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 {
109}; 109};
110 110
111/** 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 */
119struct omap_hwmod_rst_info {
120 const char *name;
121 u8 rst_shift;
122};
123
124/**
112 * struct omap_hwmod_opt_clk - optional clocks used by this hwmod 125 * struct omap_hwmod_opt_clk - optional clocks used by this hwmod
113 * @role: "sys", "32k", "tv", etc -- for use in clk_get() 126 * @role: "sys", "32k", "tv", etc -- for use in clk_get()
114 * @clk: opt clock: OMAP clock name 127 * @clk: opt clock: OMAP clock name
@@ -328,10 +341,12 @@ struct omap_hwmod_omap2_prcm {
328/** 341/**
329 * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data 342 * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data
330 * @clkctrl_reg: PRCM address of the clock control register 343 * @clkctrl_reg: PRCM address of the clock control register
344 * @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM
331 * @submodule_wkdep_bit: bit shift of the WKDEP range 345 * @submodule_wkdep_bit: bit shift of the WKDEP range
332 */ 346 */
333struct omap_hwmod_omap4_prcm { 347struct omap_hwmod_omap4_prcm {
334 void __iomem *clkctrl_reg; 348 void __iomem *clkctrl_reg;
349 void __iomem *rstctrl_reg;
335 u8 submodule_wkdep_bit; 350 u8 submodule_wkdep_bit;
336}; 351};
337 352
@@ -451,6 +466,7 @@ struct omap_hwmod {
451 struct omap_device *od; 466 struct omap_device *od;
452 struct omap_hwmod_irq_info *mpu_irqs; 467 struct omap_hwmod_irq_info *mpu_irqs;
453 struct omap_hwmod_dma_info *sdma_reqs; 468 struct omap_hwmod_dma_info *sdma_reqs;
469 struct omap_hwmod_rst_info *rst_lines;
454 union { 470 union {
455 struct omap_hwmod_omap2_prcm omap2; 471 struct omap_hwmod_omap2_prcm omap2;
456 struct omap_hwmod_omap4_prcm omap4; 472 struct omap_hwmod_omap4_prcm omap4;
@@ -472,6 +488,7 @@ struct omap_hwmod {
472 u8 response_lat; 488 u8 response_lat;
473 u8 mpu_irqs_cnt; 489 u8 mpu_irqs_cnt;
474 u8 sdma_reqs_cnt; 490 u8 sdma_reqs_cnt;
491 u8 rst_lines_cnt;
475 u8 opt_clks_cnt; 492 u8 opt_clks_cnt;
476 u8 masters_cnt; 493 u8 masters_cnt;
477 u8 slaves_cnt; 494 u8 slaves_cnt;