Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
9af2ebbd
K
Kernel
项目概览
openeuler
/
Kernel
大约 1 年 前同步成功
通知
7
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
9af2ebbd
编写于
9月 23, 2010
作者:
T
Tony Lindgren
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'hwmod_2.6.37' of
git://git.pwsan.com/linux-2.6
into omap-for-linus
上级
493c32a0
74ff3a68
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
829 addition
and
110 deletion
+829
-110
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/Makefile
+2
-2
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.c
+472
-90
arch/arm/mach-omap2/prcm.c
arch/arm/mach-omap2/prcm.c
+27
-2
arch/arm/mach-omap2/prm.h
arch/arm/mach-omap2/prm.h
+17
-1
arch/arm/mach-omap2/prm2xxx_3xxx.c
arch/arm/mach-omap2/prm2xxx_3xxx.c
+110
-0
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-omap2/prm44xx.c
+116
-0
arch/arm/plat-omap/include/plat/omap_hwmod.h
arch/arm/plat-omap/include/plat/omap_hwmod.h
+41
-14
arch/arm/plat-omap/include/plat/prcm.h
arch/arm/plat-omap/include/plat/prcm.h
+2
-0
arch/arm/plat-omap/omap_device.c
arch/arm/plat-omap/omap_device.c
+42
-1
未找到文件。
arch/arm/mach-omap2/Makefile
浏览文件 @
9af2ebbd
...
...
@@ -5,7 +5,7 @@
# Common support
obj-y
:=
id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o
omap-2-3-common
=
irq.o sdrc.o
omap-2-3-common
=
irq.o sdrc.o
prm2xxx_3xxx.o
hwmod-common
=
omap_hwmod.o
\
omap_hwmod_common_data.o
prcm-common
=
prcm.o powerdomain.o
...
...
@@ -15,7 +15,7 @@ clock-common = clock.o clock_common_data.o \
obj-$(CONFIG_ARCH_OMAP2)
+=
$
(
omap-2-3-common
)
$
(
prcm-common
)
$
(
hwmod-common
)
obj-$(CONFIG_ARCH_OMAP3)
+=
$
(
omap-2-3-common
)
$
(
prcm-common
)
$
(
hwmod-common
)
obj-$(CONFIG_ARCH_OMAP4)
+=
$
(
prcm-common
)
$
(
hwmod-common
)
obj-$(CONFIG_ARCH_OMAP4)
+=
$
(
prcm-common
)
prm44xx.o
$
(
hwmod-common
)
obj-$(CONFIG_OMAP_MCBSP)
+=
mcbsp.o
...
...
arch/arm/mach-omap2/omap_hwmod.c
浏览文件 @
9af2ebbd
...
...
@@ -13,10 +13,102 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This code manages "OMAP modules" (on-chip devices) and their
* integration with Linux device driver and bus code.
*
* References:
* Introduction
* ------------
* One way to view an OMAP SoC is as a collection of largely unrelated
* IP blocks connected by interconnects. The IP blocks include
* devices such as ARM processors, audio serial interfaces, UARTs,
* etc. Some of these devices, like the DSP, are created by TI;
* others, like the SGX, largely originate from external vendors. In
* TI's documentation, on-chip devices are referred to as "OMAP
* modules." Some of these IP blocks are identical across several
* OMAP versions. Others are revised frequently.
*
* These OMAP modules are tied together by various interconnects.
* Most of the address and data flow between modules is via OCP-based
* interconnects such as the L3 and L4 buses; but there are other
* interconnects that distribute the hardware clock tree, handle idle
* and reset signaling, supply power, and connect the modules to
* various pads or balls on the OMAP package.
*
* OMAP hwmod provides a consistent way to describe the on-chip
* hardware blocks and their integration into the rest of the chip.
* This description can be automatically generated from the TI
* hardware database. OMAP hwmod provides a standard, consistent API
* to reset, enable, idle, and disable these hardware blocks. And
* hwmod provides a way for other core code, such as the Linux device
* code or the OMAP power management and address space mapping code,
* to query the hardware database.
*
* Using hwmod
* -----------
* Drivers won't call hwmod functions directly. That is done by the
* omap_device code, and in rare occasions, by custom integration code
* in arch/arm/ *omap*. The omap_device code includes functions to
* build a struct platform_device using omap_hwmod data, and that is
* currently how hwmod data is communicated to drivers and to the
* Linux driver model. Most drivers will call omap_hwmod functions only
* indirectly, via pm_runtime*() functions.
*
* From a layering perspective, here is where the OMAP hwmod code
* fits into the kernel software stack:
*
* +-------------------------------+
* | Device driver code |
* | (e.g., drivers/) |
* +-------------------------------+
* | Linux driver model |
* | (platform_device / |
* | platform_driver data/code) |
* +-------------------------------+
* | OMAP core-driver integration |
* |(arch/arm/mach-omap2/devices.c)|
* +-------------------------------+
* | omap_device code |
* | (../plat-omap/omap_device.c) |
* +-------------------------------+
* ----> | omap_hwmod code/data | <-----
* | (../mach-omap2/omap_hwmod*) |
* +-------------------------------+
* | OMAP clock/PRCM/register fns |
* | (__raw_{read,write}l, clk*) |
* +-------------------------------+
*
* Device drivers should not contain any OMAP-specific code or data in
* them. They should only contain code to operate the IP block that
* the driver is responsible for. This is because these IP blocks can
* also appear in other SoCs, either from TI (such as DaVinci) or from
* other manufacturers; and drivers should be reusable across other
* platforms.
*
* The OMAP hwmod code also will attempt to reset and idle all on-chip
* devices upon boot. The goal here is for the kernel to be
* completely self-reliant and independent from bootloaders. This is
* to ensure a repeatable configuration, both to ensure consistent
* runtime behavior, and to make it easier for others to reproduce
* bugs.
*
* OMAP module activity states
* ---------------------------
* The hwmod code considers modules to be in one of several activity
* states. IP blocks start out in an UNKNOWN state, then once they
* are registered via the hwmod code, proceed to the REGISTERED state.
* Once their clock names are resolved to clock pointers, the module
* enters the CLKS_INITED state; and finally, once the module has been
* reset and the integration registers programmed, the INITIALIZED state
* is entered. The hwmod code will then place the module into either
* the IDLE state to save power, or in the case of a critical system
* module, the ENABLED state.
*
* OMAP core integration code can then call omap_hwmod*() functions
* directly to move the module between the IDLE, ENABLED, and DISABLED
* states, as needed. This is done during both the PM idle loop, and
* in the OMAP core integration code's implementation of the PM runtime
* functions.
*
* References
* ----------
* This is a partial list.
* - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
* - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
* - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
...
...
@@ -50,11 +142,13 @@
#include <plat/powerdomain.h>
#include <plat/clock.h>
#include <plat/omap_hwmod.h>
#include <plat/prcm.h>
#include "cm.h"
#include "prm.h"
/* Maximum microseconds to wait for OMAP module to reset */
#define MAX_MODULE_
RESET_WAIT
10000
/* Maximum microseconds to wait for OMAP module to
soft
reset */
#define MAX_MODULE_
SOFTRESET_WAIT
10000
/* Name of the OMAP hwmod for the MPU */
#define MPU_INITIATOR_NAME "mpu"
...
...
@@ -544,6 +638,36 @@ static int _disable_clocks(struct omap_hwmod *oh)
return
0
;
}
static
void
_enable_optional_clocks
(
struct
omap_hwmod
*
oh
)
{
struct
omap_hwmod_opt_clk
*
oc
;
int
i
;
pr_debug
(
"omap_hwmod: %s: enabling optional clocks
\n
"
,
oh
->
name
);
for
(
i
=
oh
->
opt_clks_cnt
,
oc
=
oh
->
opt_clks
;
i
>
0
;
i
--
,
oc
++
)
if
(
oc
->
_clk
)
{
pr_debug
(
"omap_hwmod: enable %s:%s
\n
"
,
oc
->
role
,
oc
->
_clk
->
name
);
clk_enable
(
oc
->
_clk
);
}
}
static
void
_disable_optional_clocks
(
struct
omap_hwmod
*
oh
)
{
struct
omap_hwmod_opt_clk
*
oc
;
int
i
;
pr_debug
(
"omap_hwmod: %s: disabling optional clocks
\n
"
,
oh
->
name
);
for
(
i
=
oh
->
opt_clks_cnt
,
oc
=
oh
->
opt_clks
;
i
>
0
;
i
--
,
oc
++
)
if
(
oc
->
_clk
)
{
pr_debug
(
"omap_hwmod: disable %s:%s
\n
"
,
oc
->
role
,
oc
->
_clk
->
name
);
clk_disable
(
oc
->
_clk
);
}
}
/**
* _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use
* @oh: struct omap_hwmod *
...
...
@@ -622,7 +746,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
}
/**
* _
sysc_enable
- try to bring a module out of idle via OCP_SYSCONFIG
* _
enable_sysc
- try to bring a module out of idle via OCP_SYSCONFIG
* @oh: struct omap_hwmod *
*
* If module is marked as SWSUP_SIDLE, force the module out of slave
...
...
@@ -630,7 +754,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
* as SWSUP_MSUSPEND, force the module out of master standby;
* otherwise, configure it for smart-standby. No return value.
*/
static
void
_
sysc_enable
(
struct
omap_hwmod
*
oh
)
static
void
_
enable_sysc
(
struct
omap_hwmod
*
oh
)
{
u8
idlemode
,
sf
;
u32
v
;
...
...
@@ -659,8 +783,6 @@ static void _sysc_enable(struct omap_hwmod *oh)
_set_module_autoidle
(
oh
,
idlemode
,
&
v
);
}
/* XXX OCP ENAWAKEUP bit? */
/*
* XXX The clock framework should handle this, by
* calling into this code. But this must wait until the
...
...
@@ -671,10 +793,14 @@ static void _sysc_enable(struct omap_hwmod *oh)
_set_clockactivity
(
oh
,
oh
->
class
->
sysc
->
clockact
,
&
v
);
_write_sysconfig
(
v
,
oh
);
/* If slave is in SMARTIDLE, also enable wakeup */
if
((
sf
&
SYSC_HAS_SIDLEMODE
)
&&
!
(
oh
->
flags
&
HWMOD_SWSUP_SIDLE
))
_enable_wakeup
(
oh
);
}
/**
* _
sysc_idle
- try to put a module into idle via OCP_SYSCONFIG
* _
idle_sysc
- try to put a module into idle via OCP_SYSCONFIG
* @oh: struct omap_hwmod *
*
* If module is marked as SWSUP_SIDLE, force the module into slave
...
...
@@ -682,7 +808,7 @@ static void _sysc_enable(struct omap_hwmod *oh)
* as SWSUP_MSUSPEND, force the module into master standby; otherwise,
* configure it for smart-standby. No return value.
*/
static
void
_
sysc_idle
(
struct
omap_hwmod
*
oh
)
static
void
_
idle_sysc
(
struct
omap_hwmod
*
oh
)
{
u8
idlemode
,
sf
;
u32
v
;
...
...
@@ -709,13 +835,13 @@ static void _sysc_idle(struct omap_hwmod *oh)
}
/**
* _s
ysc_shutdown
- force a module into idle via OCP_SYSCONFIG
* _s
hutdown_sysc
- force a module into idle via OCP_SYSCONFIG
* @oh: struct omap_hwmod *
*
* Force the module into slave idle and master suspend. No return
* value.
*/
static
void
_s
ysc_shutdown
(
struct
omap_hwmod
*
oh
)
static
void
_s
hutdown_sysc
(
struct
omap_hwmod
*
oh
)
{
u32
v
;
u8
sf
;
...
...
@@ -767,10 +893,10 @@ static struct omap_hwmod *_lookup(const char *name)
* @data: not used; pass NULL
*
* Called by omap_hwmod_late_init() (after omap2_clk_init()).
* Resolves all clock names embedded in the hwmod.
Must be called
*
with omap_hwmod_mutex held. Returns -EINVAL if the omap_hwmod
*
has not yet been registered or if the clocks have already bee
n
*
initialized, 0 on success, or a non-zero error on
failure.
* Resolves all clock names embedded in the hwmod.
Returns -EINVAL if
*
the omap_hwmod has not yet been registered or if the clocks have
*
already been initialized, 0 on success, or a non-zero error o
n
* failure.
*/
static
int
_init_clocks
(
struct
omap_hwmod
*
oh
,
void
*
data
)
{
...
...
@@ -833,57 +959,203 @@ static int _wait_target_ready(struct omap_hwmod *oh)
return
ret
;
}
/**
* _lookup_hardreset - return the register bit shift for this hwmod/reset line
* @oh: struct omap_hwmod *
* @name: name of the reset line in the context of this hwmod
*
* Return the bit position of the reset line that match the
* input name. Return -ENOENT if not found.
*/
static
u8
_lookup_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
i
<
oh
->
rst_lines_cnt
;
i
++
)
{
const
char
*
rst_line
=
oh
->
rst_lines
[
i
].
name
;
if
(
!
strcmp
(
rst_line
,
name
))
{
u8
shift
=
oh
->
rst_lines
[
i
].
rst_shift
;
pr_debug
(
"omap_hwmod: %s: _lookup_hardreset: %s: %d
\n
"
,
oh
->
name
,
rst_line
,
shift
);
return
shift
;
}
}
return
-
ENOENT
;
}
/**
* _assert_hardreset - assert the HW reset line of submodules
* contained in the hwmod module.
* @oh: struct omap_hwmod *
* @name: name of the reset line to lookup and assert
*
* Some IP like dsp, ipu or iva contain processor that require
* an HW reset line to be assert / deassert in order to enable fully
* the IP.
*/
static
int
_assert_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
)
{
u8
shift
;
if
(
!
oh
)
return
-
EINVAL
;
shift
=
_lookup_hardreset
(
oh
,
name
);
if
(
IS_ERR_VALUE
(
shift
))
return
shift
;
if
(
cpu_is_omap24xx
()
||
cpu_is_omap34xx
())
return
omap2_prm_assert_hardreset
(
oh
->
prcm
.
omap2
.
module_offs
,
shift
);
else
if
(
cpu_is_omap44xx
())
return
omap4_prm_assert_hardreset
(
oh
->
prcm
.
omap4
.
rstctrl_reg
,
shift
);
else
return
-
EINVAL
;
}
/**
* _deassert_hardreset - deassert the HW reset line of submodules contained
* in the hwmod module.
* @oh: struct omap_hwmod *
* @name: name of the reset line to look up and deassert
*
* Some IP like dsp, ipu or iva contain processor that require
* an HW reset line to be assert / deassert in order to enable fully
* the IP.
*/
static
int
_deassert_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
)
{
u8
shift
;
int
r
;
if
(
!
oh
)
return
-
EINVAL
;
shift
=
_lookup_hardreset
(
oh
,
name
);
if
(
IS_ERR_VALUE
(
shift
))
return
shift
;
if
(
cpu_is_omap24xx
()
||
cpu_is_omap34xx
())
r
=
omap2_prm_deassert_hardreset
(
oh
->
prcm
.
omap2
.
module_offs
,
shift
);
else
if
(
cpu_is_omap44xx
())
r
=
omap4_prm_deassert_hardreset
(
oh
->
prcm
.
omap4
.
rstctrl_reg
,
shift
);
else
return
-
EINVAL
;
if
(
r
==
-
EBUSY
)
pr_warning
(
"omap_hwmod: %s: failed to hardreset
\n
"
,
oh
->
name
);
return
r
;
}
/**
* _read_hardreset - read the HW reset line state of submodules
* contained in the hwmod module
* @oh: struct omap_hwmod *
* @name: name of the reset line to look up and read
*
* Return the state of the reset line.
*/
static
int
_read_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
)
{
u8
shift
;
if
(
!
oh
)
return
-
EINVAL
;
shift
=
_lookup_hardreset
(
oh
,
name
);
if
(
IS_ERR_VALUE
(
shift
))
return
shift
;
if
(
cpu_is_omap24xx
()
||
cpu_is_omap34xx
())
{
return
omap2_prm_is_hardreset_asserted
(
oh
->
prcm
.
omap2
.
module_offs
,
shift
);
}
else
if
(
cpu_is_omap44xx
())
{
return
omap4_prm_is_hardreset_asserted
(
oh
->
prcm
.
omap4
.
rstctrl_reg
,
shift
);
}
else
{
return
-
EINVAL
;
}
}
/**
* _reset - reset an omap_hwmod
* @oh: struct omap_hwmod *
*
* Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be
* enabled for this to work. Must be called with omap_hwmod_mutex
* held. Returns -EINVAL if the hwmod cannot be reset this way or if
* the hwmod is in the wrong state, -ETIMEDOUT if the module did not
* reset in time, or 0 upon success.
* enabled for this to work. Returns -EINVAL if the hwmod cannot be
* reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if
* the module did not reset in time, or 0 upon success.
*
* In OMAP3 a specific SYSSTATUS register is used to get the reset status.
* Starting in OMAP4, some IPs does not have SYSSTATUS register and instead
* use the SYSCONFIG softreset bit to provide the status.
*
* Note that some IP like McBSP does have a reset control but no reset status.
*/
static
int
_reset
(
struct
omap_hwmod
*
oh
)
{
u32
r
,
v
;
u32
v
;
int
c
=
0
;
int
ret
=
0
;
if
(
!
oh
->
class
->
sysc
||
!
(
oh
->
class
->
sysc
->
sysc_flags
&
SYSC_HAS_SOFTRESET
)
||
(
oh
->
class
->
sysc
->
sysc_flags
&
SYSS_MISSING
))
!
(
oh
->
class
->
sysc
->
sysc_flags
&
SYSC_HAS_SOFTRESET
))
return
-
EINVAL
;
/* clocks must be on for this operation */
if
(
oh
->
_state
!=
_HWMOD_STATE_ENABLED
)
{
WARN
(
1
,
"omap_hwmod: %s: reset can only be entered from "
"enabled state
\n
"
,
oh
->
name
);
pr_warning
(
"omap_hwmod: %s: reset can only be entered from "
"enabled state
\n
"
,
oh
->
name
);
return
-
EINVAL
;
}
/* For some modules, all optionnal clocks need to be enabled as well */
if
(
oh
->
flags
&
HWMOD_CONTROL_OPT_CLKS_IN_RESET
)
_enable_optional_clocks
(
oh
);
pr_debug
(
"omap_hwmod: %s: resetting
\n
"
,
oh
->
name
);
v
=
oh
->
_sysc_cache
;
r
=
_set_softreset
(
oh
,
&
v
);
if
(
r
)
return
r
;
r
et
=
_set_softreset
(
oh
,
&
v
);
if
(
r
et
)
goto
dis_opt_clks
;
_write_sysconfig
(
v
,
oh
);
omap_test_timeout
((
omap_hwmod_readl
(
oh
,
oh
->
class
->
sysc
->
syss_offs
)
&
SYSS_RESETDONE_MASK
),
MAX_MODULE_RESET_WAIT
,
c
);
if
(
c
==
MAX_MODULE_RESET_WAIT
)
WARN
(
1
,
"omap_hwmod: %s: failed to reset in %d usec
\n
"
,
oh
->
name
,
MAX_MODULE_RESET_WAIT
);
if
(
oh
->
class
->
sysc
->
sysc_flags
&
SYSS_HAS_RESET_STATUS
)
omap_test_timeout
((
omap_hwmod_readl
(
oh
,
oh
->
class
->
sysc
->
syss_offs
)
&
SYSS_RESETDONE_MASK
),
MAX_MODULE_SOFTRESET_WAIT
,
c
);
else
if
(
oh
->
class
->
sysc
->
sysc_flags
&
SYSC_HAS_RESET_STATUS
)
omap_test_timeout
(
!
(
omap_hwmod_readl
(
oh
,
oh
->
class
->
sysc
->
sysc_offs
)
&
SYSC_TYPE2_SOFTRESET_MASK
),
MAX_MODULE_SOFTRESET_WAIT
,
c
);
if
(
c
==
MAX_MODULE_SOFTRESET_WAIT
)
pr_warning
(
"omap_hwmod: %s: softreset failed (waited %d usec)
\n
"
,
oh
->
name
,
MAX_MODULE_SOFTRESET_WAIT
);
else
pr_debug
(
"omap_hwmod: %s: reset in %d usec
\n
"
,
oh
->
name
,
c
);
pr_debug
(
"omap_hwmod: %s:
soft
reset in %d usec
\n
"
,
oh
->
name
,
c
);
/*
* XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
* _wait_target_ready() or _reset()
*/
return
(
c
==
MAX_MODULE_RESET_WAIT
)
?
-
ETIMEDOUT
:
0
;
ret
=
(
c
==
MAX_MODULE_SOFTRESET_WAIT
)
?
-
ETIMEDOUT
:
0
;
dis_opt_clks:
if
(
oh
->
flags
&
HWMOD_CONTROL_OPT_CLKS_IN_RESET
)
_disable_optional_clocks
(
oh
);
return
ret
;
}
/**
...
...
@@ -891,9 +1163,11 @@ static int _reset(struct omap_hwmod *oh)
* @oh: struct omap_hwmod *
*
* Enables an omap_hwmod @oh such that the MPU can access the hwmod's
* register target. Must be called with omap_hwmod_mutex held.
* Returns -EINVAL if the hwmod is in the wrong state or passes along
* the return value of _wait_target_ready().
* register target. (This function has a full name --
* _omap_hwmod_enable() rather than simply _enable() -- because it is
* currently required by the pm34xx.c idle loop.) Returns -EINVAL if
* the hwmod is in the wrong state or passes along the return value of
* _wait_target_ready().
*/
int
_omap_hwmod_enable
(
struct
omap_hwmod
*
oh
)
{
...
...
@@ -909,6 +1183,15 @@ int _omap_hwmod_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
);
/* XXX mux balls */
_add_initiator_dep
(
oh
,
mpu_oh
);
...
...
@@ -922,7 +1205,7 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
if
(
oh
->
class
->
sysc
)
{
if
(
!
(
oh
->
_int_flags
&
_HWMOD_SYSCONFIG_LOADED
))
_update_sysc_cache
(
oh
);
_
sysc_enable
(
oh
);
_
enable_sysc
(
oh
);
}
}
else
{
pr_debug
(
"omap_hwmod: %s: _wait_target_ready: %d
\n
"
,
...
...
@@ -933,12 +1216,14 @@ int _omap_hwmod_enable(struct omap_hwmod *oh)
}
/**
* _idle - idle an omap_hwmod
* _
omap_hwmod_
idle - idle an omap_hwmod
* @oh: struct omap_hwmod *
*
* Idles an omap_hwmod @oh. This should be called once the hwmod has
* no further work. Returns -EINVAL if the hwmod is in the wrong
* state or returns 0.
* no further work. (This function has a full name --
* _omap_hwmod_idle() rather than simply _idle() -- because it is
* currently required by the pm34xx.c idle loop.) Returns -EINVAL if
* the hwmod is in the wrong state or returns 0.
*/
int
_omap_hwmod_idle
(
struct
omap_hwmod
*
oh
)
{
...
...
@@ -951,7 +1236,7 @@ int _omap_hwmod_idle(struct omap_hwmod *oh)
pr_debug
(
"omap_hwmod: %s: idling
\n
"
,
oh
->
name
);
if
(
oh
->
class
->
sysc
)
_
sysc_idle
(
oh
);
_
idle_sysc
(
oh
);
_del_initiator_dep
(
oh
,
mpu_oh
);
_disable_clocks
(
oh
);
...
...
@@ -981,10 +1266,21 @@ static int _shutdown(struct omap_hwmod *oh)
pr_debug
(
"omap_hwmod: %s: disabling
\n
"
,
oh
->
name
);
if
(
oh
->
class
->
sysc
)
_sysc_shutdown
(
oh
);
_del_initiator_dep
(
oh
,
mpu_oh
);
/* XXX what about the other system initiators here? DMA, tesla, d2d */
_disable_clocks
(
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
);
/* XXX what about the other system initiators here? dma, dsp */
_disable_clocks
(
oh
);
}
/* XXX Should this code also force-disable the optional clocks? */
/* XXX mux any associated balls to safe mode */
...
...
@@ -1000,11 +1296,10 @@ static int _shutdown(struct omap_hwmod *oh)
* @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1
*
* Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh
* OCP_SYSCONFIG register. Must be called with omap_hwmod_mutex held.
* @skip_setup_idle is intended to be used on a system that will not
* call omap_hwmod_enable() to enable devices (e.g., a system without
* PM runtime). Returns -EINVAL if the hwmod is in the wrong state or
* returns 0.
* OCP_SYSCONFIG register. @skip_setup_idle is intended to be used on
* a system that will not call omap_hwmod_enable() to enable devices
* (e.g., a system without PM runtime). Returns -EINVAL if the hwmod
* is in the wrong state or returns 0.
*/
static
int
_setup
(
struct
omap_hwmod
*
oh
,
void
*
data
)
{
...
...
@@ -1034,8 +1329,19 @@ static int _setup(struct omap_hwmod *oh, void *data)
}
}
mutex_init
(
&
oh
->
_mutex
);
oh
->
_state
=
_HWMOD_STATE_INITIALIZED
;
/*
* In the case of hwmod with hardreset that should not be
* de-assert at boot time, we have to keep the module
* initialized, because we cannot enable it properly with the
* reset asserted. Exit without warning because that behavior is
* expected.
*/
if
((
oh
->
flags
&
HWMOD_INIT_NO_RESET
)
&&
oh
->
rst_lines_cnt
==
1
)
return
0
;
r
=
_omap_hwmod_enable
(
oh
);
if
(
r
)
{
pr_warning
(
"omap_hwmod: %s: cannot be enabled (%d)
\n
"
,
...
...
@@ -1044,16 +1350,16 @@ static int _setup(struct omap_hwmod *oh, void *data)
}
if
(
!
(
oh
->
flags
&
HWMOD_INIT_NO_RESET
))
{
_reset
(
oh
);
/*
* XXX Do the OCP_SYSCONFIG bits need to be
* reprogrammed after a reset? If not, then this can
* be removed. If they do, then probably the
* _omap_hwmod_enable() function should be split to avoid the
* rewrite of the OCP_SYSCONFIG register.
* OCP_SYSCONFIG bits need to be reprogrammed after a softreset.
* The _omap_hwmod_enable() function should be split to
* avoid the rewrite of the OCP_SYSCONFIG register.
*/
if
(
oh
->
class
->
sysc
)
{
_update_sysc_cache
(
oh
);
_
sysc_enable
(
oh
);
_
enable_sysc
(
oh
);
}
}
...
...
@@ -1309,7 +1615,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh)
* omap_hwmod_enable - enable an omap_hwmod
* @oh: struct omap_hwmod *
*
* Enable an omap_hw
om
d @oh. Intended to be called by omap_device_enable().
* Enable an omap_hw
mo
d @oh. Intended to be called by omap_device_enable().
* Returns -EINVAL on error or passes along the return value from _enable().
*/
int
omap_hwmod_enable
(
struct
omap_hwmod
*
oh
)
...
...
@@ -1319,9 +1625,9 @@ int omap_hwmod_enable(struct omap_hwmod *oh)
if
(
!
oh
)
return
-
EINVAL
;
mutex_lock
(
&
o
map_hwmod
_mutex
);
mutex_lock
(
&
o
h
->
_mutex
);
r
=
_omap_hwmod_enable
(
oh
);
mutex_unlock
(
&
o
map_hwmod
_mutex
);
mutex_unlock
(
&
o
h
->
_mutex
);
return
r
;
}
...
...
@@ -1331,7 +1637,7 @@ int omap_hwmod_enable(struct omap_hwmod *oh)
* omap_hwmod_idle - idle an omap_hwmod
* @oh: struct omap_hwmod *
*
* Idle an omap_hw
om
d @oh. Intended to be called by omap_device_idle().
* Idle an omap_hw
mo
d @oh. Intended to be called by omap_device_idle().
* Returns -EINVAL on error or passes along the return value from _idle().
*/
int
omap_hwmod_idle
(
struct
omap_hwmod
*
oh
)
...
...
@@ -1339,9 +1645,9 @@ int omap_hwmod_idle(struct omap_hwmod *oh)
if
(
!
oh
)
return
-
EINVAL
;
mutex_lock
(
&
o
map_hwmod
_mutex
);
mutex_lock
(
&
o
h
->
_mutex
);
_omap_hwmod_idle
(
oh
);
mutex_unlock
(
&
o
map_hwmod
_mutex
);
mutex_unlock
(
&
o
h
->
_mutex
);
return
0
;
}
...
...
@@ -1350,7 +1656,7 @@ int omap_hwmod_idle(struct omap_hwmod *oh)
* omap_hwmod_shutdown - shutdown an omap_hwmod
* @oh: struct omap_hwmod *
*
* Shutdown an omap_hw
om
d @oh. Intended to be called by
* Shutdown an omap_hw
mo
d @oh. Intended to be called by
* omap_device_shutdown(). Returns -EINVAL on error or passes along
* the return value from _shutdown().
*/
...
...
@@ -1359,9 +1665,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh)
if
(
!
oh
)
return
-
EINVAL
;
mutex_lock
(
&
o
map_hwmod
_mutex
);
mutex_lock
(
&
o
h
->
_mutex
);
_shutdown
(
oh
);
mutex_unlock
(
&
o
map_hwmod
_mutex
);
mutex_unlock
(
&
o
h
->
_mutex
);
return
0
;
}
...
...
@@ -1374,9 +1680,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh)
*/
int
omap_hwmod_enable_clocks
(
struct
omap_hwmod
*
oh
)
{
mutex_lock
(
&
o
map_hwmod
_mutex
);
mutex_lock
(
&
o
h
->
_mutex
);
_enable_clocks
(
oh
);
mutex_unlock
(
&
o
map_hwmod
_mutex
);
mutex_unlock
(
&
o
h
->
_mutex
);
return
0
;
}
...
...
@@ -1389,9 +1695,9 @@ int omap_hwmod_enable_clocks(struct omap_hwmod *oh)
*/
int
omap_hwmod_disable_clocks
(
struct
omap_hwmod
*
oh
)
{
mutex_lock
(
&
o
map_hwmod
_mutex
);
mutex_lock
(
&
o
h
->
_mutex
);
_disable_clocks
(
oh
);
mutex_unlock
(
&
o
map_hwmod
_mutex
);
mutex_unlock
(
&
o
h
->
_mutex
);
return
0
;
}
...
...
@@ -1430,20 +1736,18 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh)
*
* Under some conditions, a driver may wish to reset the entire device.
* Called from omap_device code. Returns -EINVAL on error or passes along
* the return value from _reset()
/_enable()
.
* the return value from _reset().
*/
int
omap_hwmod_reset
(
struct
omap_hwmod
*
oh
)
{
int
r
;
if
(
!
oh
||
!
(
oh
->
_state
&
_HWMOD_STATE_ENABLED
)
)
if
(
!
oh
)
return
-
EINVAL
;
mutex_lock
(
&
o
map_hwmod
_mutex
);
mutex_lock
(
&
o
h
->
_mutex
);
r
=
_reset
(
oh
);
if
(
!
r
)
r
=
_omap_hwmod_enable
(
oh
);
mutex_unlock
(
&
omap_hwmod_mutex
);
mutex_unlock
(
&
oh
->
_mutex
);
return
r
;
}
...
...
@@ -1468,7 +1772,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh)
{
int
ret
,
i
;
ret
=
oh
->
mpu_irqs_cnt
+
oh
->
sdma_
ch
s_cnt
;
ret
=
oh
->
mpu_irqs_cnt
+
oh
->
sdma_
req
s_cnt
;
for
(
i
=
0
;
i
<
oh
->
slaves_cnt
;
i
++
)
ret
+=
oh
->
slaves
[
i
]
->
addr_cnt
;
...
...
@@ -1501,10 +1805,10 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
r
++
;
}
for
(
i
=
0
;
i
<
oh
->
sdma_
ch
s_cnt
;
i
++
)
{
(
res
+
r
)
->
name
=
(
oh
->
sdma_
ch
s
+
i
)
->
name
;
(
res
+
r
)
->
start
=
(
oh
->
sdma_
chs
+
i
)
->
dma_ch
;
(
res
+
r
)
->
end
=
(
oh
->
sdma_
chs
+
i
)
->
dma_ch
;
for
(
i
=
0
;
i
<
oh
->
sdma_
req
s_cnt
;
i
++
)
{
(
res
+
r
)
->
name
=
(
oh
->
sdma_
req
s
+
i
)
->
name
;
(
res
+
r
)
->
start
=
(
oh
->
sdma_
reqs
+
i
)
->
dma_req
;
(
res
+
r
)
->
end
=
(
oh
->
sdma_
reqs
+
i
)
->
dma_req
;
(
res
+
r
)
->
flags
=
IORESOURCE_DMA
;
r
++
;
}
...
...
@@ -1644,9 +1948,9 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
!
(
oh
->
class
->
sysc
->
sysc_flags
&
SYSC_HAS_ENAWAKEUP
))
return
-
EINVAL
;
mutex_lock
(
&
o
map_hwmod
_mutex
);
mutex_lock
(
&
o
h
->
_mutex
);
_enable_wakeup
(
oh
);
mutex_unlock
(
&
o
map_hwmod
_mutex
);
mutex_unlock
(
&
o
h
->
_mutex
);
return
0
;
}
...
...
@@ -1669,13 +1973,91 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
!
(
oh
->
class
->
sysc
->
sysc_flags
&
SYSC_HAS_ENAWAKEUP
))
return
-
EINVAL
;
mutex_lock
(
&
o
map_hwmod
_mutex
);
mutex_lock
(
&
o
h
->
_mutex
);
_disable_wakeup
(
oh
);
mutex_unlock
(
&
o
map_hwmod
_mutex
);
mutex_unlock
(
&
o
h
->
_mutex
);
return
0
;
}
/**
* omap_hwmod_assert_hardreset - assert the HW reset line of submodules
* contained in the hwmod module.
* @oh: struct omap_hwmod *
* @name: name of the reset line to lookup and assert
*
* Some IP like dsp, ipu or iva contain processor that require
* an HW reset line to be assert / deassert in order to enable fully
* the IP. Returns -EINVAL if @oh is null or if the operation is not
* yet supported on this OMAP; otherwise, passes along the return value
* from _assert_hardreset().
*/
int
omap_hwmod_assert_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
)
{
int
ret
;
if
(
!
oh
)
return
-
EINVAL
;
mutex_lock
(
&
oh
->
_mutex
);
ret
=
_assert_hardreset
(
oh
,
name
);
mutex_unlock
(
&
oh
->
_mutex
);
return
ret
;
}
/**
* omap_hwmod_deassert_hardreset - deassert the HW reset line of submodules
* contained in the hwmod module.
* @oh: struct omap_hwmod *
* @name: name of the reset line to look up and deassert
*
* Some IP like dsp, ipu or iva contain processor that require
* an HW reset line to be assert / deassert in order to enable fully
* the IP. Returns -EINVAL if @oh is null or if the operation is not
* yet supported on this OMAP; otherwise, passes along the return value
* from _deassert_hardreset().
*/
int
omap_hwmod_deassert_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
)
{
int
ret
;
if
(
!
oh
)
return
-
EINVAL
;
mutex_lock
(
&
oh
->
_mutex
);
ret
=
_deassert_hardreset
(
oh
,
name
);
mutex_unlock
(
&
oh
->
_mutex
);
return
ret
;
}
/**
* omap_hwmod_read_hardreset - read the HW reset line state of submodules
* contained in the hwmod module
* @oh: struct omap_hwmod *
* @name: name of the reset line to look up and read
*
* Return the current state of the hwmod @oh's reset line named @name:
* returns -EINVAL upon parameter error or if this operation
* is unsupported on the current OMAP; otherwise, passes along the return
* value from _read_hardreset().
*/
int
omap_hwmod_read_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
)
{
int
ret
;
if
(
!
oh
)
return
-
EINVAL
;
mutex_lock
(
&
oh
->
_mutex
);
ret
=
_read_hardreset
(
oh
,
name
);
mutex_unlock
(
&
oh
->
_mutex
);
return
ret
;
}
/**
* omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname
* @classname: struct omap_hwmod_class name to search for
...
...
arch/arm/mach-omap2/prcm.c
浏览文件 @
9af2ebbd
...
...
@@ -33,6 +33,7 @@
#include "cm.h"
#include "prm.h"
#include "prm-regbits-24xx.h"
#include "prm-regbits-44xx.h"
static
void
__iomem
*
prm_base
;
static
void
__iomem
*
cm_base
;
...
...
@@ -161,8 +162,8 @@ void omap_prcm_arch_reset(char mode, const char *cmd)
prm_set_mod_reg_bits
(
OMAP_RST_DPLL3_MASK
,
prcm_offs
,
OMAP2_RM_RSTCTRL
);
if
(
cpu_is_omap44xx
())
prm_set_mod_reg_bits
(
OMAP
_RST_DPLL3_MASK
,
prcm_offs
,
OMAP4_RM_RSTCTRL
);
prm_set_mod_reg_bits
(
OMAP
4430_RST_GLOBAL_WARM_SW_MASK
,
prcm_offs
,
OMAP4_RM_RSTCTRL
);
}
static
inline
u32
__omap_prcm_read
(
void
__iomem
*
base
,
s16
module
,
u16
reg
)
...
...
@@ -215,6 +216,30 @@ u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
return
v
;
}
/* Read a PRM register, AND it, and shift the result down to bit 0 */
u32
omap4_prm_read_bits_shift
(
void
__iomem
*
reg
,
u32
mask
)
{
u32
v
;
v
=
__raw_readl
(
reg
);
v
&=
mask
;
v
>>=
__ffs
(
mask
);
return
v
;
}
/* Read-modify-write a register in a PRM module. Caller must lock */
u32
omap4_prm_rmw_reg_bits
(
u32
mask
,
u32
bits
,
void
__iomem
*
reg
)
{
u32
v
;
v
=
__raw_readl
(
reg
);
v
&=
~
mask
;
v
|=
bits
;
__raw_writel
(
v
,
reg
);
return
v
;
}
/* Read a register in a CM module */
u32
cm_read_mod_reg
(
s16
module
,
u16
idx
)
{
...
...
arch/arm/mach-omap2/prm.h
浏览文件 @
9af2ebbd
...
...
@@ -5,7 +5,7 @@
* OMAP2/3 Power/Reset Management (PRM) register definitions
*
* Copyright (C) 2007-2009 Texas Instruments, Inc.
* Copyright (C) 20
09
Nokia Corporation
* Copyright (C) 20
10
Nokia Corporation
*
* Written by Paul Walmsley
*
...
...
@@ -246,6 +246,15 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
return
prm_rmw_mod_reg_bits
(
bits
,
0x0
,
module
,
idx
);
}
/* These omap2_ PRM functions apply to both OMAP2 and 3 */
int
omap2_prm_is_hardreset_asserted
(
s16
prm_mod
,
u8
shift
);
int
omap2_prm_assert_hardreset
(
s16
prm_mod
,
u8
shift
);
int
omap2_prm_deassert_hardreset
(
s16
prm_mod
,
u8
shift
);
int
omap4_prm_is_hardreset_asserted
(
void
__iomem
*
rstctrl_reg
,
u8
shift
);
int
omap4_prm_assert_hardreset
(
void
__iomem
*
rstctrl_reg
,
u8
shift
);
int
omap4_prm_deassert_hardreset
(
void
__iomem
*
rstctrl_reg
,
u8
shift
);
#endif
/*
...
...
@@ -398,4 +407,11 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
#define OMAP_POWERSTATE_MASK (0x3 << 0)
/*
* MAX_MODULE_HARDRESET_WAIT: Maximum microseconds to wait for an OMAP
* submodule to exit hardreset
*/
#define MAX_MODULE_HARDRESET_WAIT 10000
#endif
arch/arm/mach-omap2/prm2xxx_3xxx.c
0 → 100644
浏览文件 @
9af2ebbd
/*
* OMAP2/3 PRM module functions
*
* Copyright (C) 2010 Texas Instruments, Inc.
* Copyright (C) 2010 Nokia Corporation
* Benoît Cousson
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <plat/common.h>
#include <plat/cpu.h>
#include <plat/prcm.h>
#include "prm.h"
#include "prm-regbits-24xx.h"
#include "prm-regbits-34xx.h"
/**
* omap2_prm_is_hardreset_asserted - read the HW reset line state of
* submodules contained in the hwmod module
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @shift: register bit shift corresponding to the reset line to check
*
* Returns 1 if the (sub)module hardreset line is currently asserted,
* 0 if the (sub)module hardreset line is not currently asserted, or
* -EINVAL if called while running on a non-OMAP2/3 chip.
*/
int
omap2_prm_is_hardreset_asserted
(
s16
prm_mod
,
u8
shift
)
{
if
(
!
(
cpu_is_omap24xx
()
||
cpu_is_omap34xx
()))
return
-
EINVAL
;
return
prm_read_mod_bits_shift
(
prm_mod
,
OMAP2_RM_RSTCTRL
,
(
1
<<
shift
));
}
/**
* omap2_prm_assert_hardreset - assert the HW reset line of a submodule
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @shift: register bit shift corresponding to the reset line to assert
*
* Some IPs like dsp or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
* IP. These modules may have multiple hard-reset lines that reset
* different 'submodules' inside the IP block. This function will
* place the submodule into reset. Returns 0 upon success or -EINVAL
* upon an argument error.
*/
int
omap2_prm_assert_hardreset
(
s16
prm_mod
,
u8
shift
)
{
u32
mask
;
if
(
!
(
cpu_is_omap24xx
()
||
cpu_is_omap34xx
()))
return
-
EINVAL
;
mask
=
1
<<
shift
;
prm_rmw_mod_reg_bits
(
mask
,
mask
,
prm_mod
,
OMAP2_RM_RSTCTRL
);
return
0
;
}
/**
* omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @shift: register bit shift corresponding to the reset line to deassert
*
* Some IPs like dsp or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
* IP. These modules may have multiple hard-reset lines that reset
* different 'submodules' inside the IP block. This function will
* take the submodule out of reset and wait until the PRCM indicates
* that the reset has completed before returning. Returns 0 upon success or
* -EINVAL upon an argument error, -EEXIST if the submodule was already out
* of reset, or -EBUSY if the submodule did not exit reset promptly.
*/
int
omap2_prm_deassert_hardreset
(
s16
prm_mod
,
u8
shift
)
{
u32
mask
;
int
c
;
if
(
!
(
cpu_is_omap24xx
()
||
cpu_is_omap34xx
()))
return
-
EINVAL
;
mask
=
1
<<
shift
;
/* Check the current status to avoid de-asserting the line twice */
if
(
prm_read_mod_bits_shift
(
prm_mod
,
OMAP2_RM_RSTCTRL
,
mask
)
==
0
)
return
-
EEXIST
;
/* Clear the reset status by writing 1 to the status bit */
prm_rmw_mod_reg_bits
(
0xffffffff
,
mask
,
prm_mod
,
OMAP2_RM_RSTST
);
/* de-assert the reset control line */
prm_rmw_mod_reg_bits
(
mask
,
0
,
prm_mod
,
OMAP2_RM_RSTCTRL
);
/* wait the status to be set */
omap_test_timeout
(
prm_read_mod_bits_shift
(
prm_mod
,
OMAP2_RM_RSTST
,
mask
),
MAX_MODULE_HARDRESET_WAIT
,
c
);
return
(
c
==
MAX_MODULE_HARDRESET_WAIT
)
?
-
EBUSY
:
0
;
}
arch/arm/mach-omap2/prm44xx.c
0 → 100644
浏览文件 @
9af2ebbd
/*
* OMAP4 PRM module functions
*
* Copyright (C) 2010 Texas Instruments, Inc.
* Copyright (C) 2010 Nokia Corporation
* Benoît Cousson
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <plat/common.h>
#include <plat/cpu.h>
#include <plat/prcm.h>
#include "prm.h"
#include "prm-regbits-44xx.h"
/*
* Address offset (in bytes) between the reset control and the reset
* status registers: 4 bytes on OMAP4
*/
#define OMAP4_RST_CTRL_ST_OFFSET 4
/**
* omap4_prm_is_hardreset_asserted - read the HW reset line state of
* submodules contained in the hwmod module
* @rstctrl_reg: RM_RSTCTRL register address for this module
* @shift: register bit shift corresponding to the reset line to check
*
* Returns 1 if the (sub)module hardreset line is currently asserted,
* 0 if the (sub)module hardreset line is not currently asserted, or
* -EINVAL upon parameter error.
*/
int
omap4_prm_is_hardreset_asserted
(
void
__iomem
*
rstctrl_reg
,
u8
shift
)
{
if
(
!
cpu_is_omap44xx
()
||
!
rstctrl_reg
)
return
-
EINVAL
;
return
omap4_prm_read_bits_shift
(
rstctrl_reg
,
(
1
<<
shift
));
}
/**
* omap4_prm_assert_hardreset - assert the HW reset line of a submodule
* @rstctrl_reg: RM_RSTCTRL register address for this module
* @shift: register bit shift corresponding to the reset line to assert
*
* Some IPs like dsp, ipu or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
* IP. These modules may have multiple hard-reset lines that reset
* different 'submodules' inside the IP block. This function will
* place the submodule into reset. Returns 0 upon success or -EINVAL
* upon an argument error.
*/
int
omap4_prm_assert_hardreset
(
void
__iomem
*
rstctrl_reg
,
u8
shift
)
{
u32
mask
;
if
(
!
cpu_is_omap44xx
()
||
!
rstctrl_reg
)
return
-
EINVAL
;
mask
=
1
<<
shift
;
omap4_prm_rmw_reg_bits
(
mask
,
mask
,
rstctrl_reg
);
return
0
;
}
/**
* omap4_prm_deassert_hardreset - deassert a submodule hardreset line and wait
* @rstctrl_reg: RM_RSTCTRL register address for this module
* @shift: register bit shift corresponding to the reset line to deassert
*
* Some IPs like dsp, ipu or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
* IP. These modules may have multiple hard-reset lines that reset
* different 'submodules' inside the IP block. This function will
* take the submodule out of reset and wait until the PRCM indicates
* that the reset has completed before returning. Returns 0 upon success or
* -EINVAL upon an argument error, -EEXIST if the submodule was already out
* of reset, or -EBUSY if the submodule did not exit reset promptly.
*/
int
omap4_prm_deassert_hardreset
(
void
__iomem
*
rstctrl_reg
,
u8
shift
)
{
u32
mask
;
void
__iomem
*
rstst_reg
;
int
c
;
if
(
!
cpu_is_omap44xx
()
||
!
rstctrl_reg
)
return
-
EINVAL
;
rstst_reg
=
rstctrl_reg
+
OMAP4_RST_CTRL_ST_OFFSET
;
mask
=
1
<<
shift
;
/* Check the current status to avoid de-asserting the line twice */
if
(
omap4_prm_read_bits_shift
(
rstctrl_reg
,
mask
)
==
0
)
return
-
EEXIST
;
/* Clear the reset status by writing 1 to the status bit */
omap4_prm_rmw_reg_bits
(
0xffffffff
,
mask
,
rstst_reg
);
/* de-assert the reset control line */
omap4_prm_rmw_reg_bits
(
mask
,
0
,
rstctrl_reg
);
/* wait the status to be set */
omap_test_timeout
(
omap4_prm_read_bits_shift
(
rstst_reg
,
mask
),
MAX_MODULE_HARDRESET_WAIT
,
c
);
return
(
c
==
MAX_MODULE_HARDRESET_WAIT
)
?
-
EBUSY
:
0
;
}
arch/arm/plat-omap/include/plat/omap_hwmod.h
浏览文件 @
9af2ebbd
...
...
@@ -14,19 +14,16 @@
*
* These headers and macros are used to define OMAP on-chip module
* data and their integration with other OMAP modules and Linux.
*
* References:
* - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
* - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
* - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
* - OMAP4430 Multimedia Device Silicon Revision 1.0 (SWPU140)
* - Open Core Protocol Specification 2.2
* Copious documentation and references can also be found in the
* omap_hwmod code, in arch/arm/mach-omap2/omap_hwmod.c (as of this
* writing).
*
* To do:
* - add interconnect error log structures
* - add pinmuxing
* - init_conn_id_bit (CONNID_BIT_VECTOR)
* - implement default hwmod SMS/SDRC flags?
* - remove unused fields
*
*/
#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H
...
...
@@ -35,6 +32,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/ioport.h>
#include <linux/mutex.h>
#include <plat/cpu.h>
struct
omap_device
;
...
...
@@ -96,7 +94,7 @@ struct omap_hwmod_irq_info {
/**
* struct omap_hwmod_dma_info - DMA channels used by the hwmod
* @name: name of the DMA channel (module local name)
* @dma_
ch: DMA channel
ID
* @dma_
req: DMA request
ID
*
* @name should be something short, e.g., "tx" or "rx". It is for use
* by platform_get_resource_byname(). It is defined locally to the
...
...
@@ -104,7 +102,20 @@ struct omap_hwmod_irq_info {
*/
struct
omap_hwmod_dma_info
{
const
char
*
name
;
u16
dma_ch
;
u16
dma_req
;
};
/**
* struct omap_hwmod_rst_info - IPs reset lines use by hwmod
* @name: name of the reset line (module local name)
* @rst_shift: Offset of the reset bit
*
* @name should be something short, e.g., "cpu0" or "rst". It is defined
* locally to the hwmod.
*/
struct
omap_hwmod_rst_info
{
const
char
*
name
;
u8
rst_shift
;
};
/**
...
...
@@ -237,8 +248,9 @@ struct omap_hwmod_ocp_if {
#define SYSC_HAS_CLOCKACTIVITY (1 << 4)
#define SYSC_HAS_SIDLEMODE (1 << 5)
#define SYSC_HAS_MIDLEMODE (1 << 6)
#define SYSS_
MISSING
(1 << 7)
#define SYSS_
HAS_RESET_STATUS
(1 << 7)
#define SYSC_NO_CACHE (1 << 8)
/* XXX SW flag, belongs elsewhere */
#define SYSC_HAS_RESET_STATUS (1 << 9)
/* omap_hwmod_sysconfig.clockact flags */
#define CLOCKACT_TEST_BOTH 0x0
...
...
@@ -327,10 +339,12 @@ struct omap_hwmod_omap2_prcm {
/**
* struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data
* @clkctrl_reg: PRCM address of the clock control register
* @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM
* @submodule_wkdep_bit: bit shift of the WKDEP range
*/
struct
omap_hwmod_omap4_prcm
{
void
__iomem
*
clkctrl_reg
;
void
__iomem
*
rstctrl_reg
;
u8
submodule_wkdep_bit
;
};
...
...
@@ -352,6 +366,10 @@ struct omap_hwmod_omap4_prcm {
* HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup
* HWMOD_NO_IDLEST : this module does not have idle status - this is the case
* only for few initiator modules on OMAP2 & 3.
* HWMOD_CONTROL_OPT_CLKS_IN_RESET: Enable all optional clocks during reset.
* This is needed for devices like DSS that require optional clocks enabled
* in order to complete the reset. Optional clocks will be disabled
* again after the reset.
*/
#define HWMOD_SWSUP_SIDLE (1 << 0)
#define HWMOD_SWSUP_MSTANDBY (1 << 1)
...
...
@@ -360,6 +378,7 @@ struct omap_hwmod_omap4_prcm {
#define HWMOD_NO_OCP_AUTOIDLE (1 << 4)
#define HWMOD_SET_DEFAULT_CLOCKACT (1 << 5)
#define HWMOD_NO_IDLEST (1 << 6)
#define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7)
/*
* omap_hwmod._int_flags definitions
...
...
@@ -410,7 +429,7 @@ struct omap_hwmod_class {
* @class: struct omap_hwmod_class * to the class of this hwmod
* @od: struct omap_device currently associated with this hwmod (internal use)
* @mpu_irqs: ptr to an array of MPU IRQs (see also mpu_irqs_cnt)
* @sdma_
chs: ptr to an array of SDMA channel IDs (see also sdma_ch
s_cnt)
* @sdma_
reqs: ptr to an array of System DMA request IDs (see sdma_req
s_cnt)
* @prcm: PRCM data pertaining to this hwmod
* @main_clk: main clock: OMAP clock name
* @_clk: pointer to the main struct clk (filled in at runtime)
...
...
@@ -424,7 +443,7 @@ struct omap_hwmod_class {
* @msuspendmux_reg_id: CONTROL_MSUSPENDMUX register ID (1-6)
* @msuspendmux_shift: CONTROL_MSUSPENDMUX register bit shift
* @mpu_irqs_cnt: number of @mpu_irqs
* @sdma_
chs_cnt: number of @sdma_ch
s
* @sdma_
reqs_cnt: number of @sdma_req
s
* @opt_clks_cnt: number of @opt_clks
* @master_cnt: number of @master entries
* @slaves_cnt: number of @slave entries
...
...
@@ -433,6 +452,7 @@ struct omap_hwmod_class {
* @_state: internal-use hwmod state
* @flags: hwmod flags (documented below)
* @omap_chip: OMAP chips this hwmod is present on
* @_mutex: mutex serializing operations on this hwmod
* @node: list node for hwmod list (internal use)
*
* @main_clk refers to this module's "main clock," which for our
...
...
@@ -448,7 +468,8 @@ struct omap_hwmod {
struct
omap_hwmod_class
*
class
;
struct
omap_device
*
od
;
struct
omap_hwmod_irq_info
*
mpu_irqs
;
struct
omap_hwmod_dma_info
*
sdma_chs
;
struct
omap_hwmod_dma_info
*
sdma_reqs
;
struct
omap_hwmod_rst_info
*
rst_lines
;
union
{
struct
omap_hwmod_omap2_prcm
omap2
;
struct
omap_hwmod_omap4_prcm
omap4
;
...
...
@@ -461,6 +482,7 @@ struct omap_hwmod {
void
*
dev_attr
;
u32
_sysc_cache
;
void
__iomem
*
_mpu_rt_va
;
struct
mutex
_mutex
;
struct
list_head
node
;
u16
flags
;
u8
_mpu_port_index
;
...
...
@@ -468,7 +490,8 @@ struct omap_hwmod {
u8
msuspendmux_shift
;
u8
response_lat
;
u8
mpu_irqs_cnt
;
u8
sdma_chs_cnt
;
u8
sdma_reqs_cnt
;
u8
rst_lines_cnt
;
u8
opt_clks_cnt
;
u8
masters_cnt
;
u8
slaves_cnt
;
...
...
@@ -492,6 +515,10 @@ int omap_hwmod_idle(struct omap_hwmod *oh);
int
_omap_hwmod_idle
(
struct
omap_hwmod
*
oh
);
int
omap_hwmod_shutdown
(
struct
omap_hwmod
*
oh
);
int
omap_hwmod_assert_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
);
int
omap_hwmod_deassert_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
);
int
omap_hwmod_read_hardreset
(
struct
omap_hwmod
*
oh
,
const
char
*
name
);
int
omap_hwmod_enable_clocks
(
struct
omap_hwmod
*
oh
);
int
omap_hwmod_disable_clocks
(
struct
omap_hwmod
*
oh
);
...
...
arch/arm/plat-omap/include/plat/prcm.h
浏览文件 @
9af2ebbd
...
...
@@ -38,6 +38,8 @@ u32 prm_read_mod_reg(s16 module, u16 idx);
void
prm_write_mod_reg
(
u32
val
,
s16
module
,
u16
idx
);
u32
prm_rmw_mod_reg_bits
(
u32
mask
,
u32
bits
,
s16
module
,
s16
idx
);
u32
prm_read_mod_bits_shift
(
s16
domain
,
s16
idx
,
u32
mask
);
u32
omap4_prm_read_bits_shift
(
void
__iomem
*
reg
,
u32
mask
);
u32
omap4_prm_rmw_reg_bits
(
u32
mask
,
u32
bits
,
void
__iomem
*
reg
);
u32
cm_read_mod_reg
(
s16
module
,
u16
idx
);
void
cm_write_mod_reg
(
u32
val
,
s16
module
,
u16
idx
);
u32
cm_rmw_mod_reg_bits
(
u32
mask
,
u32
bits
,
s16
module
,
s16
idx
);
...
...
arch/arm/plat-omap/omap_device.c
浏览文件 @
9af2ebbd
...
...
@@ -82,6 +82,7 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <plat/omap_device.h>
#include <plat/omap_hwmod.h>
...
...
@@ -243,6 +244,44 @@ static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
return
container_of
(
pdev
,
struct
omap_device
,
pdev
);
}
/**
* _add_optional_clock_alias - Add clock alias for hwmod optional clocks
* @od: struct omap_device *od
*
* For every optional clock present per hwmod per omap_device, this function
* adds an entry in the clocks list of the form <dev-id=dev_name, con-id=role>
* if an entry is already present in it with the form <dev-id=NULL, con-id=role>
*
* The function is called from inside omap_device_build_ss(), after
* omap_device_register.
*
* This allows drivers to get a pointer to its optional clocks based on its role
* by calling clk_get(<dev*>, <role>).
*
* No return value.
*/
static
void
_add_optional_clock_alias
(
struct
omap_device
*
od
,
struct
omap_hwmod
*
oh
)
{
int
i
;
for
(
i
=
0
;
i
<
oh
->
opt_clks_cnt
;
i
++
)
{
struct
omap_hwmod_opt_clk
*
oc
;
int
r
;
oc
=
&
oh
->
opt_clks
[
i
];
if
(
!
oc
->
_clk
)
continue
;
r
=
clk_add_alias
(
oc
->
role
,
dev_name
(
&
od
->
pdev
.
dev
),
(
char
*
)
oc
->
clk
,
&
od
->
pdev
.
dev
);
if
(
r
)
pr_err
(
"omap_device: %s: clk_add_alias for %s failed
\n
"
,
dev_name
(
&
od
->
pdev
.
dev
),
oc
->
role
);
}
}
/* Public functions for use by core code */
...
...
@@ -421,8 +460,10 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
else
ret
=
omap_device_register
(
od
);
for
(
i
=
0
;
i
<
oh_cnt
;
i
++
)
for
(
i
=
0
;
i
<
oh_cnt
;
i
++
)
{
hwmods
[
i
]
->
od
=
od
;
_add_optional_clock_alias
(
od
,
hwmods
[
i
]);
}
if
(
ret
)
goto
odbs_exit4
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录