Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
331d919a
Commit
331d919a
authored
Aug 04, 2010
by
Tony Lindgren
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for_2.6.36' of
git://git.pwsan.com/linux-2.6
into omap-for-linus
parents
047b51fb
fb8ce14c
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
790 additions
and
225 deletions
+790
-225
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/Kconfig
+6
-0
arch/arm/mach-omap1/clock.c
arch/arm/mach-omap1/clock.c
+12
-10
arch/arm/mach-omap1/clock.h
arch/arm/mach-omap1/clock.h
+1
-1
arch/arm/mach-omap1/clock_data.c
arch/arm/mach-omap1/clock_data.c
+103
-26
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/Makefile
+2
-2
arch/arm/mach-omap2/clock3xxx_data.c
arch/arm/mach-omap2/clock3xxx_data.c
+1
-1
arch/arm/mach-omap2/cm.c
arch/arm/mach-omap2/cm.c
+3
-3
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/io.c
+9
-2
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.c
+79
-27
arch/arm/mach-omap2/omap_hwmod_2420_data.c
arch/arm/mach-omap2/omap_hwmod_2420_data.c
+56
-23
arch/arm/mach-omap2/omap_hwmod_2430_data.c
arch/arm/mach-omap2/omap_hwmod_2430_data.c
+56
-25
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+63
-29
arch/arm/mach-omap2/omap_hwmod_common_data.c
arch/arm/mach-omap2/omap_hwmod_common_data.c
+3
-0
arch/arm/mach-omap2/omap_hwmod_common_data.h
arch/arm/mach-omap2/omap_hwmod_common_data.h
+1
-0
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/pm.c
+84
-0
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/Makefile
+1
-0
arch/arm/plat-omap/i2c.c
arch/arm/plat-omap/i2c.c
+11
-1
arch/arm/plat-omap/include/plat/clock.h
arch/arm/plat-omap/include/plat/clock.h
+107
-23
arch/arm/plat-omap/include/plat/common.h
arch/arm/plat-omap/include/plat/common.h
+4
-0
arch/arm/plat-omap/include/plat/omap-pm.h
arch/arm/plat-omap/include/plat/omap-pm.h
+100
-30
arch/arm/plat-omap/include/plat/omap_device.h
arch/arm/plat-omap/include/plat/omap_device.h
+2
-0
arch/arm/plat-omap/include/plat/omap_hwmod.h
arch/arm/plat-omap/include/plat/omap_hwmod.h
+9
-5
arch/arm/plat-omap/omap-pm-noop.c
arch/arm/plat-omap/omap-pm-noop.c
+48
-13
arch/arm/plat-omap/omap_device.c
arch/arm/plat-omap/omap_device.c
+29
-4
No files found.
arch/arm/mach-omap1/Kconfig
View file @
331d919a
...
...
@@ -228,6 +228,12 @@ config OMAP_ARM_120MHZ
help
Enable 120MHz clock for OMAP CPU. If unsure, say N.
config OMAP_ARM_96MHZ
bool "OMAP ARM 96 MHz CPU"
depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_OMAP850)
help
Enable 96MHz clock for OMAP CPU. If unsure, say N.
config OMAP_ARM_60MHZ
bool "OMAP ARM 60 MHz CPU"
depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_OMAP850)
...
...
arch/arm/mach-omap1/clock.c
View file @
331d919a
...
...
@@ -11,7 +11,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/errno.h>
...
...
@@ -34,9 +33,9 @@
__u32
arm_idlect1_mask
;
struct
clk
*
api_ck_p
,
*
ck_dpll1_p
,
*
ck_ref_p
;
/*
-------------------------------------------------------------------------
/*
* Omap1 specific clock functions
*
-------------------------------------------------------------------------*
/
*/
unsigned
long
omap1_uart_recalc
(
struct
clk
*
clk
)
{
...
...
@@ -523,7 +522,8 @@ const struct clkops clkops_dspck = {
.
disable
=
omap1_clk_disable_dsp_domain
,
};
static
int
omap1_clk_enable_uart_functional
(
struct
clk
*
clk
)
/* XXX SYSC register handling does not belong in the clock framework */
static
int
omap1_clk_enable_uart_functional_16xx
(
struct
clk
*
clk
)
{
int
ret
;
struct
uart_clk
*
uclk
;
...
...
@@ -539,7 +539,8 @@ static int omap1_clk_enable_uart_functional(struct clk *clk)
return
ret
;
}
static
void
omap1_clk_disable_uart_functional
(
struct
clk
*
clk
)
/* XXX SYSC register handling does not belong in the clock framework */
static
void
omap1_clk_disable_uart_functional_16xx
(
struct
clk
*
clk
)
{
struct
uart_clk
*
uclk
;
...
...
@@ -550,9 +551,10 @@ static void omap1_clk_disable_uart_functional(struct clk *clk)
omap1_clk_disable_generic
(
clk
);
}
const
struct
clkops
clkops_uart
=
{
.
enable
=
omap1_clk_enable_uart_functional
,
.
disable
=
omap1_clk_disable_uart_functional
,
/* XXX SYSC register handling does not belong in the clock framework */
const
struct
clkops
clkops_uart_16xx
=
{
.
enable
=
omap1_clk_enable_uart_functional_16xx
,
.
disable
=
omap1_clk_disable_uart_functional_16xx
,
};
long
omap1_clk_round_rate
(
struct
clk
*
clk
,
unsigned
long
rate
)
...
...
@@ -572,9 +574,9 @@ int omap1_clk_set_rate(struct clk *clk, unsigned long rate)
return
ret
;
}
/*
-------------------------------------------------------------------------
/*
* Omap1 clock reset and init functions
*
-------------------------------------------------------------------------*
/
*/
#ifdef CONFIG_OMAP_RESET_CLOCKS
...
...
arch/arm/mach-omap1/clock.h
View file @
331d919a
...
...
@@ -107,7 +107,7 @@ extern struct clk *api_ck_p, *ck_dpll1_p, *ck_ref_p;
extern
const
struct
clkops
clkops_dspck
;
extern
const
struct
clkops
clkops_dummy
;
extern
const
struct
clkops
clkops_uart
;
extern
const
struct
clkops
clkops_uart
_16xx
;
extern
const
struct
clkops
clkops_generic
;
#endif
arch/arm/mach-omap1/clock_data.c
View file @
331d919a
...
...
@@ -8,6 +8,10 @@
* 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.
*
* To do:
* - Clocks that are only available on some chips should be marked with the
* chips that they are present on.
*/
#include <linux/kernel.h>
...
...
@@ -23,9 +27,49 @@
#include "clock.h"
/*------------------------------------------------------------------------
/* Some ARM_IDLECT1 bit shifts - used in struct arm_idlect1_clk */
#define IDL_CLKOUT_ARM_SHIFT 12
#define IDLTIM_ARM_SHIFT 9
#define IDLAPI_ARM_SHIFT 8
#define IDLIF_ARM_SHIFT 6
#define IDLLB_ARM_SHIFT 4
/* undocumented? */
#define OMAP1510_IDLLCD_ARM_SHIFT 3
/* undocumented? */
#define IDLPER_ARM_SHIFT 2
#define IDLXORP_ARM_SHIFT 1
#define IDLWDT_ARM_SHIFT 0
/* Some MOD_CONF_CTRL_0 bit shifts - used in struct clk.enable_bit */
#define CONF_MOD_UART3_CLK_MODE_R 31
#define CONF_MOD_UART2_CLK_MODE_R 30
#define CONF_MOD_UART1_CLK_MODE_R 29
#define CONF_MOD_MMC_SD_CLK_REQ_R 23
#define CONF_MOD_MCBSP3_AUXON 20
/* Some MOD_CONF_CTRL_1 bit shifts - used in struct clk.enable_bit */
#define CONF_MOD_SOSSI_CLK_EN_R 16
/* Some OTG_SYSCON_2-specific bit fields */
#define OTG_SYSCON_2_UHOST_EN_SHIFT 8
/* Some SOFT_REQ_REG bit fields - used in struct clk.enable_bit */
#define SOFT_MMC2_DPLL_REQ_SHIFT 13
#define SOFT_MMC_DPLL_REQ_SHIFT 12
#define SOFT_UART3_DPLL_REQ_SHIFT 11
#define SOFT_UART2_DPLL_REQ_SHIFT 10
#define SOFT_UART1_DPLL_REQ_SHIFT 9
#define SOFT_USB_OTG_DPLL_REQ_SHIFT 8
#define SOFT_CAM_DPLL_REQ_SHIFT 7
#define SOFT_COM_MCKO_REQ_SHIFT 6
#define SOFT_PERIPH_REQ_SHIFT 5
/* sys_ck gate for UART2 ? */
#define USB_REQ_EN_SHIFT 4
#define SOFT_USB_REQ_SHIFT 3
/* sys_ck gate for USB host? */
#define SOFT_SDW_REQ_SHIFT 2
/* sys_ck gate for Bluetooth? */
#define SOFT_COM_REQ_SHIFT 1
/* sys_ck gate for com proc? */
#define SOFT_DPLL_REQ_SHIFT 0
/*
* Omap1 clocks
*
-------------------------------------------------------------------------*
/
*/
static
struct
clk
ck_ref
=
{
.
name
=
"ck_ref"
,
...
...
@@ -54,7 +98,7 @@ static struct arm_idlect1_clk ck_dpll1out = {
.
enable_bit
=
EN_CKOUT_ARM
,
.
recalc
=
&
followparent_recalc
,
},
.
idlect_shift
=
12
,
.
idlect_shift
=
IDL_CLKOUT_ARM_SHIFT
,
};
static
struct
clk
sossi_ck
=
{
...
...
@@ -63,7 +107,7 @@ static struct clk sossi_ck = {
.
parent
=
&
ck_dpll1out
.
clk
,
.
flags
=
CLOCK_NO_IDLE_PARENT
|
ENABLE_REG_32BIT
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
MOD_CONF_CTRL_1
),
.
enable_bit
=
16
,
.
enable_bit
=
CONF_MOD_SOSSI_CLK_EN_R
,
.
recalc
=
&
omap1_sossi_recalc
,
.
set_rate
=
&
omap1_set_sossi_rate
,
};
...
...
@@ -91,7 +135,7 @@ static struct arm_idlect1_clk armper_ck = {
.
round_rate
=
omap1_clk_round_rate_ckctl_arm
,
.
set_rate
=
omap1_clk_set_rate_ckctl_arm
,
},
.
idlect_shift
=
2
,
.
idlect_shift
=
IDLPER_ARM_SHIFT
,
};
/*
...
...
@@ -118,7 +162,7 @@ static struct arm_idlect1_clk armxor_ck = {
.
enable_bit
=
EN_XORPCK
,
.
recalc
=
&
followparent_recalc
,
},
.
idlect_shift
=
1
,
.
idlect_shift
=
IDLXORP_ARM_SHIFT
,
};
static
struct
arm_idlect1_clk
armtim_ck
=
{
...
...
@@ -131,7 +175,7 @@ static struct arm_idlect1_clk armtim_ck = {
.
enable_bit
=
EN_TIMCK
,
.
recalc
=
&
followparent_recalc
,
},
.
idlect_shift
=
9
,
.
idlect_shift
=
IDLTIM_ARM_SHIFT
,
};
static
struct
arm_idlect1_clk
armwdt_ck
=
{
...
...
@@ -145,7 +189,7 @@ static struct arm_idlect1_clk armwdt_ck = {
.
fixed_div
=
14
,
.
recalc
=
&
omap_fixed_divisor_recalc
,
},
.
idlect_shift
=
0
,
.
idlect_shift
=
IDLWDT_ARM_SHIFT
,
};
static
struct
clk
arminth_ck16xx
=
{
...
...
@@ -212,7 +256,6 @@ static struct clk dsptim_ck = {
.
recalc
=
&
followparent_recalc
,
};
/* Tie ARM_IDLECT1:IDLIF_ARM to this logical clock structure */
static
struct
arm_idlect1_clk
tc_ck
=
{
.
clk
=
{
.
name
=
"tc_ck"
,
...
...
@@ -224,7 +267,7 @@ static struct arm_idlect1_clk tc_ck = {
.
round_rate
=
omap1_clk_round_rate_ckctl_arm
,
.
set_rate
=
omap1_clk_set_rate_ckctl_arm
,
},
.
idlect_shift
=
6
,
.
idlect_shift
=
IDLIF_ARM_SHIFT
,
};
static
struct
clk
arminth_ck1510
=
{
...
...
@@ -304,7 +347,7 @@ static struct arm_idlect1_clk api_ck = {
.
enable_bit
=
EN_APICK
,
.
recalc
=
&
followparent_recalc
,
},
.
idlect_shift
=
8
,
.
idlect_shift
=
IDLAPI_ARM_SHIFT
,
};
static
struct
arm_idlect1_clk
lb_ck
=
{
...
...
@@ -317,7 +360,7 @@ static struct arm_idlect1_clk lb_ck = {
.
enable_bit
=
EN_LBCK
,
.
recalc
=
&
followparent_recalc
,
},
.
idlect_shift
=
4
,
.
idlect_shift
=
IDLLB_ARM_SHIFT
,
};
static
struct
clk
rhea1_ck
=
{
...
...
@@ -359,9 +402,15 @@ static struct arm_idlect1_clk lcd_ck_1510 = {
.
round_rate
=
omap1_clk_round_rate_ckctl_arm
,
.
set_rate
=
omap1_clk_set_rate_ckctl_arm
,
},
.
idlect_shift
=
3
,
.
idlect_shift
=
OMAP1510_IDLLCD_ARM_SHIFT
,
};
/*
* XXX The enable_bit here is misused - it simply switches between 12MHz
* and 48MHz. Reimplement with clksel.
*
* XXX does this need SYSC register handling?
*/
static
struct
clk
uart1_1510
=
{
.
name
=
"uart1_ck"
,
.
ops
=
&
clkops_null
,
...
...
@@ -370,25 +419,37 @@ static struct clk uart1_1510 = {
.
rate
=
12000000
,
.
flags
=
ENABLE_REG_32BIT
|
CLOCK_NO_IDLE_PARENT
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
MOD_CONF_CTRL_0
),
.
enable_bit
=
29
,
/* Chooses between 12MHz and 48MHz */
.
enable_bit
=
CONF_MOD_UART1_CLK_MODE_R
,
.
set_rate
=
&
omap1_set_uart_rate
,
.
recalc
=
&
omap1_uart_recalc
,
};
/*
* XXX The enable_bit here is misused - it simply switches between 12MHz
* and 48MHz. Reimplement with clksel.
*
* XXX SYSC register handling does not belong in the clock framework
*/
static
struct
uart_clk
uart1_16xx
=
{
.
clk
=
{
.
name
=
"uart1_ck"
,
.
ops
=
&
clkops_uart
,
.
ops
=
&
clkops_uart
_16xx
,
/* Direct from ULPD, no real parent */
.
parent
=
&
armper_ck
.
clk
,
.
rate
=
48000000
,
.
flags
=
ENABLE_REG_32BIT
|
CLOCK_NO_IDLE_PARENT
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
MOD_CONF_CTRL_0
),
.
enable_bit
=
29
,
.
enable_bit
=
CONF_MOD_UART1_CLK_MODE_R
,
},
.
sysc_addr
=
0xfffb0054
,
};
/*
* XXX The enable_bit here is misused - it simply switches between 12MHz
* and 48MHz. Reimplement with clksel.
*
* XXX does this need SYSC register handling?
*/
static
struct
clk
uart2_ck
=
{
.
name
=
"uart2_ck"
,
.
ops
=
&
clkops_null
,
...
...
@@ -397,11 +458,17 @@ static struct clk uart2_ck = {
.
rate
=
12000000
,
.
flags
=
ENABLE_REG_32BIT
|
CLOCK_NO_IDLE_PARENT
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
MOD_CONF_CTRL_0
),
.
enable_bit
=
30
,
/* Chooses between 12MHz and 48MHz */
.
enable_bit
=
CONF_MOD_UART2_CLK_MODE_R
,
.
set_rate
=
&
omap1_set_uart_rate
,
.
recalc
=
&
omap1_uart_recalc
,
};
/*
* XXX The enable_bit here is misused - it simply switches between 12MHz
* and 48MHz. Reimplement with clksel.
*
* XXX does this need SYSC register handling?
*/
static
struct
clk
uart3_1510
=
{
.
name
=
"uart3_ck"
,
.
ops
=
&
clkops_null
,
...
...
@@ -410,21 +477,27 @@ static struct clk uart3_1510 = {
.
rate
=
12000000
,
.
flags
=
ENABLE_REG_32BIT
|
CLOCK_NO_IDLE_PARENT
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
MOD_CONF_CTRL_0
),
.
enable_bit
=
31
,
/* Chooses between 12MHz and 48MHz */
.
enable_bit
=
CONF_MOD_UART3_CLK_MODE_R
,
.
set_rate
=
&
omap1_set_uart_rate
,
.
recalc
=
&
omap1_uart_recalc
,
};
/*
* XXX The enable_bit here is misused - it simply switches between 12MHz
* and 48MHz. Reimplement with clksel.
*
* XXX SYSC register handling does not belong in the clock framework
*/
static
struct
uart_clk
uart3_16xx
=
{
.
clk
=
{
.
name
=
"uart3_ck"
,
.
ops
=
&
clkops_uart
,
.
ops
=
&
clkops_uart
_16xx
,
/* Direct from ULPD, no real parent */
.
parent
=
&
armper_ck
.
clk
,
.
rate
=
48000000
,
.
flags
=
ENABLE_REG_32BIT
|
CLOCK_NO_IDLE_PARENT
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
MOD_CONF_CTRL_0
),
.
enable_bit
=
31
,
.
enable_bit
=
CONF_MOD_UART3_CLK_MODE_R
,
},
.
sysc_addr
=
0xfffb9854
,
};
...
...
@@ -457,7 +530,7 @@ static struct clk usb_hhc_ck16xx = {
/* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
.
flags
=
ENABLE_REG_32BIT
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
OTG_BASE
+
0x08
),
/* OTG_SYSCON_2 */
.
enable_bit
=
8
/* UHOST_EN */
,
.
enable_bit
=
OTG_SYSCON_2_UHOST_EN_SHIFT
};
static
struct
clk
usb_dc_ck
=
{
...
...
@@ -466,7 +539,7 @@ static struct clk usb_dc_ck = {
/* Direct from ULPD, no parent */
.
rate
=
48000000
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
SOFT_REQ_REG
),
.
enable_bit
=
4
,
.
enable_bit
=
USB_REQ_EN_SHIFT
,
};
static
struct
clk
usb_dc_ck7xx
=
{
...
...
@@ -475,7 +548,7 @@ static struct clk usb_dc_ck7xx = {
/* Direct from ULPD, no parent */
.
rate
=
48000000
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
SOFT_REQ_REG
),
.
enable_bit
=
8
,
.
enable_bit
=
SOFT_USB_OTG_DPLL_REQ_SHIFT
,
};
static
struct
clk
uart1_7xx
=
{
...
...
@@ -502,7 +575,7 @@ static struct clk mclk_1510 = {
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.
rate
=
12000000
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
SOFT_REQ_REG
),
.
enable_bit
=
6
,
.
enable_bit
=
SOFT_COM_MCKO_REQ_SHIFT
,
};
static
struct
clk
mclk_16xx
=
{
...
...
@@ -542,9 +615,13 @@ static struct clk mmc1_ck = {
.
rate
=
48000000
,
.
flags
=
ENABLE_REG_32BIT
|
CLOCK_NO_IDLE_PARENT
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
MOD_CONF_CTRL_0
),
.
enable_bit
=
23
,
.
enable_bit
=
CONF_MOD_MMC_SD_CLK_REQ_R
,
};
/*
* XXX MOD_CONF_CTRL_0 bit 20 is defined in the 1510 TRM as
* CONF_MOD_MCBSP3_AUXON ??
*/
static
struct
clk
mmc2_ck
=
{
.
name
=
"mmc2_ck"
,
.
ops
=
&
clkops_generic
,
...
...
@@ -564,7 +641,7 @@ static struct clk mmc3_ck = {
.
rate
=
48000000
,
.
flags
=
ENABLE_REG_32BIT
|
CLOCK_NO_IDLE_PARENT
,
.
enable_reg
=
OMAP1_IO_ADDRESS
(
SOFT_REQ_REG
),
.
enable_bit
=
12
,
.
enable_bit
=
SOFT_MMC_DPLL_REQ_SHIFT
,
};
static
struct
clk
virtual_ck_mpu
=
{
...
...
arch/arm/mach-omap2/Makefile
View file @
331d919a
...
...
@@ -3,7 +3,7 @@
#
# Common support
obj-y
:=
id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o
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
hwmod-common
=
omap_hwmod.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
)
obj-$(CONFIG_ARCH_OMAP4)
+=
$
(
prcm-common
)
$
(
hwmod-common
)
obj-$(CONFIG_OMAP_MCBSP)
+=
mcbsp.o
...
...
arch/arm/mach-omap2/clock3xxx_data.c
View file @
331d919a
...
...
@@ -1408,7 +1408,7 @@ static struct clk ts_fck = {
static
struct
clk
usbtll_fck
=
{
.
name
=
"usbtll_fck"
,
.
ops
=
&
clkops_omap2_dflt
,
.
ops
=
&
clkops_omap2_dflt
_wait
,
.
parent
=
&
dpll5_m2_ck
,
.
enable_reg
=
OMAP_CM_REGADDR
(
CORE_MOD
,
OMAP3430ES2_CM_FCLKEN3
),
.
enable_bit
=
OMAP3430ES2_EN_USBTLL_SHIFT
,
...
...
arch/arm/mach-omap2/cm.c
View file @
331d919a
...
...
@@ -50,15 +50,15 @@ int omap2_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
cm_idlest_reg
=
cm_idlest_offs
[
idlest_id
-
1
];
mask
=
1
<<
idlest_shift
;
if
(
cpu_is_omap24xx
())
ena
=
idlest_shift
;
ena
=
mask
;
else
if
(
cpu_is_omap34xx
())
ena
=
0
;
else
BUG
();
mask
=
1
<<
idlest_shift
;
/* XXX should be OMAP2 CM */
omap_test_timeout
(((
cm_read_mod_reg
(
prcm_mod
,
cm_idlest_reg
)
&
mask
)
==
ena
),
MAX_MODULE_READY_TIME
,
i
);
...
...
arch/arm/mach-omap2/io.c
View file @
331d919a
...
...
@@ -44,6 +44,7 @@
#include <plat/clockdomain.h>
#include "clockdomains.h"
#include <plat/omap_hwmod.h>
/*
...
...
@@ -315,6 +316,8 @@ static int __init _omap2_init_reprogram_sdrc(void)
void
__init
omap2_init_common_hw
(
struct
omap_sdrc_params
*
sdrc_cs0
,
struct
omap_sdrc_params
*
sdrc_cs1
)
{
u8
skip_setup_idle
=
0
;
pwrdm_init
(
powerdomains_omap
);
clkdm_init
(
clockdomains_omap
,
clkdm_autodeps
);
if
(
cpu_is_omap242x
())
...
...
@@ -338,9 +341,13 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
pr_err
(
"Could not init clock framework - unknown CPU
\n
"
);
omap_serial_early_init
();
#ifndef CONFIG_PM_RUNTIME
skip_setup_idle
=
1
;
#endif
if
(
cpu_is_omap24xx
()
||
cpu_is_omap34xx
())
/* FIXME: OMAP4 */
omap_hwmod_late_init
();
omap_pm_if_init
();
omap_hwmod_late_init
(
skip_setup_idle
);
if
(
cpu_is_omap24xx
()
||
cpu_is_omap34xx
())
{
omap2_sdrc_init
(
sdrc_cs0
,
sdrc_cs1
);
_omap2_init_reprogram_sdrc
();
...
...
arch/arm/mach-omap2/omap_hwmod.c
View file @
331d919a
/*
* omap_hwmod implementation for OMAP2/3/4
*
* Copyright (C) 2009 Nokia Corporation
* Copyright (C) 2009
-2010
Nokia Corporation
*
* Paul Walmsley, Benoît Cousson, Kevin Hilman
*
...
...
@@ -423,7 +423,7 @@ static int _init_main_clk(struct omap_hwmod *oh)
}
/**
* _init_interface_clk - get a struct clk * for the the hwmod's interface clks
* _init_interface_clk
s
- get a struct clk * for the the hwmod's interface clks
* @oh: struct omap_hwmod *
*
* Called from _init_clocks(). Populates the @oh OCP slave interface
...
...
@@ -764,6 +764,7 @@ static struct omap_hwmod *_lookup(const char *name)
/**
* _init_clocks - clk_get() all clocks associated with this hwmod
* @oh: struct omap_hwmod *
* @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
...
...
@@ -771,7 +772,7 @@ static struct omap_hwmod *_lookup(const char *name)
* has not yet been registered or if the clocks have already been
* initialized, 0 on success, or a non-zero error on failure.
*/
static
int
_init_clocks
(
struct
omap_hwmod
*
oh
)
static
int
_init_clocks
(
struct
omap_hwmod
*
oh
,
void
*
data
)
{
int
ret
=
0
;
...
...
@@ -886,7 +887,7 @@ static int _reset(struct omap_hwmod *oh)
}
/**
* _enable - enable an omap_hwmod
* _
omap_hwmod_
enable - enable an omap_hwmod
* @oh: struct omap_hwmod *
*
* Enables an omap_hwmod @oh such that the MPU can access the hwmod's
...
...
@@ -894,7 +895,7 @@ static int _reset(struct omap_hwmod *oh)
* Returns -EINVAL if the hwmod is in the wrong state or passes along
* the return value of _wait_target_ready().
*/
static
int
_enable
(
struct
omap_hwmod
*
oh
)
int
_omap_hwmod
_enable
(
struct
omap_hwmod
*
oh
)
{
int
r
;
...
...
@@ -939,7 +940,7 @@ static int _enable(struct omap_hwmod *oh)
* no further work. Returns -EINVAL if the hwmod is in the wrong
* state or returns 0.
*/
static
int
_idle
(
struct
omap_hwmod
*
oh
)
int
_omap_hwmod
_idle
(
struct
omap_hwmod
*
oh
)
{
if
(
oh
->
_state
!=
_HWMOD_STATE_ENABLED
)
{
WARN
(
1
,
"omap_hwmod: %s: idle state can only be entered from "
...
...
@@ -996,19 +997,25 @@ static int _shutdown(struct omap_hwmod *oh)
/**
* _setup - do initial configuration of omap_hwmod
* @oh: struct omap_hwmod *
* @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. Returns -EINVAL if the hwmod is in the wrong state or returns
* 0.
* 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.
*/
static
int
_setup
(
struct
omap_hwmod
*
oh
)
static
int
_setup
(
struct
omap_hwmod
*
oh
,
void
*
data
)
{
int
i
,
r
;
u8
skip_setup_idle
;
if
(
!
oh
)
if
(
!
oh
||
!
data
)
return
-
EINVAL
;
skip_setup_idle
=
*
(
u8
*
)
data
;
/* Set iclk autoidle mode */
if
(
oh
->
slaves_cnt
>
0
)
{
for
(
i
=
0
;
i
<
oh
->
slaves_cnt
;
i
++
)
{
...
...
@@ -1029,7 +1036,7 @@ static int _setup(struct omap_hwmod *oh)
oh
->
_state
=
_HWMOD_STATE_INITIALIZED
;
r
=
_enable
(
oh
);
r
=
_
omap_hwmod_
enable
(
oh
);
if
(
r
)
{
pr_warning
(
"omap_hwmod: %s: cannot be enabled (%d)
\n
"
,
oh
->
name
,
oh
->
_state
);
...
...
@@ -1041,7 +1048,7 @@ static int _setup(struct omap_hwmod *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
* _enable() function should be split to avoid the
* _
omap_hwmod_
enable() function should be split to avoid the
* rewrite of the OCP_SYSCONFIG register.
*/
if
(
oh
->
class
->
sysc
)
{
...
...
@@ -1050,8 +1057,8 @@ static int _setup(struct omap_hwmod *oh)
}
}
if
(
!
(
oh
->
flags
&
HWMOD_INIT_NO_IDLE
))
_idle
(
oh
);
if
(
!
(
oh
->
flags
&
HWMOD_INIT_NO_IDLE
)
&&
!
skip_setup_idle
)
_
omap_hwmod_
idle
(
oh
);
return
0
;
}
...
...
@@ -1062,14 +1069,29 @@ static int _setup(struct omap_hwmod *oh)
u32
omap_hwmod_readl
(
struct
omap_hwmod
*
oh
,
u16
reg_offs
)
{
return
__raw_readl
(
oh
->
_rt_va
+
reg_offs
);
return
__raw_readl
(
oh
->
_
mpu_
rt_va
+
reg_offs
);
}
void
omap_hwmod_writel
(
u32
v
,
struct
omap_hwmod
*
oh
,
u16
reg_offs
)
{
__raw_writel
(
v
,
oh
->
_rt_va
+
reg_offs
);
__raw_writel
(
v
,
oh
->
_
mpu_
rt_va
+
reg_offs
);
}
/**
* omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode
* @oh: struct omap_hwmod *
* @idlemode: SIDLEMODE field bits (shifted to bit 0)
*
* Sets the IP block's OCP slave idlemode in hardware, and updates our
* local copy. Intended to be used by drivers that have some erratum
* that requires direct manipulation of the SIDLEMODE bits. Returns
* -EINVAL if @oh is null, or passes along the return value from
* _set_slave_idlemode().
*
* XXX Does this function have any current users? If not, we should
* remove it; it is better to let the rest of the hwmod code handle this.
* Any users of this function should be scrutinized carefully.
*/
int
omap_hwmod_set_slave_idlemode
(
struct
omap_hwmod
*
oh
,
u8
idlemode
)
{
u32
v
;
...
...
@@ -1124,7 +1146,7 @@ int omap_hwmod_register(struct omap_hwmod *oh)
ms_id
=
_find_mpu_port_index
(
oh
);
if
(
!
IS_ERR_VALUE
(
ms_id
))
{
oh
->
_mpu_port_index
=
ms_id
;
oh
->
_rt_va
=
_find_mpu_rt_base
(
oh
,
oh
->
_mpu_port_index
);
oh
->
_
mpu_
rt_va
=
_find_mpu_rt_base
(
oh
,
oh
->
_mpu_port_index
);
}
else
{
oh
->
_int_flags
|=
_HWMOD_NO_MPU_PORT
;
}
...
...
@@ -1164,6 +1186,7 @@ struct omap_hwmod *omap_hwmod_lookup(const char *name)
/**
* omap_hwmod_for_each - call function for each registered omap_hwmod
* @fn: pointer to a callback function
* @data: void * data to pass to callback function
*
* Call @fn for each registered omap_hwmod, passing @data to each
* function. @fn must return 0 for success or any other value for
...
...
@@ -1172,7 +1195,8 @@ struct omap_hwmod *omap_hwmod_lookup(const char *name)
* caller of omap_hwmod_for_each(). @fn is called with
* omap_hwmod_for_each() held.
*/
int
omap_hwmod_for_each
(
int
(
*
fn
)(
struct
omap_hwmod
*
oh
))
int
omap_hwmod_for_each
(
int
(
*
fn
)(
struct
omap_hwmod
*
oh
,
void
*
data
),
void
*
data
)
{
struct
omap_hwmod
*
temp_oh
;
int
ret
;
...
...
@@ -1182,7 +1206,7 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh))
mutex_lock
(
&
omap_hwmod_mutex
);
list_for_each_entry
(
temp_oh
,
&
omap_hwmod_list
,
node
)
{
ret
=
(
*
fn
)(
temp_oh
);
ret
=
(
*
fn
)(
temp_oh
,
data
);
if
(
ret
)
break
;
}
...
...
@@ -1229,24 +1253,28 @@ int omap_hwmod_init(struct omap_hwmod **ohs)
/**
* omap_hwmod_late_init - do some post-clock framework initialization
* @skip_setup_idle: if 1, do not idle hwmods in _setup()
*
* Must be called after omap2_clk_init(). Resolves the struct clk names
* to struct clk pointers for each registered omap_hwmod. Also calls
* _setup() on each hwmod. Returns 0.
*/
int
omap_hwmod_late_init
(
void
)
int
omap_hwmod_late_init
(
u8
skip_setup_idle
)
{
int
r
;
/* XXX check return value */
r
=
omap_hwmod_for_each
(
_init_clocks
);
r
=
omap_hwmod_for_each
(
_init_clocks
,
NULL
);
WARN
(
r
,
"omap_hwmod: omap_hwmod_late_init(): _init_clocks failed
\n
"
);
mpu_oh
=
omap_hwmod_lookup
(
MPU_INITIATOR_NAME
);
WARN
(
!
mpu_oh
,
"omap_hwmod: could not find MPU initiator hwmod %s
\n
"
,
MPU_INITIATOR_NAME
);
omap_hwmod_for_each
(
_setup
);
if
(
skip_setup_idle
)
pr_debug
(
"omap_hwmod: will leave hwmods enabled during setup
\n
"
);
omap_hwmod_for_each
(
_setup
,
&
skip_setup_idle
);
return
0
;
}
...
...
@@ -1270,7 +1298,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh)
pr_debug
(
"omap_hwmod: %s: unregistering
\n
"
,
oh
->
name
);
mutex_lock
(
&
omap_hwmod_mutex
);
iounmap
(
oh
->
_rt_va
);
iounmap
(
oh
->
_
mpu_
rt_va
);
list_del
(
&
oh
->
node
);
mutex_unlock
(
&
omap_hwmod_mutex
);
...
...
@@ -1292,12 +1320,13 @@ int omap_hwmod_enable(struct omap_hwmod *oh)
return
-
EINVAL
;
mutex_lock
(
&
omap_hwmod_mutex
);
r
=
_enable
(
oh
);
r
=
_
omap_hwmod_
enable
(
oh
);
mutex_unlock
(
&
omap_hwmod_mutex
);
return
r
;
}
/**
* omap_hwmod_idle - idle an omap_hwmod
* @oh: struct omap_hwmod *
...
...
@@ -1311,7 +1340,7 @@ int omap_hwmod_idle(struct omap_hwmod *oh)
return
-
EINVAL
;
mutex_lock
(
&
omap_hwmod_mutex
);
_idle
(
oh
);
_
omap_hwmod_
idle
(
oh
);
mutex_unlock
(
&
omap_hwmod_mutex
);
return
0
;
...
...
@@ -1413,7 +1442,7 @@ int omap_hwmod_reset(struct omap_hwmod *oh)
mutex_lock
(
&
omap_hwmod_mutex
);
r
=
_reset
(
oh
);
if
(
!
r
)
r
=
_enable
(
oh
);
r
=
_
omap_hwmod_
enable
(
oh
);
mutex_unlock
(
&
omap_hwmod_mutex
);
return
r
;
...
...
@@ -1529,6 +1558,29 @@ struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh)
}
/**
* omap_hwmod_get_mpu_rt_va - return the module's base address (for the MPU)
* @oh: struct omap_hwmod *
*
* Returns the virtual address corresponding to the beginning of the
* module's register target, in the address range that is intended to
* be used by the MPU. Returns the virtual address upon success or NULL
* upon error.
*/
void
__iomem
*
omap_hwmod_get_mpu_rt_va
(
struct
omap_hwmod
*
oh
)
{
if
(
!
oh
)
return
NULL
;
if
(
oh
->
_int_flags
&
_HWMOD_NO_MPU_PORT
)
return
NULL
;
if
(
oh
->
_state
==
_HWMOD_STATE_UNKNOWN
)
return
NULL
;
return
oh
->
_mpu_rt_va
;
}
/**
* omap_hwmod_add_initiator_dep - add sleepdep from @init_oh to @oh
* @oh: struct omap_hwmod *
...
...
arch/arm/mach-omap2/omap_hwmod_2420_data.c
View file @
331d919a
...
...
@@ -30,42 +30,44 @@
*/
static
struct
omap_hwmod
omap2420_mpu_hwmod
;
static
struct
omap_hwmod
omap2420_l3_hwmod
;
static
struct
omap_hwmod
omap2420_iva_hwmod
;
static
struct
omap_hwmod
omap2420_l3_main_hwmod
;
static
struct
omap_hwmod
omap2420_l4_core_hwmod
;
/* L3 -> L4_CORE interface */
static
struct
omap_hwmod_ocp_if
omap2420_l3__l4_core
=
{
.
master
=
&
omap2420_l3_hwmod
,
static
struct
omap_hwmod_ocp_if
omap2420_l3_
main_
_l4_core
=
{
.
master
=
&
omap2420_l3_
main_
hwmod
,
.
slave
=
&
omap2420_l4_core_hwmod
,
.
user
=
OCP_USER_MPU
|
OCP_USER_SDMA
,
};
/* MPU -> L3 interface */
static
struct
omap_hwmod_ocp_if
omap2420_mpu__l3
=
{
static
struct
omap_hwmod_ocp_if
omap2420_mpu__l3
_main
=
{
.
master
=
&
omap2420_mpu_hwmod
,
.
slave
=
&
omap2420_l3_hwmod
,
.
slave
=
&
omap2420_l3_
main_
hwmod
,
.
user
=
OCP_USER_MPU
,
};
/* Slave interfaces on the L3 interconnect */
static
struct
omap_hwmod_ocp_if
*
omap2420_l3_slaves
[]
=
{
&
omap2420_mpu__l3
,
static
struct
omap_hwmod_ocp_if
*
omap2420_l3_
main_
slaves
[]
=
{
&
omap2420_mpu__l3
_main
,
};
/* Master interfaces on the L3 interconnect */
static
struct
omap_hwmod_ocp_if
*
omap2420_l3_masters
[]
=
{
&
omap2420_l3__l4_core
,
static
struct
omap_hwmod_ocp_if
*
omap2420_l3_ma
in_ma
sters
[]
=
{
&
omap2420_l3_
main_
_l4_core
,
};
/* L3 */
static
struct
omap_hwmod
omap2420_l3_hwmod
=
{
.
name
=
"l3_
hwmod
"
,
static
struct
omap_hwmod
omap2420_l3_
main_
hwmod
=
{
.
name
=
"l3_
main
"
,
.
class
=
&
l3_hwmod_class
,
.
masters
=
omap2420_l3_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2420_l3_masters
),
.
slaves
=
omap2420_l3_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap2420_l3_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2420
)
.
masters
=
omap2420_l3_main_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2420_l3_main_masters
),
.
slaves
=
omap2420_l3_main_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap2420_l3_main_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2420
),
.
flags
=
HWMOD_NO_IDLEST
,
};
static
struct
omap_hwmod
omap2420_l4_wkup_hwmod
;
...
...
@@ -79,7 +81,7 @@ static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
/* Slave interfaces on the L4_CORE interconnect */
static
struct
omap_hwmod_ocp_if
*
omap2420_l4_core_slaves
[]
=
{
&
omap2420_l3__l4_core
,
&
omap2420_l3_
main_
_l4_core
,
};
/* Master interfaces on the L4_CORE interconnect */
...
...
@@ -89,13 +91,14 @@ static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = {
/* L4 CORE */
static
struct
omap_hwmod
omap2420_l4_core_hwmod
=
{
.
name
=
"l4_core
_hwmod
"
,
.
name
=
"l4_core"
,
.
class
=
&
l4_hwmod_class
,
.
masters
=
omap2420_l4_core_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2420_l4_core_masters
),
.
slaves
=
omap2420_l4_core_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap2420_l4_core_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2420
)
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2420
),
.
flags
=
HWMOD_NO_IDLEST
,
};
/* Slave interfaces on the L4_WKUP interconnect */
...
...
@@ -109,18 +112,19 @@ static struct omap_hwmod_ocp_if *omap2420_l4_wkup_masters[] = {
/* L4 WKUP */
static
struct
omap_hwmod
omap2420_l4_wkup_hwmod
=
{
.
name
=
"l4_wkup
_hwmod
"
,
.
name
=
"l4_wkup"
,
.
class
=
&
l4_hwmod_class
,
.
masters
=
omap2420_l4_wkup_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2420_l4_wkup_masters
),
.
slaves
=
omap2420_l4_wkup_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap2420_l4_wkup_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2420
)
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2420
),
.
flags
=
HWMOD_NO_IDLEST
,
};
/* Master interfaces on the MPU device */
static
struct
omap_hwmod_ocp_if
*
omap2420_mpu_masters
[]
=
{
&
omap2420_mpu__l3
,
&
omap2420_mpu__l3
_main
,
};
/* MPU */
...
...
@@ -133,11 +137,40 @@ static struct omap_hwmod omap2420_mpu_hwmod = {
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2420
),
};
/*
* IVA1 interface data
*/
/* IVA <- L3 interface */
static
struct
omap_hwmod_ocp_if
omap2420_l3__iva
=
{
.
master
=
&
omap2420_l3_main_hwmod
,
.
slave
=
&
omap2420_iva_hwmod
,
.
clk
=
"iva1_ifck"
,
.
user
=
OCP_USER_MPU
|
OCP_USER_SDMA
,
};
static
struct
omap_hwmod_ocp_if
*
omap2420_iva_masters
[]
=
{
&
omap2420_l3__iva
,
};
/*
* IVA2 (IVA2)
*/
static
struct
omap_hwmod
omap2420_iva_hwmod
=
{
.
name
=
"iva"
,
.
class
=
&
iva_hwmod_class
,
.
masters
=
omap2420_iva_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2420_iva_masters
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2420
)
};
static
__initdata
struct
omap_hwmod
*
omap2420_hwmods
[]
=
{
&
omap2420_l3_hwmod
,
&
omap2420_l3_
main_
hwmod
,
&
omap2420_l4_core_hwmod
,
&
omap2420_l4_wkup_hwmod
,
&
omap2420_mpu_hwmod
,
&
omap2420_iva_hwmod
,
NULL
,
};
...
...
arch/arm/mach-omap2/omap_hwmod_2430_data.c
View file @
331d919a
...
...
@@ -30,47 +30,47 @@
*/
static
struct
omap_hwmod
omap2430_mpu_hwmod
;
static
struct
omap_hwmod
omap2430_l3_hwmod
;
static
struct
omap_hwmod
omap2430_iva_hwmod
;
static
struct
omap_hwmod
omap2430_l3_main_hwmod
;
static
struct
omap_hwmod
omap2430_l4_core_hwmod
;
/* L3 -> L4_CORE interface */
static
struct
omap_hwmod_ocp_if
omap2430_l3__l4_core
=
{
.
master
=
&
omap2430_l3_hwmod
,
static
struct
omap_hwmod_ocp_if
omap2430_l3_
main_
_l4_core
=
{
.
master
=
&
omap2430_l3_
main_
hwmod
,
.
slave
=
&
omap2430_l4_core_hwmod
,
.
user
=
OCP_USER_MPU
|
OCP_USER_SDMA
,
};
/* MPU -> L3 interface */
static
struct
omap_hwmod_ocp_if
omap2430_mpu__l3
=
{
static
struct
omap_hwmod_ocp_if
omap2430_mpu__l3
_main
=
{
.
master
=
&
omap2430_mpu_hwmod
,
.
slave
=
&
omap2430_l3_hwmod
,
.
slave
=
&
omap2430_l3_
main_
hwmod
,
.
user
=
OCP_USER_MPU
,
};
/* Slave interfaces on the L3 interconnect */
static
struct
omap_hwmod_ocp_if
*
omap2430_l3_slaves
[]
=
{
&
omap2430_mpu__l3
,
static
struct
omap_hwmod_ocp_if
*
omap2430_l3_
main_
slaves
[]
=
{
&
omap2430_mpu__l3
_main
,
};
/* Master interfaces on the L3 interconnect */
static
struct
omap_hwmod_ocp_if
*
omap2430_l3_masters
[]
=
{
&
omap2430_l3__l4_core
,
static
struct
omap_hwmod_ocp_if
*
omap2430_l3_ma
in_ma
sters
[]
=
{
&
omap2430_l3_
main_
_l4_core
,
};
/* L3 */
static
struct
omap_hwmod
omap2430_l3_hwmod
=
{
.
name
=
"l3_
hwmod
"
,
static
struct
omap_hwmod
omap2430_l3_
main_
hwmod
=
{
.
name
=
"l3_
main
"
,
.
class
=
&
l3_hwmod_class
,
.
masters
=
omap2430_l3_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2430_l3_masters
),
.
slaves
=
omap2430_l3_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap2430_l3_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2430
)
.
masters
=
omap2430_l3_main_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2430_l3_main_masters
),
.
slaves
=
omap2430_l3_main_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap2430_l3_main_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2430
),
.
flags
=
HWMOD_NO_IDLEST
,
};
static
struct
omap_hwmod
omap2430_l4_wkup_hwmod
;
static
struct
omap_hwmod
omap2430_mmc1_hwmod
;
static
struct
omap_hwmod
omap2430_mmc2_hwmod
;
/* L4_CORE -> L4_WKUP interface */
static
struct
omap_hwmod_ocp_if
omap2430_l4_core__l4_wkup
=
{
...
...
@@ -81,7 +81,7 @@ static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = {
/* Slave interfaces on the L4_CORE interconnect */
static
struct
omap_hwmod_ocp_if
*
omap2430_l4_core_slaves
[]
=
{
&
omap2430_l3__l4_core
,
&
omap2430_l3_
main_
_l4_core
,
};
/* Master interfaces on the L4_CORE interconnect */
...
...
@@ -91,13 +91,14 @@ static struct omap_hwmod_ocp_if *omap2430_l4_core_masters[] = {
/* L4 CORE */
static
struct
omap_hwmod
omap2430_l4_core_hwmod
=
{
.
name
=
"l4_core
_hwmod
"
,
.
name
=
"l4_core"
,
.
class
=
&
l4_hwmod_class
,
.
masters
=
omap2430_l4_core_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2430_l4_core_masters
),
.
slaves
=
omap2430_l4_core_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap2430_l4_core_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2430
)
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2430
),
.
flags
=
HWMOD_NO_IDLEST
,
};
/* Slave interfaces on the L4_WKUP interconnect */
...
...
@@ -111,18 +112,19 @@ static struct omap_hwmod_ocp_if *omap2430_l4_wkup_masters[] = {
/* L4 WKUP */
static
struct
omap_hwmod
omap2430_l4_wkup_hwmod
=
{
.
name
=
"l4_wkup
_hwmod
"
,
.
name
=
"l4_wkup"
,
.
class
=
&
l4_hwmod_class
,
.
masters
=
omap2430_l4_wkup_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2430_l4_wkup_masters
),
.
slaves
=
omap2430_l4_wkup_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap2430_l4_wkup_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2430
)
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2430
),
.
flags
=
HWMOD_NO_IDLEST
,
};
/* Master interfaces on the MPU device */
static
struct
omap_hwmod_ocp_if
*
omap2430_mpu_masters
[]
=
{
&
omap2430_mpu__l3
,
&
omap2430_mpu__l3
_main
,
};
/* MPU */
...
...
@@ -135,11 +137,40 @@ static struct omap_hwmod omap2430_mpu_hwmod = {
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2430
),
};
/*
* IVA2_1 interface data
*/
/* IVA2 <- L3 interface */
static
struct
omap_hwmod_ocp_if
omap2430_l3__iva
=
{
.
master
=
&
omap2430_l3_main_hwmod
,
.
slave
=
&
omap2430_iva_hwmod
,
.
clk
=
"dsp_fck"
,
.
user
=
OCP_USER_MPU
|
OCP_USER_SDMA
,
};
static
struct
omap_hwmod_ocp_if
*
omap2430_iva_masters
[]
=
{
&
omap2430_l3__iva
,
};
/*
* IVA2 (IVA2)
*/
static
struct
omap_hwmod
omap2430_iva_hwmod
=
{
.
name
=
"iva"
,
.
class
=
&
iva_hwmod_class
,
.
masters
=
omap2430_iva_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap2430_iva_masters
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP2430
)
};
static
__initdata
struct
omap_hwmod
*
omap2430_hwmods
[]
=
{
&
omap2430_l3_hwmod
,
&
omap2430_l3_
main_
hwmod
,
&
omap2430_l4_core_hwmod
,
&
omap2430_l4_wkup_hwmod
,
&
omap2430_mpu_hwmod
,
&
omap2430_iva_hwmod
,
NULL
,
};
...
...
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
View file @
331d919a
...
...
@@ -32,51 +32,53 @@
*/
static
struct
omap_hwmod
omap3xxx_mpu_hwmod
;
static
struct
omap_hwmod
omap3xxx_l3_hwmod
;
static
struct
omap_hwmod
omap3xxx_iva_hwmod
;
static
struct
omap_hwmod
omap3xxx_l3_main_hwmod
;
static
struct
omap_hwmod
omap3xxx_l4_core_hwmod
;
static
struct
omap_hwmod
omap3xxx_l4_per_hwmod
;
/* L3 -> L4_CORE interface */
static
struct
omap_hwmod_ocp_if
omap3xxx_l3__l4_core
=
{
.
master
=
&
omap3xxx_l3_hwmod
,
static
struct
omap_hwmod_ocp_if
omap3xxx_l3_
main_
_l4_core
=
{
.
master
=
&
omap3xxx_l3_
main_
hwmod
,
.
slave
=
&
omap3xxx_l4_core_hwmod
,
.
user
=
OCP_USER_MPU
|
OCP_USER_SDMA
,
};
/* L3 -> L4_PER interface */
static
struct
omap_hwmod_ocp_if
omap3xxx_l3__l4_per
=
{
.
master
=
&
omap3xxx_l3_hwmod
,
static
struct
omap_hwmod_ocp_if
omap3xxx_l3_
main_
_l4_per
=
{
.
master
=
&
omap3xxx_l3_
main_
hwmod
,
.
slave
=
&
omap3xxx_l4_per_hwmod
,
.
user
=
OCP_USER_MPU
|
OCP_USER_SDMA
,
};
/* MPU -> L3 interface */
static
struct
omap_hwmod_ocp_if
omap3xxx_mpu__l3
=
{
static
struct
omap_hwmod_ocp_if
omap3xxx_mpu__l3
_main
=
{
.
master
=
&
omap3xxx_mpu_hwmod
,
.
slave
=
&
omap3xxx_l3_hwmod
,
.
slave
=
&
omap3xxx_l3_
main_
hwmod
,
.
user
=
OCP_USER_MPU
,
};
/* Slave interfaces on the L3 interconnect */
static
struct
omap_hwmod_ocp_if
*
omap3xxx_l3_slaves
[]
=
{
&
omap3xxx_mpu__l3
,
static
struct
omap_hwmod_ocp_if
*
omap3xxx_l3_
main_
slaves
[]
=
{
&
omap3xxx_mpu__l3
_main
,
};
/* Master interfaces on the L3 interconnect */
static
struct
omap_hwmod_ocp_if
*
omap3xxx_l3_masters
[]
=
{
&
omap3xxx_l3__l4_core
,
&
omap3xxx_l3__l4_per
,
static
struct
omap_hwmod_ocp_if
*
omap3xxx_l3_ma
in_ma
sters
[]
=
{
&
omap3xxx_l3_
main_
_l4_core
,
&
omap3xxx_l3_
main_
_l4_per
,
};
/* L3 */
static
struct
omap_hwmod
omap3xxx_l3_hwmod
=
{
.
name
=
"l3_
hwmod
"
,
static
struct
omap_hwmod
omap3xxx_l3_
main_
hwmod
=
{
.
name
=
"l3_
main
"
,
.
class
=
&
l3_hwmod_class
,
.
masters
=
omap3xxx_l3_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap3xxx_l3_masters
),
.
slaves
=
omap3xxx_l3_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap3xxx_l3_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
)
.
masters
=
omap3xxx_l3_main_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap3xxx_l3_main_masters
),
.
slaves
=
omap3xxx_l3_main_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap3xxx_l3_main_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
),
.
flags
=
HWMOD_NO_IDLEST
,
};
static
struct
omap_hwmod
omap3xxx_l4_wkup_hwmod
;
...
...
@@ -90,7 +92,7 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
/* Slave interfaces on the L4_CORE interconnect */
static
struct
omap_hwmod_ocp_if
*
omap3xxx_l4_core_slaves
[]
=
{
&
omap3xxx_l3__l4_core
,
&
omap3xxx_l3_
main_
_l4_core
,
};
/* Master interfaces on the L4_CORE interconnect */
...
...
@@ -100,18 +102,19 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_core_masters[] = {
/* L4 CORE */
static
struct
omap_hwmod
omap3xxx_l4_core_hwmod
=
{
.
name
=
"l4_core
_hwmod
"
,
.
name
=
"l4_core"
,
.
class
=
&
l4_hwmod_class
,
.
masters
=
omap3xxx_l4_core_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap3xxx_l4_core_masters
),
.
slaves
=
omap3xxx_l4_core_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap3xxx_l4_core_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
)
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
),
.
flags
=
HWMOD_NO_IDLEST
,
};
/* Slave interfaces on the L4_PER interconnect */
static
struct
omap_hwmod_ocp_if
*
omap3xxx_l4_per_slaves
[]
=
{
&
omap3xxx_l3__l4_per
,
&
omap3xxx_l3_
main_
_l4_per
,
};
/* Master interfaces on the L4_PER interconnect */
...
...
@@ -120,13 +123,14 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_per_masters[] = {
/* L4 PER */
static
struct
omap_hwmod
omap3xxx_l4_per_hwmod
=
{
.
name
=
"l4_per
_hwmod
"
,
.
name
=
"l4_per"
,
.
class
=
&
l4_hwmod_class
,
.
masters
=
omap3xxx_l4_per_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap3xxx_l4_per_masters
),
.
slaves
=
omap3xxx_l4_per_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap3xxx_l4_per_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
)
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
),
.
flags
=
HWMOD_NO_IDLEST
,
};
/* Slave interfaces on the L4_WKUP interconnect */
...
...
@@ -140,18 +144,19 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_masters[] = {
/* L4 WKUP */
static
struct
omap_hwmod
omap3xxx_l4_wkup_hwmod
=
{
.
name
=
"l4_wkup
_hwmod
"
,
.
name
=
"l4_wkup"
,
.
class
=
&
l4_hwmod_class
,
.
masters
=
omap3xxx_l4_wkup_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap3xxx_l4_wkup_masters
),
.
slaves
=
omap3xxx_l4_wkup_slaves
,
.
slaves_cnt
=
ARRAY_SIZE
(
omap3xxx_l4_wkup_slaves
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
)
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
),
.
flags
=
HWMOD_NO_IDLEST
,
};
/* Master interfaces on the MPU device */
static
struct
omap_hwmod_ocp_if
*
omap3xxx_mpu_masters
[]
=
{
&
omap3xxx_mpu__l3
,
&
omap3xxx_mpu__l3
_main
,
};
/* MPU */
...
...
@@ -164,12 +169,41 @@ static struct omap_hwmod omap3xxx_mpu_hwmod = {
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
),
};
/*
* IVA2_2 interface data
*/
/* IVA2 <- L3 interface */
static
struct
omap_hwmod_ocp_if
omap3xxx_l3__iva
=
{
.
master
=
&
omap3xxx_l3_main_hwmod
,
.
slave
=
&
omap3xxx_iva_hwmod
,
.
clk
=
"iva2_ck"
,
.
user
=
OCP_USER_MPU
|
OCP_USER_SDMA
,
};
static
struct
omap_hwmod_ocp_if
*
omap3xxx_iva_masters
[]
=
{
&
omap3xxx_l3__iva
,
};
/*
* IVA2 (IVA2)
*/
static
struct
omap_hwmod
omap3xxx_iva_hwmod
=
{
.
name
=
"iva"
,
.
class
=
&
iva_hwmod_class
,
.
masters
=
omap3xxx_iva_masters
,
.
masters_cnt
=
ARRAY_SIZE
(
omap3xxx_iva_masters
),
.
omap_chip
=
OMAP_CHIP_INIT
(
CHIP_IS_OMAP3430
)
};
static
__initdata
struct
omap_hwmod
*
omap3xxx_hwmods
[]
=
{
&
omap3xxx_l3_hwmod
,
&
omap3xxx_l3_
main_
hwmod
,
&
omap3xxx_l4_core_hwmod
,
&
omap3xxx_l4_per_hwmod
,
&
omap3xxx_l4_wkup_hwmod
,
&
omap3xxx_mpu_hwmod
,
&
omap3xxx_iva_hwmod
,
NULL
,
};
...
...
arch/arm/mach-omap2/omap_hwmod_common_data.c
View file @
331d919a
...
...
@@ -66,3 +66,6 @@ struct omap_hwmod_class mpu_hwmod_class = {
.
name
=
"mpu"
};
struct
omap_hwmod_class
iva_hwmod_class
=
{
.
name
=
"iva"
};
arch/arm/mach-omap2/omap_hwmod_common_data.h
View file @
331d919a
...
...
@@ -20,5 +20,6 @@
extern
struct
omap_hwmod_class
l3_hwmod_class
;
extern
struct
omap_hwmod_class
l4_hwmod_class
;
extern
struct
omap_hwmod_class
mpu_hwmod_class
;
extern
struct
omap_hwmod_class
iva_hwmod_class
;
#endif
arch/arm/mach-omap2/pm.c
0 → 100644
View file @
331d919a
/*
* pm.c - Common OMAP2+ power management-related code
*
* Copyright (C) 2010 Texas Instruments, Inc.
* Copyright (C) 2010 Nokia Corporation
*
* 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/init.h>
#include <linux/io.h>
#include <linux/err.h>
#include <plat/omap-pm.h>
#include <plat/omap_device.h>
#include <plat/common.h>
static
struct
omap_device_pm_latency
*
pm_lats
;
static
struct
device
*
mpu_dev
;
static
struct
device
*
dsp_dev
;
static
struct
device
*
l3_dev
;
struct
device
*
omap2_get_mpuss_device
(
void
)
{
WARN_ON_ONCE
(
!
mpu_dev
);
return
mpu_dev
;
}
struct
device
*
omap2_get_dsp_device
(
void
)
{
WARN_ON_ONCE
(
!
dsp_dev
);
return
dsp_dev
;
}
struct
device
*
omap2_get_l3_device
(
void
)
{
WARN_ON_ONCE
(
!
l3_dev
);
return
l3_dev
;
}
/* static int _init_omap_device(struct omap_hwmod *oh, void *user) */
static
int
_init_omap_device
(
char
*
name
,
struct
device
**
new_dev
)
{
struct
omap_hwmod
*
oh
;
struct
omap_device
*
od
;
oh
=
omap_hwmod_lookup
(
name
);
if
(
WARN
(
!
oh
,
"%s: could not find omap_hwmod for %s
\n
"
,
__func__
,
name
))
return
-
ENODEV
;
od
=
omap_device_build
(
oh
->
name
,
0
,
oh
,
NULL
,
0
,
pm_lats
,
0
,
false
);
if
(
WARN
(
IS_ERR
(
od
),
"%s: could not build omap_device for %s
\n
"
,
__func__
,
name
))
return
-
ENODEV
;
*
new_dev
=
&
od
->
pdev
.
dev
;
return
0
;
}
/*
* Build omap_devices for processors and bus.
*/
static
void
omap2_init_processor_devices
(
void
)
{
_init_omap_device
(
"mpu"
,
&
mpu_dev
);
_init_omap_device
(
"iva"
,
&
dsp_dev
);
_init_omap_device
(
"l3_main"
,
&
l3_dev
);
}
static
int
__init
omap2_common_pm_init
(
void
)
{
omap2_init_processor_devices
();
omap_pm_if_init
();
return
0
;
}
device_initcall
(
omap2_common_pm_init
);
arch/arm/plat-omap/Makefile
View file @
331d919a
...
...
@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
# omap_device support (OMAP2+ only at the moment)
obj-$(CONFIG_ARCH_OMAP2)
+=
omap_device.o
obj-$(CONFIG_ARCH_OMAP3)
+=
omap_device.o
obj-$(CONFIG_ARCH_OMAP4)
+=
omap_device.o
obj-$(CONFIG_OMAP_MCBSP)
+=
mcbsp.o
obj-$(CONFIG_OMAP_IOMMU)
+=
iommu.o iovmm.o
...
...
arch/arm/plat-omap/i2c.c
View file @
331d919a
...
...
@@ -138,6 +138,16 @@ static inline int omap1_i2c_add_bus(struct platform_device *pdev, int bus_id)
return
platform_device_register
(
pdev
);
}
/*
* XXX This function is a temporary compatibility wrapper - only
* needed until the I2C driver can be converted to call
* omap_pm_set_max_dev_wakeup_lat() and handle a return code.
*/
static
void
omap_pm_set_max_mpu_wakeup_lat_compat
(
struct
device
*
dev
,
long
t
)
{
omap_pm_set_max_mpu_wakeup_lat
(
dev
,
t
);
}
static
inline
int
omap2_i2c_add_bus
(
struct
platform_device
*
pdev
,
int
bus_id
)
{
struct
resource
*
res
;
...
...
@@ -168,7 +178,7 @@ static inline int omap2_i2c_add_bus(struct platform_device *pdev, int bus_id)
struct
omap_i2c_bus_platform_data
*
pd
;
pd
=
pdev
->
dev
.
platform_data
;
pd
->
set_mpu_wkup_lat
=
omap_pm_set_max_mpu_wakeup_lat
;
pd
->
set_mpu_wkup_lat
=
omap_pm_set_max_mpu_wakeup_lat
_compat
;
}
return
platform_device_register
(
pdev
);
...
...
arch/arm/plat-omap/include/plat/clock.h
View file @
331d919a
...
...
@@ -19,6 +19,22 @@ struct module;
struct
clk
;
struct
clockdomain
;
/**
* struct clkops - some clock function pointers
* @enable: fn ptr that enables the current clock in hardware
* @disable: fn ptr that enables the current clock in hardware
* @find_idlest: function returning the IDLEST register for the clock's IP blk
* @find_companion: function returning the "companion" clk reg for the clock
*
* A "companion" clk is an accompanying clock to the one being queried
* that must be enabled for the IP module connected to the clock to
* become accessible by the hardware. Neither @find_idlest nor
* @find_companion should be needed; that information is IP
* block-specific; the hwmod code has been created to handle this, but
* until hwmod data is ready and drivers have been converted to use PM
* runtime calls in place of clk_enable()/clk_disable(), @find_idlest and
* @find_companion must, unfortunately, remain.
*/
struct
clkops
{
int
(
*
enable
)(
struct
clk
*
);
void
(
*
disable
)(
struct
clk
*
);
...
...
@@ -30,12 +46,45 @@ struct clkops {
#ifdef CONFIG_ARCH_OMAP2PLUS
/* struct clksel_rate.flags possibilities */
#define RATE_IN_242X (1 << 0)
#define RATE_IN_243X (1 << 1)
#define RATE_IN_3XXX (1 << 2)
/* rates common to all OMAP3 */
#define RATE_IN_3430ES2 (1 << 3)
/* 3430ES2 rates only */
#define RATE_IN_36XX (1 << 4)
#define RATE_IN_4430 (1 << 5)
#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)
#define RATE_IN_3430ES2PLUS (RATE_IN_3430ES2 | RATE_IN_36XX)
/**
* struct clksel_rate - register bitfield values corresponding to clk divisors
* @val: register bitfield value (shifted to bit 0)
* @div: clock divisor corresponding to @val
* @flags: (see "struct clksel_rate.flags possibilities" above)
*
* @val should match the value of a read from struct clk.clksel_reg
* AND'ed with struct clk.clksel_mask, shifted right to bit 0.
*
* @div is the divisor that should be applied to the parent clock's rate
* to produce the current clock's rate.
*
* XXX @flags probably should be replaced with an struct omap_chip.
*/
struct
clksel_rate
{
u32
val
;
u8
div
;
u8
flags
;
};
/**
* struct clksel - available parent clocks, and a pointer to their divisors
* @parent: struct clk * to a possible parent clock
* @rates: available divisors for this parent clock
*
* A struct clksel is always associated with one or more struct clks
* and one or more struct clksel_rates.
*/
struct
clksel
{
struct
clk
*
parent
;
const
struct
clksel_rate
*
rates
;
...
...
@@ -116,6 +165,60 @@ struct dpll_data {
#endif
/* struct clk.flags possibilities */
#define ENABLE_REG_32BIT (1 << 0)
/* Use 32-bit access */
#define CLOCK_IDLE_CONTROL (1 << 1)
#define CLOCK_NO_IDLE_PARENT (1 << 2)
#define ENABLE_ON_INIT (1 << 3)
/* Enable upon framework init */
#define INVERT_ENABLE (1 << 4)
/* 0 enables, 1 disables */
/**
* struct clk - OMAP struct clk
* @node: list_head connecting this clock into the full clock list
* @ops: struct clkops * for this clock
* @name: the name of the clock in the hardware (used in hwmod data and debug)
* @parent: pointer to this clock's parent struct clk
* @children: list_head connecting to the child clks' @sibling list_heads
* @sibling: list_head connecting this clk to its parent clk's @children
* @rate: current clock rate
* @enable_reg: register to write to enable the clock (see @enable_bit)
* @recalc: fn ptr that returns the clock's current rate
* @set_rate: fn ptr that can change the clock's current rate
* @round_rate: fn ptr that can round the clock's current rate
* @init: fn ptr to do clock-specific initialization
* @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg)
* @usecount: number of users that have requested this clock to be enabled
* @fixed_div: when > 0, this clock's rate is its parent's rate / @fixed_div
* @flags: see "struct clk.flags possibilities" above
* @clksel_reg: for clksel clks, register va containing src/divisor select
* @clksel_mask: bitmask in @clksel_reg for the src/divisor selector
* @clksel: for clksel clks, pointer to struct clksel for this clock
* @dpll_data: for DPLLs, pointer to struct dpll_data for this clock
* @clkdm_name: clockdomain name that this clock is contained in
* @clkdm: pointer to struct clockdomain, resolved from @clkdm_name at runtime
* @rate_offset: bitshift for rate selection bitfield (OMAP1 only)
* @src_offset: bitshift for source selection bitfield (OMAP1 only)
*
* XXX @rate_offset, @src_offset should probably be removed and OMAP1
* clock code converted to use clksel.
*
* XXX @usecount is poorly named. It should be "enable_count" or
* something similar. "users" in the description refers to kernel
* code (core code or drivers) that have called clk_enable() and not
* yet called clk_disable(); the usecount of parent clocks is also
* incremented by the clock code when clk_enable() is called on child
* clocks and decremented by the clock code when clk_disable() is
* called on child clocks.
*
* XXX @clkdm, @usecount, @children, @sibling should be marked for
* internal use only.
*
* @children and @sibling are used to optimize parent-to-child clock
* tree traversals. (child-to-parent traversals use @parent.)
*
* XXX The notion of the clock's current rate probably needs to be
* separated from the clock's target rate.
*/
struct
clk
{
struct
list_head
node
;
const
struct
clkops
*
ops
;
...
...
@@ -129,8 +232,8 @@ struct clk {
int
(
*
set_rate
)(
struct
clk
*
,
unsigned
long
);
long
(
*
round_rate
)(
struct
clk
*
,
unsigned
long
);
void
(
*
init
)(
struct
clk
*
);
__
u8
enable_bit
;
__
s8
usecount
;
u8
enable_bit
;
s8
usecount
;
u8
fixed_div
;
u8
flags
;
#ifdef CONFIG_ARCH_OMAP2PLUS
...
...
@@ -141,8 +244,8 @@ struct clk {
const
char
*
clkdm_name
;
struct
clockdomain
*
clkdm
;
#else
__
u8
rate_offset
;
__
u8
src_offset
;
u8
rate_offset
;
u8
src_offset
;
#endif
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
struct
dentry
*
dent
;
/* For visible tree hierarchy */
...
...
@@ -188,23 +291,4 @@ extern const struct clkops clkops_null;
extern
struct
clk
dummy_ck
;
/* Clock flags */
#define ENABLE_REG_32BIT (1 << 0)
/* Use 32-bit access */
#define CLOCK_IDLE_CONTROL (1 << 1)
#define CLOCK_NO_IDLE_PARENT (1 << 2)
#define ENABLE_ON_INIT (1 << 3)
/* Enable upon framework init */
#define INVERT_ENABLE (1 << 4)
/* 0 enables, 1 disables */
/* Clksel_rate flags */
#define RATE_IN_242X (1 << 0)
#define RATE_IN_243X (1 << 1)
#define RATE_IN_3XXX (1 << 2)
/* rates common to all OMAP3 */
#define RATE_IN_3430ES2 (1 << 3)
/* 3430ES2 rates only */
#define RATE_IN_36XX (1 << 4)
#define RATE_IN_4430 (1 << 5)
#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)
#define RATE_IN_3430ES2PLUS (RATE_IN_3430ES2 | RATE_IN_36XX)
#endif
arch/arm/plat-omap/include/plat/common.h
View file @
331d919a
...
...
@@ -87,4 +87,8 @@ void omap2_set_globals_uart(struct omap_globals *);
} \
})
extern
struct
device
*
omap2_get_mpuss_device
(
void
);
extern
struct
device
*
omap2_get_dsp_device
(
void
);
extern
struct
device
*
omap2_get_l3_device
(
void
);
#endif
/* __ARCH_ARM_MACH_OMAP_COMMON_H */
arch/arm/plat-omap/include/plat/omap-pm.h
View file @
331d919a
/*
* omap-pm.h - OMAP power management interface
*
* Copyright (C) 2008-20
09
Texas Instruments, Inc.
* Copyright (C) 2008-20
09
Nokia Corporation
* Copyright (C) 2008-20
10
Texas Instruments, Inc.
* Copyright (C) 2008-20
10
Nokia Corporation
* Paul Walmsley
*
* Interface developed by (in alphabetical order): Karthik Dasu, Jouni
...
...
@@ -16,6 +16,7 @@
#include <linux/device.h>
#include <linux/cpufreq.h>
#include <linux/clk.h>
#include "powerdomain.h"
...
...
@@ -89,7 +90,7 @@ void omap_pm_if_exit(void);
* @t: maximum MPU wakeup latency in microseconds
*
* Request that the maximum interrupt latency for the MPU to be no
* greater than
't'
microseconds. "Interrupt latency" in this case is
* greater than
@t
microseconds. "Interrupt latency" in this case is
* defined as the elapsed time from the occurrence of a hardware or
* timer interrupt to the time when the device driver's interrupt
* service routine has been entered by the MPU.
...
...
@@ -105,15 +106,19 @@ void omap_pm_if_exit(void);
* elapsed from when a device driver enables a hardware device with
* clk_enable(), to when the device is ready for register access or
* other use. To control this device wakeup latency, use
* set_max_dev_wakeup_lat()
*
omap_pm_
set_max_dev_wakeup_lat()
*
* Multiple calls to set_max_mpu_wakeup_lat() will replace the
* Multiple calls to
omap_pm_
set_max_mpu_wakeup_lat() will replace the
* previous t value. To remove the latency target for the MPU, call
* with t = -1.
*
* No return value.
* XXX This constraint will be deprecated soon in favor of the more
* general omap_pm_set_max_dev_wakeup_lat()
*
* Returns -EINVAL for an invalid argument, -ERANGE if the constraint
* is not satisfiable, or 0 upon success.
*/
void
omap_pm_set_max_mpu_wakeup_lat
(
struct
device
*
dev
,
long
t
);
int
omap_pm_set_max_mpu_wakeup_lat
(
struct
device
*
dev
,
long
t
);
/**
...
...
@@ -123,8 +128,8 @@ void omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t);
* @r: minimum throughput (in KiB/s)
*
* Request that the minimum data throughput on the OCP interconnect
* attached to device
'dev' interconnect agent 'tbus_id'
be no less
* than
'r'
KiB/s.
* attached to device
@dev interconnect agent @tbus_id
be no less
* than
@r
KiB/s.
*
* It is expected that the OMAP PM or bus code will use this
* information to set the interconnect clock to run at the lowest
...
...
@@ -138,40 +143,44 @@ void omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t);
* code will also need to add an minimum L3 interconnect speed
* constraint,
*
* Multiple calls to
set_min_bus_tput() will replace the previous rat
e
*
value for this device. To remove the interconnect throughpu
t
* restriction for this device, call with r = 0.
* Multiple calls to
omap_pm_set_min_bus_tput() will replace th
e
*
previous rate value for this device. To remove the interconnec
t
*
throughput
restriction for this device, call with r = 0.
*
* No return value.
* Returns -EINVAL for an invalid argument, -ERANGE if the constraint
* is not satisfiable, or 0 upon success.
*/
void
omap_pm_set_min_bus_tput
(
struct
device
*
dev
,
u8
agent_id
,
unsigned
long
r
);
int
omap_pm_set_min_bus_tput
(
struct
device
*
dev
,
u8
agent_id
,
unsigned
long
r
);
/**
* omap_pm_set_max_dev_wakeup_lat - set the maximum device enable latency
* @dev: struct device *
* @req_dev: struct device * requesting the constraint, or NULL if none
* @dev: struct device * to set the constraint one
* @t: maximum device wakeup latency in microseconds
*
* Request that the maximum amount of time necessary for a device
to
*
become accessible after its clocks are enabled should be no greater
*
than 't' microseconds. Specifically, this represents the time from
*
when a device driver enables device clocks with clk_enable(), to
*
when the register reads and writes on the device will succeed.
*
This function should be called before clk_disable() is called,
*
since the power state transition decision may be made during
* clk_disable().
* Request that the maximum amount of time necessary for a device
@dev
*
to become accessible after its clocks are enabled should be no
*
greater than @t microseconds. Specifically, this represents the
*
time from when a device driver enables device clocks with
*
clk_enable(), to when the register reads and writes on the device
*
will succeed. This function should be called before clk_disable()
*
is called, since the power state transition decision may be made
*
during
clk_disable().
*
* It is intended that underlying PM code will use this information to
* determine what power state to put the powerdomain enclosing this
* device into.
*
* Multiple calls to set_max_dev_wakeup_lat() will replace the
* previous wakeup latency values for this device. To remove the
wakeup
* latency restriction for this device, call with t = -1.
* Multiple calls to
omap_pm_
set_max_dev_wakeup_lat() will replace the
* previous wakeup latency values for this device. To remove the
*
wakeup
latency restriction for this device, call with t = -1.
*
* No return value.
* Returns -EINVAL for an invalid argument, -ERANGE if the constraint
* is not satisfiable, or 0 upon success.
*/
void
omap_pm_set_max_dev_wakeup_lat
(
struct
device
*
dev
,
long
t
);
int
omap_pm_set_max_dev_wakeup_lat
(
struct
device
*
req_dev
,
struct
device
*
dev
,
long
t
);
/**
...
...
@@ -198,10 +207,71 @@ void omap_pm_set_max_dev_wakeup_lat(struct device *dev, long t);
* value for this device. To remove the maximum DMA latency for this
* device, call with t = -1.
*
* No return value.
* Returns -EINVAL for an invalid argument, -ERANGE if the constraint
* is not satisfiable, or 0 upon success.
*/
void
omap_pm_set_max_sdma_lat
(
struct
device
*
dev
,
long
t
);
int
omap_pm_set_max_sdma_lat
(
struct
device
*
dev
,
long
t
);
/**
* omap_pm_set_min_clk_rate - set minimum clock rate requested by @dev
* @dev: struct device * requesting the constraint
* @clk: struct clk * to set the minimum rate constraint on
* @r: minimum rate in Hz
*
* Request that the minimum clock rate on the device @dev's clk @clk
* be no less than @r Hz.
*
* It is expected that the OMAP PM code will use this information to
* find an OPP or clock setting that will satisfy this clock rate
* constraint, along with any other applicable system constraints on
* the clock rate or corresponding voltage, etc.
*
* omap_pm_set_min_clk_rate() differs from the clock code's
* clk_set_rate() in that it considers other constraints before taking
* any hardware action, and may change a system OPP rather than just a
* clock rate. clk_set_rate() is intended to be a low-level
* interface.
*
* omap_pm_set_min_clk_rate() is easily open to abuse. A better API
* would be something like "omap_pm_set_min_dev_performance()";
* however, there is no easily-generalizable concept of performance
* that applies to all devices. Only a device (and possibly the
* device subsystem) has both the subsystem-specific knowledge, and
* the hardware IP block-specific knowledge, to translate a constraint
* on "touchscreen sampling accuracy" or "number of pixels or polygons
* rendered per second" to a clock rate. This translation can be
* dependent on the hardware IP block's revision, or firmware version,
* and the driver is the only code on the system that has this
* information and can know how to translate that into a clock rate.
*
* The intended use-case for this function is for userspace or other
* kernel code to communicate a particular performance requirement to
* a subsystem; then for the subsystem to communicate that requirement
* to something that is meaningful to the device driver; then for the
* device driver to convert that requirement to a clock rate, and to
* then call omap_pm_set_min_clk_rate().
*
* Users of this function (such as device drivers) should not simply
* call this function with some high clock rate to ensure "high
* performance." Rather, the device driver should take a performance
* constraint from its subsystem, such as "render at least X polygons
* per second," and use some formula or table to convert that into a
* clock rate constraint given the hardware type and hardware
* revision. Device drivers or subsystems should not assume that they
* know how to make a power/performance tradeoff - some device use
* cases may tolerate a lower-fidelity device function for lower power
* consumption; others may demand a higher-fidelity device function,
* no matter what the power consumption.
*
* Multiple calls to omap_pm_set_min_clk_rate() will replace the
* previous rate value for the device @dev. To remove the minimum clock
* rate constraint for the device, call with r = 0.
*
* Returns -EINVAL for an invalid argument, -ERANGE if the constraint
* is not satisfiable, or 0 upon success.
*/
int
omap_pm_set_min_clk_rate
(
struct
device
*
dev
,
struct
clk
*
c
,
long
r
);
/*
* DSP Bridge-specific constraints
...
...
arch/arm/plat-omap/include/plat/omap_device.h
View file @
331d919a
...
...
@@ -101,6 +101,8 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
int
omap_device_register
(
struct
omap_device
*
od
);
int
omap_early_device_register
(
struct
omap_device
*
od
);
void
__iomem
*
omap_device_get_rt_va
(
struct
omap_device
*
od
);
/* OMAP PM interface */
int
omap_device_align_pm_lat
(
struct
platform_device
*
pdev
,
u32
new_wakeup_lat_limit
);
...
...
arch/arm/plat-omap/include/plat/omap_hwmod.h
View file @
331d919a
/*
* omap_hwmod macros, structures
*
* Copyright (C) 2009 Nokia Corporation
* Copyright (C) 2009
-2010
Nokia Corporation
* Paul Walmsley
*
* Created in collaboration with (alphabetical order): Benoît Cousson,
...
...
@@ -419,7 +419,7 @@ struct omap_hwmod_class {
* @slaves: ptr to array of OCP ifs that this hwmod can respond on
* @dev_attr: arbitrary device attributes that can be passed to the driver
* @_sysc_cache: internal-use hwmod flags
* @_rt_va: cached register target start address (internal use)
* @_
mpu_
rt_va: cached register target start address (internal use)
* @_mpu_port_index: cached MPU register target slave ID (internal use)
* @msuspendmux_reg_id: CONTROL_MSUSPENDMUX register ID (1-6)
* @msuspendmux_shift: CONTROL_MSUSPENDMUX register bit shift
...
...
@@ -460,7 +460,7 @@ struct omap_hwmod {
struct
omap_hwmod_ocp_if
**
slaves
;
/* connect to *_TA */
void
*
dev_attr
;
u32
_sysc_cache
;
void
__iomem
*
_rt_va
;
void
__iomem
*
_
mpu_
rt_va
;
struct
list_head
node
;
u16
flags
;
u8
_mpu_port_index
;
...
...
@@ -482,11 +482,14 @@ int omap_hwmod_init(struct omap_hwmod **ohs);
int
omap_hwmod_register
(
struct
omap_hwmod
*
oh
);
int
omap_hwmod_unregister
(
struct
omap_hwmod
*
oh
);
struct
omap_hwmod
*
omap_hwmod_lookup
(
const
char
*
name
);
int
omap_hwmod_for_each
(
int
(
*
fn
)(
struct
omap_hwmod
*
oh
));
int
omap_hwmod_late_init
(
void
);
int
omap_hwmod_for_each
(
int
(
*
fn
)(
struct
omap_hwmod
*
oh
,
void
*
data
),
void
*
data
);
int
omap_hwmod_late_init
(
u8
skip_setup_idle
);
int
omap_hwmod_enable
(
struct
omap_hwmod
*
oh
);
int
_omap_hwmod_enable
(
struct
omap_hwmod
*
oh
);
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_enable_clocks
(
struct
omap_hwmod
*
oh
);
...
...
@@ -504,6 +507,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh);
int
omap_hwmod_fill_resources
(
struct
omap_hwmod
*
oh
,
struct
resource
*
res
);
struct
powerdomain
*
omap_hwmod_get_pwrdm
(
struct
omap_hwmod
*
oh
);
void
__iomem
*
omap_hwmod_get_mpu_rt_va
(
struct
omap_hwmod
*
oh
);
int
omap_hwmod_add_initiator_dep
(
struct
omap_hwmod
*
oh
,
struct
omap_hwmod
*
init_oh
);
...
...
arch/arm/plat-omap/omap-pm-noop.c
View file @
331d919a
...
...
@@ -34,11 +34,11 @@ struct omap_opp *l3_opps;
* Device-driver-originated constraints (via board-*.c files)
*/
void
omap_pm_set_max_mpu_wakeup_lat
(
struct
device
*
dev
,
long
t
)
int
omap_pm_set_max_mpu_wakeup_lat
(
struct
device
*
dev
,
long
t
)
{
if
(
!
dev
||
t
<
-
1
)
{
WARN
_ON
(
1
);
return
;
WARN
(
1
,
"OMAP PM: %s: invalid parameter(s)"
,
__func__
);
return
-
EINVAL
;
};
if
(
t
==
-
1
)
...
...
@@ -58,14 +58,16 @@ void omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
*
* TI CDP code can call constraint_set here.
*/
return
0
;
}
void
omap_pm_set_min_bus_tput
(
struct
device
*
dev
,
u8
agent_id
,
unsigned
long
r
)
int
omap_pm_set_min_bus_tput
(
struct
device
*
dev
,
u8
agent_id
,
unsigned
long
r
)
{
if
(
!
dev
||
(
agent_id
!=
OCP_INITIATOR_AGENT
&&
agent_id
!=
OCP_TARGET_AGENT
))
{
WARN
_ON
(
1
);
return
;
WARN
(
1
,
"OMAP PM: %s: invalid parameter(s)"
,
__func__
);
return
-
EINVAL
;
};
if
(
r
==
0
)
...
...
@@ -83,13 +85,16 @@ void omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
*
* TI CDP code can call constraint_set here on the VDD2 OPP.
*/
return
0
;
}
void
omap_pm_set_max_dev_wakeup_lat
(
struct
device
*
dev
,
long
t
)
int
omap_pm_set_max_dev_wakeup_lat
(
struct
device
*
req_dev
,
struct
device
*
dev
,
long
t
)
{
if
(
!
dev
||
t
<
-
1
)
{
WARN
_ON
(
1
);
return
;
if
(
!
req_dev
||
!
dev
||
t
<
-
1
)
{
WARN
(
1
,
"OMAP PM: %s: invalid parameter(s)"
,
__func__
);
return
-
EINVAL
;
};
if
(
t
==
-
1
)
...
...
@@ -111,13 +116,15 @@ void omap_pm_set_max_dev_wakeup_lat(struct device *dev, long t)
*
* TI CDP code can call constraint_set here.
*/
return
0
;
}
void
omap_pm_set_max_sdma_lat
(
struct
device
*
dev
,
long
t
)
int
omap_pm_set_max_sdma_lat
(
struct
device
*
dev
,
long
t
)
{
if
(
!
dev
||
t
<
-
1
)
{
WARN
_ON
(
1
);
return
;
WARN
(
1
,
"OMAP PM: %s: invalid parameter(s)"
,
__func__
);
return
-
EINVAL
;
};
if
(
t
==
-
1
)
...
...
@@ -139,8 +146,36 @@ void omap_pm_set_max_sdma_lat(struct device *dev, long t)
* TI CDP code can call constraint_set here.
*/
return
0
;
}
int
omap_pm_set_min_clk_rate
(
struct
device
*
dev
,
struct
clk
*
c
,
long
r
)
{
if
(
!
dev
||
!
c
||
r
<
0
)
{
WARN
(
1
,
"OMAP PM: %s: invalid parameter(s)"
,
__func__
);
return
-
EINVAL
;
}
if
(
r
==
0
)
pr_debug
(
"OMAP PM: remove min clk rate constraint: "
"dev %s
\n
"
,
dev_name
(
dev
));
else
pr_debug
(
"OMAP PM: add min clk rate constraint: "
"dev %s, rate = %ld Hz
\n
"
,
dev_name
(
dev
),
r
);
/*
* Code in a real implementation should keep track of these
* constraints on the clock, and determine the highest minimum
* clock rate. It should iterate over each OPP and determine
* whether the OPP will result in a clock rate that would
* satisfy this constraint (and any other PM constraint in effect
* at that time). Once it finds the lowest-voltage OPP that
* meets those conditions, it should switch to it, or return
* an error if the code is not capable of doing so.
*/
return
0
;
}
/*
* DSP Bridge-specific constraints
...
...
arch/arm/plat-omap/omap_device.c
View file @
331d919a
/*
* omap_device implementation
*
* Copyright (C) 2009 Nokia Corporation
* Copyright (C) 2009
-2010
Nokia Corporation
* Paul Walmsley, Kevin Hilman
*
* Developed in collaboration with (alphabetical order): Benoit
...
...
@@ -90,8 +90,11 @@
#define USE_WAKEUP_LAT 0
#define IGNORE_WAKEUP_LAT 1
#define OMAP_DEVICE_MAGIC 0xf00dcafe
/*
* OMAP_DEVICE_MAGIC: used to determine whether a struct omap_device
* obtained via container_of() is in fact a struct omap_device
*/
#define OMAP_DEVICE_MAGIC 0xf00dcafe
/* Private functions */
...
...
@@ -359,7 +362,7 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
struct
omap_device
*
od
;
char
*
pdev_name2
;
struct
resource
*
res
=
NULL
;
int
res_count
;
int
i
,
res_count
;
struct
omap_hwmod
**
hwmods
;
if
(
!
ohs
||
oh_cnt
==
0
||
!
pdev_name
)
...
...
@@ -416,6 +419,9 @@ 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
++
)
hwmods
[
i
]
->
od
=
od
;
if
(
ret
)
goto
odbs_exit4
;
...
...
@@ -652,6 +658,25 @@ struct powerdomain *omap_device_get_pwrdm(struct omap_device *od)
return
omap_hwmod_get_pwrdm
(
od
->
hwmods
[
0
]);
}
/**
* omap_device_get_mpu_rt_va - return the MPU's virtual addr for the hwmod base
* @od: struct omap_device *
*
* Return the MPU's virtual address for the base of the hwmod, from
* the ioremap() that the hwmod code does. Only valid if there is one
* hwmod associated with this device. Returns NULL if there are zero
* or more than one hwmods associated with this omap_device;
* otherwise, passes along the return value from
* omap_hwmod_get_mpu_rt_va().
*/
void
__iomem
*
omap_device_get_rt_va
(
struct
omap_device
*
od
)
{
if
(
od
->
hwmods_cnt
!=
1
)
return
NULL
;
return
omap_hwmod_get_mpu_rt_va
(
od
->
hwmods
[
0
]);
}
/*
* Public functions intended for use in omap_device_pm_latency
* .activate_func and .deactivate_func function pointers
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment