提交 92105bb7 编写于 作者: T Tony Lindgren 提交者: Russell King

[ARM] 2887/1: OMAP 2/4: Update files common to omap1 and omap2, take 2

Patch from Tony Lindgren

This patch syncs the mainline kernel with linux-omap tree.
The highlights of the patch are:
- Clock updates by Tuukka Tikkanen, Juha Yrjola,
  Daniel Petrini and Tony Lindgren
- DMA fixes by Imre Deak, Juha Yrjola and Daniel Petrini
- Add support to dual-mode hardware timers by Lauri Leukkunen
- GPIO support for 24xx by Paul Mundt
- GPIO wake-up support by Tony Lindgren
- Better GPIO interrupt handler to not lose interrupts by
  Ralph Walden and Ladislav Michl
- Power Management updates by Tuukka Tikkanen
- Make Power Management code use new SRAM functions by
  Tony Lindgren
Signed-off-by: NTony Lindgren <tony@atomide.com>
Signed-off-by: NRussell King <rmk+kernel@arm.linux.org.uk>
上级 7efb833d
......@@ -91,6 +91,13 @@ config OMAP_32K_TIMER_HZ
Kernel internal timer frequency should be a divisor of 32768,
such as 64 or 128.
config OMAP_DM_TIMER
bool "Use dual-mode timer"
default n
depends on ARCH_OMAP16XX
help
Select this option if you want to use OMAP Dual-Mode timers.
choice
prompt "Low-level debug console UART"
depends on ARCH_OMAP
......@@ -107,6 +114,15 @@ config OMAP_LL_DEBUG_UART3
endchoice
config OMAP_SERIAL_WAKE
bool "Enable wake-up events for serial ports"
depends OMAP_MUX
default y
help
Select this option if you want to have your system wake up
to data on the serial RX line. This allows you to wake the
system from serial console.
endmenu
endif
......@@ -3,7 +3,7 @@
#
# Common support
obj-y := common.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o
obj-y := common.o sram.o sram-fn.o clock.o dma.o mux.o gpio.o mcbsp.o usb.o
obj-m :=
obj-n :=
obj- :=
......@@ -15,3 +15,5 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
......@@ -21,6 +21,7 @@
#include <asm/arch/usb.h>
#include "clock.h"
#include "sram.h"
static LIST_HEAD(clocks);
static DECLARE_MUTEX(clocks_sem);
......@@ -141,7 +142,7 @@ static struct clk arm_ck = {
static struct clk armper_ck = {
.name = "armper_ck",
.parent = &ck_dpll1,
.flags = CLOCK_IN_OMAP730 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
RATE_CKCTL,
.enable_reg = ARM_IDLECT2,
.enable_bit = EN_PERCK,
......@@ -385,7 +386,8 @@ static struct clk uart2_ck = {
.name = "uart2_ck",
/* Direct from ULPD, no parent */
.rate = 12000000,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT,
.flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT |
ALWAYS_ENABLED,
.enable_reg = MOD_CONF_CTRL_0,
.enable_bit = 30, /* Chooses between 12MHz and 48MHz */
.set_rate = &set_uart_rate,
......@@ -443,6 +445,15 @@ static struct clk usb_hhc_ck16xx = {
.enable_bit = 8 /* UHOST_EN */,
};
static struct clk usb_dc_ck = {
.name = "usb_dc_ck",
/* Direct from ULPD, no parent */
.rate = 48000000,
.flags = CLOCK_IN_OMAP16XX | RATE_FIXED,
.enable_reg = SOFT_REQ_REG,
.enable_bit = 4,
};
static struct clk mclk_1510 = {
.name = "mclk",
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
......@@ -552,6 +563,7 @@ static struct clk * onchip_clks[] = {
&uart3_16xx,
&usb_clko,
&usb_hhc_ck1510, &usb_hhc_ck16xx,
&usb_dc_ck,
&mclk_1510, &mclk_16xx,
&bclk_1510, &bclk_16xx,
&mmc1_ck,
......@@ -946,14 +958,13 @@ static int select_table_rate(struct clk * clk, unsigned long rate)
if (!ptr->rate)
return -EINVAL;
if (!ptr->rate)
return -EINVAL;
/*
* In most cases we should not need to reprogram DPLL.
* Reprogramming the DPLL is tricky, it must be done from SRAM.
*/
omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
if (unlikely(ck_dpll1.rate == 0)) {
omap_writew(ptr->dpllctl_val, DPLL_CTL);
ck_dpll1.rate = ptr->pll_rate;
}
omap_writew(ptr->ckctl_val, ARM_CKCTL);
ck_dpll1.rate = ptr->pll_rate;
propagate_rate(&ck_dpll1);
return 0;
}
......@@ -1224,9 +1235,11 @@ int __init clk_init(void)
#endif
/* Cache rates for clocks connected to ck_ref (not dpll1) */
propagate_rate(&ck_ref);
printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n",
printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): "
"%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
ck_dpll1.rate, arm_ck.rate);
ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10,
arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10);
#ifdef CONFIG_MACH_OMAP_PERSEUS2
/* Select slicer output as OMAP input clock */
......@@ -1271,7 +1284,9 @@ static int __init omap_late_clk_reset(void)
struct clk *p;
__u32 regval32;
omap_writew(0, SOFT_REQ_REG);
/* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4);
omap_writew(regval32, SOFT_REQ_REG);
omap_writew(0, SOFT_REQ_REG2);
list_for_each_entry(p, &clocks, node) {
......
......@@ -26,6 +26,7 @@
#include <asm/hardware/clock.h>
#include <asm/io.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
#include <asm/arch/board.h>
#include <asm/arch/mux.h>
......@@ -35,11 +36,11 @@
#define NO_LENGTH_CHECK 0xffffffff
extern int omap_bootloader_tag_len;
extern u8 omap_bootloader_tag[];
unsigned char omap_bootloader_tag[512];
int omap_bootloader_tag_len;
struct omap_board_config_kernel *omap_board_config;
int omap_board_config_size = 0;
int omap_board_config_size;
static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
{
......
......@@ -425,7 +425,7 @@ static int dma_handle_ch(int ch)
dma_chan[ch + 6].saved_csr = csr >> 7;
csr &= 0x7f;
}
if (!csr)
if ((csr & 0x3f) == 0)
return 0;
if (unlikely(dma_chan[ch].dev_id == -1)) {
printk(KERN_WARNING "Spurious interrupt from DMA channel %d (CSR %04x)\n",
......@@ -890,11 +890,11 @@ void omap_enable_lcd_dma(void)
w |= 1 << 8;
omap_writew(w, OMAP1610_DMA_LCD_CTRL);
lcd_dma.active = 1;
w = omap_readw(OMAP1610_DMA_LCD_CCR);
w |= 1 << 7;
omap_writew(w, OMAP1610_DMA_LCD_CCR);
lcd_dma.active = 1;
}
void omap_setup_lcd_dma(void)
......@@ -965,8 +965,8 @@ void omap_clear_dma(int lch)
*/
dma_addr_t omap_get_dma_src_pos(int lch)
{
return (dma_addr_t) (OMAP_DMA_CSSA_L(lch) |
(OMAP_DMA_CSSA_U(lch) << 16));
return (dma_addr_t) (omap_readw(OMAP_DMA_CSSA_L(lch)) |
(omap_readw(OMAP_DMA_CSSA_U(lch)) << 16));
}
/*
......@@ -979,8 +979,18 @@ dma_addr_t omap_get_dma_src_pos(int lch)
*/
dma_addr_t omap_get_dma_dst_pos(int lch)
{
return (dma_addr_t) (OMAP_DMA_CDSA_L(lch) |
(OMAP_DMA_CDSA_U(lch) << 16));
return (dma_addr_t) (omap_readw(OMAP_DMA_CDSA_L(lch)) |
(omap_readw(OMAP_DMA_CDSA_U(lch)) << 16));
}
/*
* Returns current source transfer counting for the given DMA channel.
* Can be used to monitor the progress of a transfer inside a block.
* It must be called with disabled interrupts.
*/
int omap_get_dma_src_addr_counter(int lch)
{
return (dma_addr_t) omap_readw(OMAP_DMA_CSAC(lch));
}
int omap_dma_running(void)
......@@ -1076,6 +1086,7 @@ arch_initcall(omap_init_dma);
EXPORT_SYMBOL(omap_get_dma_src_pos);
EXPORT_SYMBOL(omap_get_dma_dst_pos);
EXPORT_SYMBOL(omap_get_dma_src_addr_counter);
EXPORT_SYMBOL(omap_clear_dma);
EXPORT_SYMBOL(omap_set_dma_priority);
EXPORT_SYMBOL(omap_request_dma);
......
/*
* linux/arch/arm/plat-omap/dmtimer.c
*
* OMAP Dual-Mode Timers
*
* Copyright (C) 2005 Nokia Corporation
* Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <asm/arch/hardware.h>
#include <asm/arch/dmtimer.h>
#include <asm/io.h>
#include <asm/arch/irqs.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#define OMAP_TIMER_COUNT 8
#define OMAP_TIMER_ID_REG 0x00
#define OMAP_TIMER_OCP_CFG_REG 0x10
#define OMAP_TIMER_SYS_STAT_REG 0x14
#define OMAP_TIMER_STAT_REG 0x18
#define OMAP_TIMER_INT_EN_REG 0x1c
#define OMAP_TIMER_WAKEUP_EN_REG 0x20
#define OMAP_TIMER_CTRL_REG 0x24
#define OMAP_TIMER_COUNTER_REG 0x28
#define OMAP_TIMER_LOAD_REG 0x2c
#define OMAP_TIMER_TRIGGER_REG 0x30
#define OMAP_TIMER_WRITE_PEND_REG 0x34
#define OMAP_TIMER_MATCH_REG 0x38
#define OMAP_TIMER_CAPTURE_REG 0x3c
#define OMAP_TIMER_IF_CTRL_REG 0x40
static struct dmtimer_info_struct {
struct list_head unused_timers;
struct list_head reserved_timers;
} dm_timer_info;
static struct omap_dm_timer dm_timers[] = {
{ .base=0xfffb1400, .irq=INT_1610_GPTIMER1 },
{ .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 },
{ .base=0xfffb2400, .irq=INT_1610_GPTIMER3 },
{ .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 },
{ .base=0xfffb3400, .irq=INT_1610_GPTIMER5 },
{ .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 },
{ .base=0xfffb4400, .irq=INT_1610_GPTIMER7 },
{ .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 },
{ .base=0x0 },
};
static spinlock_t dm_timer_lock;
inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
{
omap_writel(value, timer->base + reg);
while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
;
}
u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
{
return omap_readl(timer->base + reg);
}
int omap_dm_timers_active(void)
{
struct omap_dm_timer *timer;
for (timer = &dm_timers[0]; timer->base; ++timer)
if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
OMAP_TIMER_CTRL_ST)
return 1;
return 0;
}
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
{
int n = (timer - dm_timers) << 1;
u32 l;
l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
l |= source << n;
omap_writel(l, MOD_CONF_CTRL_1);
}
static void omap_dm_timer_reset(struct omap_dm_timer *timer)
{
/* Reset and set posted mode */
omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02);
omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
}
struct omap_dm_timer * omap_dm_timer_request(void)
{
struct omap_dm_timer *timer = NULL;
unsigned long flags;
spin_lock_irqsave(&dm_timer_lock, flags);
if (!list_empty(&dm_timer_info.unused_timers)) {
timer = (struct omap_dm_timer *)
dm_timer_info.unused_timers.next;
list_move_tail((struct list_head *)timer,
&dm_timer_info.reserved_timers);
}
spin_unlock_irqrestore(&dm_timer_lock, flags);
return timer;
}
void omap_dm_timer_free(struct omap_dm_timer *timer)
{
unsigned long flags;
omap_dm_timer_reset(timer);
spin_lock_irqsave(&dm_timer_lock, flags);
list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
spin_unlock_irqrestore(&dm_timer_lock, flags);
}
void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
unsigned int value)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
}
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
{
return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
}
void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
}
void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer)
{
u32 l;
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l |= OMAP_TIMER_CTRL_AR;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
void omap_dm_timer_trigger(struct omap_dm_timer *timer)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1);
}
void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value)
{
u32 l;
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l |= value & 0x3;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
void omap_dm_timer_start(struct omap_dm_timer *timer)
{
u32 l;
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l |= OMAP_TIMER_CTRL_ST;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
void omap_dm_timer_stop(struct omap_dm_timer *timer)
{
u32 l;
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l &= ~0x1;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
{
return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
}
void omap_dm_timer_reset_counter(struct omap_dm_timer *timer)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0);
}
void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
}
void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
}
void omap_dm_timer_enable_compare(struct omap_dm_timer *timer)
{
u32 l;
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l |= OMAP_TIMER_CTRL_CE;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
static inline void __dm_timer_init(void)
{
struct omap_dm_timer *timer;
spin_lock_init(&dm_timer_lock);
INIT_LIST_HEAD(&dm_timer_info.unused_timers);
INIT_LIST_HEAD(&dm_timer_info.reserved_timers);
timer = &dm_timers[0];
while (timer->base) {
list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
omap_dm_timer_reset(timer);
timer++;
}
}
static int __init omap_dm_timer_init(void)
{
if (cpu_is_omap16xx())
__dm_timer_init();
return 0;
}
arch_initcall(omap_dm_timer_init);
此差异已折叠。
......@@ -27,6 +27,7 @@
#include <asm/arch/dma.h>
#include <asm/arch/mux.h>
#include <asm/arch/irqs.h>
#include <asm/arch/dsp_common.h>
#include <asm/arch/mcbsp.h>
#include <asm/hardware/clock.h>
......@@ -187,9 +188,6 @@ static int omap_mcbsp_check(unsigned int id)
return -1;
}
#define EN_XORPCK 1
#define DSP_RSTCT2 0xe1008014
static void omap_mcbsp_dsp_request(void)
{
if (cpu_is_omap1510() || cpu_is_omap16xx()) {
......@@ -198,6 +196,11 @@ static void omap_mcbsp_dsp_request(void)
/* enable 12MHz clock to mcbsp 1 & 3 */
clk_use(mcbsp_dspxor_ck);
/*
* DSP external peripheral reset
* FIXME: This should be moved to dsp code
*/
__raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
DSP_RSTCT2);
}
......
......@@ -48,6 +48,9 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
pull_orig = 0, pull = 0;
unsigned int mask, warn = 0;
if (cpu_is_omap7xx())
return 0;
if (reg_cfg > ARRAY_SIZE(reg_cfg_table)) {
printk(KERN_ERR "MUX: reg_cfg %d\n", reg_cfg);
return -EINVAL;
......
......@@ -25,6 +25,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
......
......@@ -39,24 +39,32 @@
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/pm.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach/time.h>
#include <asm/mach-types.h>
#include <asm/mach/irq.h>
#include <asm/arch/omap16xx.h>
#include <asm/mach-types.h>
#include <asm/arch/irqs.h>
#include <asm/arch/tc.h>
#include <asm/arch/pm.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
#include <asm/arch/tps65010.h>
#include <asm/arch/dsp_common.h>
#include "clock.h"
#include "sram.h"
static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
static void (*omap_sram_idle)(void) = NULL;
static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
/*
* Let's power down on idle, but only if we are really
* idle, because once we start down the path of
......@@ -65,7 +73,6 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
*/
void omap_pm_idle(void)
{
int (*func_ptr)(void) = 0;
unsigned int mask32 = 0;
/*
......@@ -83,6 +90,13 @@ void omap_pm_idle(void)
}
mask32 = omap_readl(ARM_SYSST);
/*
* Prevent the ULPD from entering low power state by setting
* POWER_CTRL_REG:4 = 0
*/
omap_writew(omap_readw(ULPD_POWER_CTRL) &
~ULPD_DEEP_SLEEP_TRANSITION_EN, ULPD_POWER_CTRL);
/*
* Since an interrupt may set up a timer, we don't want to
* reprogram the hardware timer with interrupts enabled.
......@@ -92,18 +106,9 @@ void omap_pm_idle(void)
if ((mask32 & DSP_IDLE) == 0) {
__asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
} else {
if (cpu_is_omap1510()) {
func_ptr = (void *)(OMAP1510_SRAM_IDLE_SUSPEND);
} else if (cpu_is_omap1610() || cpu_is_omap1710()) {
func_ptr = (void *)(OMAP1610_SRAM_IDLE_SUSPEND);
} else if (cpu_is_omap5912()) {
func_ptr = (void *)(OMAP5912_SRAM_IDLE_SUSPEND);
}
} else
omap_sram_idle();
func_ptr();
}
local_fiq_enable();
local_irq_enable();
}
......@@ -115,58 +120,55 @@ void omap_pm_idle(void)
*/
static void omap_pm_wakeup_setup(void)
{
/*
* Enable ARM XOR clock and release peripheral from reset by
* writing 1 to PER_EN bit in ARM_RSTCT2, this is required
* for UART configuration to use UART2 to wake up.
*/
omap_writel(omap_readl(ARM_IDLECT2) | ENABLE_XORCLK, ARM_IDLECT2);
omap_writel(omap_readl(ARM_RSTCT2) | PER_EN, ARM_RSTCT2);
omap_writew(MODEM_32K_EN, ULPD_CLOCK_CTRL);
u32 level1_wake = OMAP_IRQ_BIT(INT_IH2_IRQ);
u32 level2_wake = OMAP_IRQ_BIT(INT_UART2) | OMAP_IRQ_BIT(INT_KEYBOARD);
/*
* Turn off all interrupts except L1-2nd level cascade,
* and the L2 wakeup interrupts: keypad and UART2.
* Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
* and the L2 wakeup interrupts: keypad and UART2. Note that the
* drivers must still separately call omap_set_gpio_wakeup() to
* wake up to a GPIO interrupt.
*/
if (cpu_is_omap1510() || cpu_is_omap16xx())
level1_wake |= OMAP_IRQ_BIT(INT_GPIO_BANK1);
else if (cpu_is_omap730())
level1_wake |= OMAP_IRQ_BIT(INT_730_GPIO_BANK1);
omap_writel(~IRQ_LEVEL2, OMAP_IH1_MIR);
omap_writel(~level1_wake, OMAP_IH1_MIR);
if (cpu_is_omap1510()) {
omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_MIR);
}
if (cpu_is_omap1510())
omap_writel(~level2_wake, OMAP_IH2_MIR);
/* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
if (cpu_is_omap16xx()) {
omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_0_MIR);
omap_writel(~0x0, OMAP_IH2_1_MIR);
omap_writel(~level2_wake, OMAP_IH2_0_MIR);
omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR);
omap_writel(~0x0, OMAP_IH2_2_MIR);
omap_writel(~0x0, OMAP_IH2_3_MIR);
}
/* New IRQ agreement */
/* New IRQ agreement, recalculate in cascade order */
omap_writel(1, OMAP_IH2_CONTROL);
omap_writel(1, OMAP_IH1_CONTROL);
/* external PULL to down, bit 22 = 0 */
omap_writel(omap_readl(PULL_DWN_CTRL_2) & ~(1<<22), PULL_DWN_CTRL_2);
}
void omap_pm_suspend(void)
{
unsigned int mask32 = 0;
unsigned long arg0 = 0, arg1 = 0;
int (*func_ptr)(unsigned short, unsigned short) = 0;
unsigned short save_dsp_idlect2;
printk("PM: OMAP%x is entering deep sleep now ...\n", system_rev);
printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
omap_serial_wake_trigger(1);
if (machine_is_omap_osk()) {
/* Stop LED1 (D9) blink */
tps65010_set_led(LED1, OFF);
}
omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
/*
* Step 1: turn off interrupts
* Step 1: turn off interrupts (FIXME: NOTE: already disabled)
*/
local_irq_disable();
......@@ -207,6 +209,8 @@ void omap_pm_suspend(void)
ARM_SAVE(ARM_CKCTL);
ARM_SAVE(ARM_IDLECT1);
ARM_SAVE(ARM_IDLECT2);
if (!(cpu_is_omap1510()))
ARM_SAVE(ARM_IDLECT3);
ARM_SAVE(ARM_EWUPCT);
ARM_SAVE(ARM_RSTCT1);
ARM_SAVE(ARM_RSTCT2);
......@@ -214,42 +218,12 @@ void omap_pm_suspend(void)
ULPD_SAVE(ULPD_CLOCK_CTRL);
ULPD_SAVE(ULPD_STATUS_REQ);
/*
* Step 3: LOW_PWR signal enabling
*
* Allow the LOW_PWR signal to be visible on MPUIO5 ball.
*/
if (cpu_is_omap1510()) {
/* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
omap_writew(omap_readw(ULPD_POWER_CTRL) |
OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
} else if (cpu_is_omap16xx()) {
/* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
omap_writew(omap_readw(ULPD_POWER_CTRL) |
OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
}
/* configure LOW_PWR pin */
omap_cfg_reg(T20_1610_LOW_PWR);
/* (Step 3 removed - we now allow deep sleep by default) */
/*
* Step 4: OMAP DSP Shutdown
*/
/* Set DSP_RST = 1 and DSP_EN = 0, put DSP block into reset */
omap_writel((omap_readl(ARM_RSTCT1) | DSP_RST) & ~DSP_ENABLE,
ARM_RSTCT1);
/* Set DSP boot mode to DSP-IDLE, DSP_BOOT_MODE = 0x2 */
omap_writel(DSP_IDLE_MODE, MPUI_DSP_BOOT_CONFIG);
/* Set EN_DSPCK = 0, stop DSP block clock */
omap_writel(omap_readl(ARM_CKCTL) & ~DSP_CLOCK_ENABLE, ARM_CKCTL);
/* Stop any DSP domain clocks */
omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
save_dsp_idlect2 = __raw_readw(DSP_IDLECT2);
__raw_writew(0, DSP_IDLECT2);
/*
* Step 5: Wakeup Event Setup
......@@ -258,24 +232,9 @@ void omap_pm_suspend(void)
omap_pm_wakeup_setup();
/*
* Step 6a: ARM and Traffic controller shutdown
*
* Step 6 starts here with clock and watchdog disable
* Step 6: ARM and Traffic controller shutdown
*/
/* stop clocks */
mask32 = omap_readl(ARM_IDLECT2);
mask32 &= ~(1<<EN_WDTCK); /* bit 0 -> 0 (WDT clock) */
mask32 |= (1<<EN_XORPCK); /* bit 1 -> 1 (XORPCK clock) */
mask32 &= ~(1<<EN_PERCK); /* bit 2 -> 0 (MPUPER_CK clock) */
mask32 &= ~(1<<EN_LCDCK); /* bit 3 -> 0 (LCDC clock) */
mask32 &= ~(1<<EN_LBCK); /* bit 4 -> 0 (local bus clock) */
mask32 |= (1<<EN_APICK); /* bit 6 -> 1 (MPUI clock) */
mask32 &= ~(1<<EN_TIMCK); /* bit 7 -> 0 (MPU timer clock) */
mask32 &= ~(1<<DMACK_REQ); /* bit 8 -> 0 (DMAC clock) */
mask32 &= ~(1<<EN_GPIOCK); /* bit 9 -> 0 (GPIO clock) */
omap_writel(mask32, ARM_IDLECT2);
/* disable ARM watchdog */
omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
......@@ -295,47 +254,24 @@ void omap_pm_suspend(void)
arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
if (cpu_is_omap1510()) {
func_ptr = (void *)(OMAP1510_SRAM_API_SUSPEND);
} else if (cpu_is_omap1610() || cpu_is_omap1710()) {
func_ptr = (void *)(OMAP1610_SRAM_API_SUSPEND);
} else if (cpu_is_omap5912()) {
func_ptr = (void *)(OMAP5912_SRAM_API_SUSPEND);
}
/*
* Step 6c: ARM and Traffic controller shutdown
*
* Jump to assembly code. The processor will stay there
* until wake up.
*/
func_ptr(arg0, arg1);
omap_sram_suspend(arg0, arg1);
/*
* If we are here, processor is woken up!
*/
if (cpu_is_omap1510()) {
/* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
omap_writew(omap_readw(ULPD_POWER_CTRL) &
~OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
} else if (cpu_is_omap16xx()) {
/* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
omap_writew(omap_readw(ULPD_POWER_CTRL) &
~OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
}
/* Restore DSP clocks */
omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
__raw_writew(save_dsp_idlect2, DSP_IDLECT2);
ARM_RESTORE(ARM_IDLECT2);
/*
* Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
*/
if (!(cpu_is_omap1510()))
ARM_RESTORE(ARM_IDLECT3);
ARM_RESTORE(ARM_CKCTL);
ARM_RESTORE(ARM_EWUPCT);
ARM_RESTORE(ARM_RSTCT1);
......@@ -366,6 +302,8 @@ void omap_pm_suspend(void)
MPUI1610_RESTORE(OMAP_IH2_3_MIR);
}
omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
/*
* Reenable interrupts
*/
......@@ -373,6 +311,8 @@ void omap_pm_suspend(void)
local_irq_enable();
local_fiq_enable();
omap_serial_wake_trigger(0);
printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
if (machine_is_omap_osk()) {
......@@ -401,6 +341,8 @@ static int omap_pm_read_proc(
ARM_SAVE(ARM_CKCTL);
ARM_SAVE(ARM_IDLECT1);
ARM_SAVE(ARM_IDLECT2);
if (!(cpu_is_omap1510()))
ARM_SAVE(ARM_IDLECT3);
ARM_SAVE(ARM_EWUPCT);
ARM_SAVE(ARM_RSTCT1);
ARM_SAVE(ARM_RSTCT2);
......@@ -436,6 +378,7 @@ static int omap_pm_read_proc(
"ARM_CKCTL_REG: 0x%-8x \n"
"ARM_IDLECT1_REG: 0x%-8x \n"
"ARM_IDLECT2_REG: 0x%-8x \n"
"ARM_IDLECT3_REG: 0x%-8x \n"
"ARM_EWUPCT_REG: 0x%-8x \n"
"ARM_RSTCT1_REG: 0x%-8x \n"
"ARM_RSTCT2_REG: 0x%-8x \n"
......@@ -449,6 +392,7 @@ static int omap_pm_read_proc(
ARM_SHOW(ARM_CKCTL),
ARM_SHOW(ARM_IDLECT1),
ARM_SHOW(ARM_IDLECT2),
ARM_SHOW(ARM_IDLECT3),
ARM_SHOW(ARM_EWUPCT),
ARM_SHOW(ARM_RSTCT1),
ARM_SHOW(ARM_RSTCT2),
......@@ -507,7 +451,7 @@ static void omap_pm_init_proc(void)
entry = create_proc_read_entry("driver/omap_pm",
S_IWUSR | S_IRUGO, NULL,
omap_pm_read_proc, 0);
omap_pm_read_proc, NULL);
}
#endif /* DEBUG && CONFIG_PROC_FS */
......@@ -580,7 +524,21 @@ static int omap_pm_finish(suspend_state_t state)
}
struct pm_ops omap_pm_ops ={
static irqreturn_t omap_wakeup_interrupt(int irq, void * dev,
struct pt_regs * regs)
{
return IRQ_HANDLED;
}
static struct irqaction omap_wakeup_irq = {
.name = "peripheral wakeup",
.flags = SA_INTERRUPT,
.handler = omap_wakeup_interrupt
};
static struct pm_ops omap_pm_ops ={
.pm_disk_mode = 0,
.prepare = omap_pm_prepare,
.enter = omap_pm_enter,
......@@ -590,42 +548,61 @@ struct pm_ops omap_pm_ops ={
static int __init omap_pm_init(void)
{
printk("Power Management for TI OMAP.\n");
pm_idle = omap_pm_idle;
/*
* We copy the assembler sleep/wakeup routines to SRAM.
* These routines need to be in SRAM as that's the only
* memory the MPU can see when it wakes up.
*/
#ifdef CONFIG_ARCH_OMAP1510
if (cpu_is_omap1510()) {
memcpy((void *)OMAP1510_SRAM_IDLE_SUSPEND,
omap1510_idle_loop_suspend,
omap1510_idle_loop_suspend_sz);
memcpy((void *)OMAP1510_SRAM_API_SUSPEND, omap1510_cpu_suspend,
omap1510_cpu_suspend_sz);
} else
#endif
if (cpu_is_omap1610() || cpu_is_omap1710()) {
memcpy((void *)OMAP1610_SRAM_IDLE_SUSPEND,
omap1610_idle_loop_suspend,
omap1610_idle_loop_suspend_sz);
memcpy((void *)OMAP1610_SRAM_API_SUSPEND, omap1610_cpu_suspend,
omap1610_cpu_suspend_sz);
} else if (cpu_is_omap5912()) {
memcpy((void *)OMAP5912_SRAM_IDLE_SUSPEND,
omap1610_idle_loop_suspend,
omap1610_idle_loop_suspend_sz);
memcpy((void *)OMAP5912_SRAM_API_SUSPEND, omap1610_cpu_suspend,
omap1610_cpu_suspend_sz);
omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
omap1510_idle_loop_suspend_sz);
omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
omap1510_cpu_suspend_sz);
} else if (cpu_is_omap16xx()) {
omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend,
omap1610_idle_loop_suspend_sz);
omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
omap1610_cpu_suspend_sz);
}
if (omap_sram_idle == NULL || omap_sram_suspend == NULL) {
printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
return -ENODEV;
}
pm_idle = omap_pm_idle;
setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
#if 0
/* --- BEGIN BOARD-DEPENDENT CODE --- */
/* Sleepx mask direction */
omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008);
/* Unmask sleepx signal */
omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
/* --- END BOARD-DEPENDENT CODE --- */
#endif
/* Program new power ramp-up time
* (0 for most boards since we don't lower voltage when in deep sleep)
*/
omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
/* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
/* Configure IDLECT3 */
if (cpu_is_omap16xx())
omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
pm_set_ops(&omap_pm_ops);
#if defined(DEBUG) && defined(CONFIG_PROC_FS)
omap_pm_init_proc();
#endif
/* configure LOW_PWR pin */
omap_cfg_reg(T20_1610_LOW_PWR);
return 0;
}
__initcall(omap_pm_init);
......
......@@ -66,7 +66,7 @@ ENTRY(omap1510_idle_loop_suspend)
@ get ARM_IDLECT2 into r2
ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
orr r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ request ARM idle
......@@ -76,7 +76,7 @@ ENTRY(omap1510_idle_loop_suspend)
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
mov r5, #IDLE_WAIT_CYCLES & 0xff
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
l_1510: subs r5, r5, #1
bne l_1510
/*
......@@ -96,7 +96,7 @@ l_1510: subs r5, r5, #1
strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
ldmfd sp!, {r0 - r12, pc} @ restore regs and return
ldmfd sp!, {r0 - r12, pc} @ restore regs and return
ENTRY(omap1510_idle_loop_suspend_sz)
.word . - omap1510_idle_loop_suspend
......@@ -115,8 +115,8 @@ ENTRY(omap1610_idle_loop_suspend)
@ turn off clock domains
@ get ARM_IDLECT2 into r2
ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
mov r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
orr r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ request ARM idle
......@@ -126,7 +126,7 @@ ENTRY(omap1610_idle_loop_suspend)
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
mov r5, #IDLE_WAIT_CYCLES & 0xff
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
l_1610: subs r5, r5, #1
bne l_1610
/*
......@@ -146,7 +146,7 @@ l_1610: subs r5, r5, #1
strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
ldmfd sp!, {r0 - r12, pc} @ restore regs and return
ldmfd sp!, {r0 - r12, pc} @ restore regs and return
ENTRY(omap1610_idle_loop_suspend_sz)
.word . - omap1610_idle_loop_suspend
......@@ -208,7 +208,7 @@ ENTRY(omap1510_cpu_suspend)
@ turn off clock domains
mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
orr r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ request ARM idle
......@@ -217,7 +217,7 @@ ENTRY(omap1510_cpu_suspend)
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
mov r5, #IDLE_WAIT_CYCLES & 0xff
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
l_1510_2:
subs r5, r5, #1
bne l_1510_2
......@@ -237,7 +237,7 @@ l_1510_2:
strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
@ restore regs and return
ldmfd sp!, {r0 - r12, pc}
ldmfd sp!, {r0 - r12, pc}
ENTRY(omap1510_cpu_suspend_sz)
.word . - omap1510_cpu_suspend
......@@ -249,21 +249,26 @@ ENTRY(omap1610_cpu_suspend)
@ save registers on stack
stmfd sp!, {r0 - r12, lr}
@ Drain write cache
mov r4, #0
mcr p15, 0, r0, c7, c10, 4
nop
@ load base address of Traffic Controller
mov r4, #TCMIF_ASM_BASE & 0xff000000
orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
mov r6, #TCMIF_ASM_BASE & 0xff000000
orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
@ prepare to put SDRAM into self-refresh manually
ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
orr r5, r5, #SELF_REFRESH_MODE & 0xff000000
orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff
str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
@ prepare to put EMIFS to Sleep
ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff
str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
@ load base address of ARM_IDLECT1 and ARM_IDLECT2
mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
......@@ -271,26 +276,22 @@ ENTRY(omap1610_cpu_suspend)
orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
@ turn off clock domains
mov r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
orr r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ work around errata of OMAP1610/5912. Enable (!) peripheral
@ clock to let the chip go into deep sleep
ldrh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
orr r5,r5, #EN_PERCK_BIT & 0xff
@ do not disable PERCK (0x04)
mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ request ARM idle
mov r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff
orr r3, r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff00
mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
mov r5, #IDLE_WAIT_CYCLES & 0xff
orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
l_1610_2:
subs r5, r5, #1
bne l_1610_2
@ disable instruction cache
mrc p15, 0, r9, c1, c0, 0
bic r2, r9, #0x1000
mcr p15, 0, r2, c1, c0, 0
nop
/*
* Let's wait for the next wake up event to wake us up. r0 can't be
* used here because r0 holds ARM_IDLECT1
......@@ -301,13 +302,21 @@ l_1610_2:
* omap1610_cpu_suspend()'s resume point.
*
* It will just start executing here, so we'll restore stuff from the
* stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
* stack.
*/
@ re-enable Icache
mcr p15, 0, r9, c1, c0, 0
@ reset the ARM_IDLECT1 and ARM_IDLECT2.
strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
@ Restore EMIFF controls
str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
@ restore regs and return
ldmfd sp!, {r0 - r12, pc}
ldmfd sp!, {r0 - r12, pc}
ENTRY(omap1610_cpu_suspend_sz)
.word . - omap1610_cpu_suspend
......
/*
* linux/arch/arm/plat-omap/sram.S
*
* Functions that need to be run in internal SRAM
*
* 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/config.h>
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/arch/io.h>
#include <asm/arch/hardware.h>
.text
/*
* Reprograms ULPD and CKCTL.
*/
ENTRY(sram_reprogram_clock)
stmfd sp!, {r0 - r12, lr} @ save registers on stack
mov r2, #IO_ADDRESS(DPLL_CTL) & 0xff000000
orr r2, r2, #IO_ADDRESS(DPLL_CTL) & 0x00ff0000
orr r2, r2, #IO_ADDRESS(DPLL_CTL) & 0x0000ff00
mov r3, #IO_ADDRESS(ARM_CKCTL) & 0xff000000
orr r3, r3, #IO_ADDRESS(ARM_CKCTL) & 0x00ff0000
orr r3, r3, #IO_ADDRESS(ARM_CKCTL) & 0x0000ff00
tst r0, #1 << 4 @ want lock mode?
beq newck @ nope
bic r0, r0, #1 << 4 @ else clear lock bit
strh r0, [r2] @ set dpll into bypass mode
orr r0, r0, #1 << 4 @ set lock bit again
newck:
strh r1, [r3] @ write new ckctl value
strh r0, [r2] @ write new dpll value
mov r4, #0x0700 @ let the clocks settle
orr r4, r4, #0x00ff
delay: sub r4, r4, #1
cmp r4, #0
bne delay
lock: ldrh r4, [r2], #0 @ read back dpll value
tst r0, #1 << 4 @ want lock mode?
beq out @ nope
tst r4, #1 << 0 @ dpll rate locked?
beq lock @ try again
out:
ldmfd sp!, {r0 - r12, pc} @ restore regs and return
ENTRY(sram_reprogram_clock_sz)
.word . - sram_reprogram_clock
/*
* linux/arch/arm/plat-omap/sram.c
*
* OMAP SRAM detection and management
*
* Copyright (C) 2005 Nokia Corporation
* Written by Tony Lindgren <tony@atomide.com>
*
* 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/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/mach/map.h>
#include <asm/io.h>
#include <asm/cacheflush.h>
#include "sram.h"
#define OMAP1_SRAM_BASE 0xd0000000
#define OMAP1_SRAM_START 0x20000000
#define SRAM_BOOTLOADER_SZ 0x80
static unsigned long omap_sram_base;
static unsigned long omap_sram_size;
static unsigned long omap_sram_ceil;
/*
* The amount of SRAM depends on the core type:
* 730 = 200K, 1510 = 512K, 5912 = 256K, 1610 = 16K, 1710 = 16K
* Note that we cannot try to test for SRAM here because writes
* to secure SRAM will hang the system. Also the SRAM is not
* yet mapped at this point.
*/
void __init omap_detect_sram(void)
{
omap_sram_base = OMAP1_SRAM_BASE;
if (cpu_is_omap730())
omap_sram_size = 0x32000;
else if (cpu_is_omap1510())
omap_sram_size = 0x80000;
else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710())
omap_sram_size = 0x4000;
else if (cpu_is_omap1611())
omap_sram_size = 0x3e800;
else {
printk(KERN_ERR "Could not detect SRAM size\n");
omap_sram_size = 0x4000;
}
printk(KERN_INFO "SRAM size: 0x%lx\n", omap_sram_size);
omap_sram_ceil = omap_sram_base + omap_sram_size;
}
static struct map_desc omap_sram_io_desc[] __initdata = {
{ OMAP1_SRAM_BASE, OMAP1_SRAM_START, 0, MT_DEVICE }
};
/*
* In order to use last 2kB of SRAM on 1611b, we must round the size
* up to multiple of PAGE_SIZE. We cannot use ioremap for SRAM, as
* clock init needs SRAM early.
*/
void __init omap_map_sram(void)
{
if (omap_sram_size == 0)
return;
omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE;
omap_sram_io_desc[0].length *= PAGE_SIZE;
iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc));
/*
* Looks like we need to preserve some bootloader code at the
* beginning of SRAM for jumping to flash for reboot to work...
*/
memset((void *)omap_sram_base + SRAM_BOOTLOADER_SZ, 0,
omap_sram_size - SRAM_BOOTLOADER_SZ);
}
static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl) = NULL;
void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl)
{
if (_omap_sram_reprogram_clock == NULL)
panic("Cannot use SRAM");
return _omap_sram_reprogram_clock(dpllctl, ckctl);
}
void * omap_sram_push(void * start, unsigned long size)
{
if (size > (omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ))) {
printk(KERN_ERR "Not enough space in SRAM\n");
return NULL;
}
omap_sram_ceil -= size;
omap_sram_ceil &= ~0x3;
memcpy((void *)omap_sram_ceil, start, size);
return (void *)omap_sram_ceil;
}
void __init omap_sram_init(void)
{
omap_detect_sram();
omap_map_sram();
_omap_sram_reprogram_clock = omap_sram_push(sram_reprogram_clock,
sram_reprogram_clock_sz);
}
/*
* linux/arch/arm/plat-omap/sram.h
*
* Interface for functions that need to be run in internal SRAM
*
* 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.
*/
#ifndef __ARCH_ARM_OMAP_SRAM_H
#define __ARCH_ARM_OMAP_SRAM_H
extern void * omap_sram_push(void * start, unsigned long size);
extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
/* Do not use these */
extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
extern unsigned long sram_reprogram_clock_sz;
#endif
......@@ -41,6 +41,7 @@
/* These routines should handle the standard chip-specific modes
* for usb0/1/2 ports, covering basic mux and transceiver setup.
* Call omap_usb_init() once, from INIT_MACHINE().
*
* Some board-*.c files will need to set up additional mux options,
* like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册