mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
[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: Tony Lindgren <tony@atomide.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
7efb833d64
commit
92105bb706
16 changed files with 1113 additions and 305 deletions
|
@ -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);
|
||||
|
|
260
arch/arm/plat-omap/dmtimer.c
Normal file
260
arch/arm/plat-omap/dmtimer.c
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* 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);
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Support functions for OMAP GPIO
|
||||
*
|
||||
* Copyright (C) 2003 Nokia Corporation
|
||||
* Copyright (C) 2003-2005 Nokia Corporation
|
||||
* Written by Juha Yrjölä <juha.yrjola@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -17,8 +17,11 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/hardware/clock.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/arch/irqs.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
|
@ -29,7 +32,7 @@
|
|||
/*
|
||||
* OMAP1510 GPIO registers
|
||||
*/
|
||||
#define OMAP1510_GPIO_BASE 0xfffce000
|
||||
#define OMAP1510_GPIO_BASE (void __iomem *)0xfffce000
|
||||
#define OMAP1510_GPIO_DATA_INPUT 0x00
|
||||
#define OMAP1510_GPIO_DATA_OUTPUT 0x04
|
||||
#define OMAP1510_GPIO_DIR_CONTROL 0x08
|
||||
|
@ -43,34 +46,37 @@
|
|||
/*
|
||||
* OMAP1610 specific GPIO registers
|
||||
*/
|
||||
#define OMAP1610_GPIO1_BASE 0xfffbe400
|
||||
#define OMAP1610_GPIO2_BASE 0xfffbec00
|
||||
#define OMAP1610_GPIO3_BASE 0xfffbb400
|
||||
#define OMAP1610_GPIO4_BASE 0xfffbbc00
|
||||
#define OMAP1610_GPIO1_BASE (void __iomem *)0xfffbe400
|
||||
#define OMAP1610_GPIO2_BASE (void __iomem *)0xfffbec00
|
||||
#define OMAP1610_GPIO3_BASE (void __iomem *)0xfffbb400
|
||||
#define OMAP1610_GPIO4_BASE (void __iomem *)0xfffbbc00
|
||||
#define OMAP1610_GPIO_REVISION 0x0000
|
||||
#define OMAP1610_GPIO_SYSCONFIG 0x0010
|
||||
#define OMAP1610_GPIO_SYSSTATUS 0x0014
|
||||
#define OMAP1610_GPIO_IRQSTATUS1 0x0018
|
||||
#define OMAP1610_GPIO_IRQENABLE1 0x001c
|
||||
#define OMAP1610_GPIO_WAKEUPENABLE 0x0028
|
||||
#define OMAP1610_GPIO_DATAIN 0x002c
|
||||
#define OMAP1610_GPIO_DATAOUT 0x0030
|
||||
#define OMAP1610_GPIO_DIRECTION 0x0034
|
||||
#define OMAP1610_GPIO_EDGE_CTRL1 0x0038
|
||||
#define OMAP1610_GPIO_EDGE_CTRL2 0x003c
|
||||
#define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c
|
||||
#define OMAP1610_GPIO_CLEAR_WAKEUPENA 0x00a8
|
||||
#define OMAP1610_GPIO_CLEAR_DATAOUT 0x00b0
|
||||
#define OMAP1610_GPIO_SET_IRQENABLE1 0x00dc
|
||||
#define OMAP1610_GPIO_SET_WAKEUPENA 0x00e8
|
||||
#define OMAP1610_GPIO_SET_DATAOUT 0x00f0
|
||||
|
||||
/*
|
||||
* OMAP730 specific GPIO registers
|
||||
*/
|
||||
#define OMAP730_GPIO1_BASE 0xfffbc000
|
||||
#define OMAP730_GPIO2_BASE 0xfffbc800
|
||||
#define OMAP730_GPIO3_BASE 0xfffbd000
|
||||
#define OMAP730_GPIO4_BASE 0xfffbd800
|
||||
#define OMAP730_GPIO5_BASE 0xfffbe000
|
||||
#define OMAP730_GPIO6_BASE 0xfffbe800
|
||||
#define OMAP730_GPIO1_BASE (void __iomem *)0xfffbc000
|
||||
#define OMAP730_GPIO2_BASE (void __iomem *)0xfffbc800
|
||||
#define OMAP730_GPIO3_BASE (void __iomem *)0xfffbd000
|
||||
#define OMAP730_GPIO4_BASE (void __iomem *)0xfffbd800
|
||||
#define OMAP730_GPIO5_BASE (void __iomem *)0xfffbe000
|
||||
#define OMAP730_GPIO6_BASE (void __iomem *)0xfffbe800
|
||||
#define OMAP730_GPIO_DATA_INPUT 0x00
|
||||
#define OMAP730_GPIO_DATA_OUTPUT 0x04
|
||||
#define OMAP730_GPIO_DIR_CONTROL 0x08
|
||||
|
@ -78,14 +84,43 @@
|
|||
#define OMAP730_GPIO_INT_MASK 0x10
|
||||
#define OMAP730_GPIO_INT_STATUS 0x14
|
||||
|
||||
/*
|
||||
* omap24xx specific GPIO registers
|
||||
*/
|
||||
#define OMAP24XX_GPIO1_BASE (void __iomem *)0x48018000
|
||||
#define OMAP24XX_GPIO2_BASE (void __iomem *)0x4801a000
|
||||
#define OMAP24XX_GPIO3_BASE (void __iomem *)0x4801c000
|
||||
#define OMAP24XX_GPIO4_BASE (void __iomem *)0x4801e000
|
||||
#define OMAP24XX_GPIO_REVISION 0x0000
|
||||
#define OMAP24XX_GPIO_SYSCONFIG 0x0010
|
||||
#define OMAP24XX_GPIO_SYSSTATUS 0x0014
|
||||
#define OMAP24XX_GPIO_IRQSTATUS1 0x0018
|
||||
#define OMAP24XX_GPIO_IRQENABLE1 0x001c
|
||||
#define OMAP24XX_GPIO_CTRL 0x0030
|
||||
#define OMAP24XX_GPIO_OE 0x0034
|
||||
#define OMAP24XX_GPIO_DATAIN 0x0038
|
||||
#define OMAP24XX_GPIO_DATAOUT 0x003c
|
||||
#define OMAP24XX_GPIO_LEVELDETECT0 0x0040
|
||||
#define OMAP24XX_GPIO_LEVELDETECT1 0x0044
|
||||
#define OMAP24XX_GPIO_RISINGDETECT 0x0048
|
||||
#define OMAP24XX_GPIO_FALLINGDETECT 0x004c
|
||||
#define OMAP24XX_GPIO_CLEARIRQENABLE1 0x0060
|
||||
#define OMAP24XX_GPIO_SETIRQENABLE1 0x0064
|
||||
#define OMAP24XX_GPIO_CLEARWKUENA 0x0080
|
||||
#define OMAP24XX_GPIO_SETWKUENA 0x0084
|
||||
#define OMAP24XX_GPIO_CLEARDATAOUT 0x0090
|
||||
#define OMAP24XX_GPIO_SETDATAOUT 0x0094
|
||||
|
||||
#define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff)
|
||||
|
||||
struct gpio_bank {
|
||||
u32 base;
|
||||
void __iomem *base;
|
||||
u16 irq;
|
||||
u16 virtual_irq_start;
|
||||
u8 method;
|
||||
int method;
|
||||
u32 reserved_map;
|
||||
u32 suspend_wakeup;
|
||||
u32 saved_wakeup;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
|
@ -93,8 +128,9 @@ struct gpio_bank {
|
|||
#define METHOD_GPIO_1510 1
|
||||
#define METHOD_GPIO_1610 2
|
||||
#define METHOD_GPIO_730 3
|
||||
#define METHOD_GPIO_24XX 4
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
#ifdef CONFIG_ARCH_OMAP16XX
|
||||
static struct gpio_bank gpio_bank_1610[5] = {
|
||||
{ OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO},
|
||||
{ OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 },
|
||||
|
@ -123,6 +159,15 @@ static struct gpio_bank gpio_bank_730[7] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP24XX
|
||||
static struct gpio_bank gpio_bank_24xx[4] = {
|
||||
{ OMAP24XX_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX },
|
||||
{ OMAP24XX_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX },
|
||||
{ OMAP24XX_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX },
|
||||
{ OMAP24XX_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX },
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct gpio_bank *gpio_bank;
|
||||
static int gpio_bank_count;
|
||||
|
||||
|
@ -149,14 +194,23 @@ static inline struct gpio_bank *get_gpio_bank(int gpio)
|
|||
return &gpio_bank[1 + (gpio >> 5)];
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP24XX
|
||||
if (cpu_is_omap24xx())
|
||||
return &gpio_bank[gpio >> 5];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int get_gpio_index(int gpio)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
if (cpu_is_omap730())
|
||||
return gpio & 0x1f;
|
||||
else
|
||||
return gpio & 0x0f;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP24XX
|
||||
if (cpu_is_omap24xx())
|
||||
return gpio & 0x1f;
|
||||
#endif
|
||||
return gpio & 0x0f;
|
||||
}
|
||||
|
||||
static inline int gpio_valid(int gpio)
|
||||
|
@ -179,6 +233,10 @@ static inline int gpio_valid(int gpio)
|
|||
#ifdef CONFIG_ARCH_OMAP730
|
||||
if (cpu_is_omap730() && gpio < 192)
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP24XX
|
||||
if (cpu_is_omap24xx() && gpio < 128)
|
||||
return 0;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
@ -195,7 +253,7 @@ static int check_gpio(int gpio)
|
|||
|
||||
static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l;
|
||||
|
||||
switch (bank->method) {
|
||||
|
@ -211,6 +269,9 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
|
|||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_DIR_CONTROL;
|
||||
break;
|
||||
case METHOD_GPIO_24XX:
|
||||
reg += OMAP24XX_GPIO_OE;
|
||||
break;
|
||||
}
|
||||
l = __raw_readl(reg);
|
||||
if (is_input)
|
||||
|
@ -234,7 +295,7 @@ void omap_set_gpio_direction(int gpio, int is_input)
|
|||
|
||||
static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l = 0;
|
||||
|
||||
switch (bank->method) {
|
||||
|
@ -269,6 +330,13 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
|
|||
else
|
||||
l &= ~(1 << gpio);
|
||||
break;
|
||||
case METHOD_GPIO_24XX:
|
||||
if (enable)
|
||||
reg += OMAP24XX_GPIO_SETDATAOUT;
|
||||
else
|
||||
reg += OMAP24XX_GPIO_CLEARDATAOUT;
|
||||
l = 1 << gpio;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
|
@ -291,7 +359,7 @@ void omap_set_gpio_dataout(int gpio, int enable)
|
|||
int omap_get_gpio_datain(int gpio)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
u32 reg;
|
||||
void __iomem *reg;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return -1;
|
||||
|
@ -310,109 +378,132 @@ int omap_get_gpio_datain(int gpio)
|
|||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_DATA_INPUT;
|
||||
break;
|
||||
case METHOD_GPIO_24XX:
|
||||
reg += OMAP24XX_GPIO_DATAIN;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return -1;
|
||||
}
|
||||
return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0;
|
||||
return (__raw_readl(reg)
|
||||
& (1 << get_gpio_index(gpio))) != 0;
|
||||
}
|
||||
|
||||
static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge)
|
||||
#define MOD_REG_BIT(reg, bit_mask, set) \
|
||||
do { \
|
||||
int l = __raw_readl(base + reg); \
|
||||
if (set) l |= bit_mask; \
|
||||
else l &= ~bit_mask; \
|
||||
__raw_writel(l, base + reg); \
|
||||
} while(0)
|
||||
|
||||
static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int trigger)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
u32 l;
|
||||
u32 gpio_bit = 1 << gpio;
|
||||
|
||||
MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
|
||||
trigger & IRQT_LOW);
|
||||
MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
|
||||
trigger & IRQT_HIGH);
|
||||
MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
|
||||
trigger & IRQT_RISING);
|
||||
MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
|
||||
trigger & IRQT_FALLING);
|
||||
/* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level
|
||||
* triggering requested. */
|
||||
}
|
||||
|
||||
static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
|
||||
{
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l = 0;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
reg += OMAP_MPUIO_GPIO_INT_EDGE;
|
||||
l = __raw_readl(reg);
|
||||
if (edge == OMAP_GPIO_RISING_EDGE)
|
||||
if (trigger == IRQT_RISING)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
else if (trigger == IRQT_FALLING)
|
||||
l &= ~(1 << gpio);
|
||||
__raw_writel(l, reg);
|
||||
else
|
||||
goto bad;
|
||||
break;
|
||||
case METHOD_GPIO_1510:
|
||||
reg += OMAP1510_GPIO_INT_CONTROL;
|
||||
l = __raw_readl(reg);
|
||||
if (edge == OMAP_GPIO_RISING_EDGE)
|
||||
if (trigger == IRQT_RISING)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
else if (trigger == IRQT_FALLING)
|
||||
l &= ~(1 << gpio);
|
||||
__raw_writel(l, reg);
|
||||
else
|
||||
goto bad;
|
||||
break;
|
||||
case METHOD_GPIO_1610:
|
||||
edge &= 0x03;
|
||||
if (gpio & 0x08)
|
||||
reg += OMAP1610_GPIO_EDGE_CTRL2;
|
||||
else
|
||||
reg += OMAP1610_GPIO_EDGE_CTRL1;
|
||||
gpio &= 0x07;
|
||||
/* We allow only edge triggering, i.e. two lowest bits */
|
||||
if (trigger & ~IRQT_BOTHEDGE)
|
||||
BUG();
|
||||
/* NOTE: knows __IRQT_{FAL,RIS}EDGE match OMAP hardware */
|
||||
trigger &= 0x03;
|
||||
l = __raw_readl(reg);
|
||||
l &= ~(3 << (gpio << 1));
|
||||
l |= edge << (gpio << 1);
|
||||
__raw_writel(l, reg);
|
||||
l |= trigger << (gpio << 1);
|
||||
break;
|
||||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_INT_CONTROL;
|
||||
l = __raw_readl(reg);
|
||||
if (edge == OMAP_GPIO_RISING_EDGE)
|
||||
if (trigger == IRQT_RISING)
|
||||
l |= 1 << gpio;
|
||||
else
|
||||
else if (trigger == IRQT_FALLING)
|
||||
l &= ~(1 << gpio);
|
||||
__raw_writel(l, reg);
|
||||
else
|
||||
goto bad;
|
||||
break;
|
||||
case METHOD_GPIO_24XX:
|
||||
set_24xx_gpio_triggering(reg, gpio, trigger);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
goto bad;
|
||||
}
|
||||
__raw_writel(l, reg);
|
||||
return 0;
|
||||
bad:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void omap_set_gpio_edge_ctrl(int gpio, int edge)
|
||||
static int gpio_irq_type(unsigned irq, unsigned type)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
unsigned gpio;
|
||||
int retval;
|
||||
|
||||
if (irq > IH_MPUIO_BASE)
|
||||
gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
|
||||
else
|
||||
gpio = irq - IH_GPIO_BASE;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
if (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL|IRQT_PROBE))
|
||||
return -EINVAL;
|
||||
|
||||
bank = get_gpio_bank(gpio);
|
||||
spin_lock(&bank->lock);
|
||||
_set_gpio_edge_ctrl(bank, get_gpio_index(gpio), edge);
|
||||
retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type);
|
||||
spin_unlock(&bank->lock);
|
||||
}
|
||||
|
||||
|
||||
static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio)
|
||||
{
|
||||
u32 reg = bank->base, l;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
l = __raw_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE);
|
||||
return (l & (1 << gpio)) ?
|
||||
OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
|
||||
case METHOD_GPIO_1510:
|
||||
l = __raw_readl(reg + OMAP1510_GPIO_INT_CONTROL);
|
||||
return (l & (1 << gpio)) ?
|
||||
OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
|
||||
case METHOD_GPIO_1610:
|
||||
if (gpio & 0x08)
|
||||
reg += OMAP1610_GPIO_EDGE_CTRL2;
|
||||
else
|
||||
reg += OMAP1610_GPIO_EDGE_CTRL1;
|
||||
return (__raw_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03;
|
||||
case METHOD_GPIO_730:
|
||||
l = __raw_readl(reg + OMAP730_GPIO_INT_CONTROL);
|
||||
return (l & (1 << gpio)) ?
|
||||
OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
|
||||
default:
|
||||
BUG();
|
||||
return -1;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
void __iomem *reg = bank->base;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_MPUIO:
|
||||
|
@ -428,6 +519,9 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
|||
case METHOD_GPIO_730:
|
||||
reg += OMAP730_GPIO_INT_STATUS;
|
||||
break;
|
||||
case METHOD_GPIO_24XX:
|
||||
reg += OMAP24XX_GPIO_IRQSTATUS1;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
|
@ -442,7 +536,7 @@ static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
|
|||
|
||||
static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable)
|
||||
{
|
||||
u32 reg = bank->base;
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l;
|
||||
|
||||
switch (bank->method) {
|
||||
|
@ -477,6 +571,13 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
|
|||
else
|
||||
l |= gpio_mask;
|
||||
break;
|
||||
case METHOD_GPIO_24XX:
|
||||
if (enable)
|
||||
reg += OMAP24XX_GPIO_SETIRQENABLE1;
|
||||
else
|
||||
reg += OMAP24XX_GPIO_CLEARIRQENABLE1;
|
||||
l = gpio_mask;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return;
|
||||
|
@ -489,6 +590,50 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena
|
|||
_enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register.
|
||||
* 1510 does not seem to have a wake-up register. If JTAG is connected
|
||||
* to the target, system will wake up always on GPIO events. While
|
||||
* system is running all registered GPIO interrupts need to have wake-up
|
||||
* enabled. When system is suspended, only selected GPIO interrupts need
|
||||
* to have wake-up enabled.
|
||||
*/
|
||||
static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
|
||||
{
|
||||
switch (bank->method) {
|
||||
case METHOD_GPIO_1610:
|
||||
case METHOD_GPIO_24XX:
|
||||
spin_lock(&bank->lock);
|
||||
if (enable)
|
||||
bank->suspend_wakeup |= (1 << gpio);
|
||||
else
|
||||
bank->suspend_wakeup &= ~(1 << gpio);
|
||||
spin_unlock(&bank->lock);
|
||||
return 0;
|
||||
default:
|
||||
printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n",
|
||||
bank->method);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
|
||||
static int gpio_wake_enable(unsigned int irq, unsigned int enable)
|
||||
{
|
||||
unsigned int gpio = irq - IH_GPIO_BASE;
|
||||
struct gpio_bank *bank;
|
||||
int retval;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return -ENODEV;
|
||||
bank = get_gpio_bank(gpio);
|
||||
spin_lock(&bank->lock);
|
||||
retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
|
||||
spin_unlock(&bank->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int omap_request_gpio(int gpio)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
|
@ -505,14 +650,32 @@ int omap_request_gpio(int gpio)
|
|||
return -1;
|
||||
}
|
||||
bank->reserved_map |= (1 << get_gpio_index(gpio));
|
||||
|
||||
/* Set trigger to none. You need to enable the trigger after request_irq */
|
||||
_set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (bank->method == METHOD_GPIO_1510) {
|
||||
u32 reg;
|
||||
void __iomem *reg;
|
||||
|
||||
/* Claim the pin for the ARM */
|
||||
/* Claim the pin for MPU */
|
||||
reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
|
||||
__raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP16XX
|
||||
if (bank->method == METHOD_GPIO_1610) {
|
||||
/* Enable wake-up during idle for dynamic tick */
|
||||
void __iomem *reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
|
||||
__raw_writel(1 << get_gpio_index(gpio), reg);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP24XX
|
||||
if (bank->method == METHOD_GPIO_24XX) {
|
||||
/* Enable wake-up during idle for dynamic tick */
|
||||
void __iomem *reg = bank->base + OMAP24XX_GPIO_SETWKUENA;
|
||||
__raw_writel(1 << get_gpio_index(gpio), reg);
|
||||
}
|
||||
#endif
|
||||
spin_unlock(&bank->lock);
|
||||
|
||||
|
@ -533,6 +696,20 @@ void omap_free_gpio(int gpio)
|
|||
spin_unlock(&bank->lock);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_ARCH_OMAP16XX
|
||||
if (bank->method == METHOD_GPIO_1610) {
|
||||
/* Disable wake-up during idle for dynamic tick */
|
||||
void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
|
||||
__raw_writel(1 << get_gpio_index(gpio), reg);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP24XX
|
||||
if (bank->method == METHOD_GPIO_24XX) {
|
||||
/* Disable wake-up during idle for dynamic tick */
|
||||
void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
|
||||
__raw_writel(1 << get_gpio_index(gpio), reg);
|
||||
}
|
||||
#endif
|
||||
bank->reserved_map &= ~(1 << get_gpio_index(gpio));
|
||||
_set_gpio_direction(bank, get_gpio_index(gpio), 1);
|
||||
_set_gpio_irqenable(bank, gpio, 0);
|
||||
|
@ -552,7 +729,7 @@ void omap_free_gpio(int gpio)
|
|||
static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
u32 isr_reg = 0;
|
||||
void __iomem *isr_reg = NULL;
|
||||
u32 isr;
|
||||
unsigned int gpio_irq;
|
||||
struct gpio_bank *bank;
|
||||
|
@ -574,24 +751,30 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
|
|||
if (bank->method == METHOD_GPIO_730)
|
||||
isr_reg = bank->base + OMAP730_GPIO_INT_STATUS;
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP24XX
|
||||
if (bank->method == METHOD_GPIO_24XX)
|
||||
isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1;
|
||||
#endif
|
||||
|
||||
isr = __raw_readl(isr_reg);
|
||||
_enable_gpio_irqbank(bank, isr, 0);
|
||||
_clear_gpio_irqbank(bank, isr);
|
||||
_enable_gpio_irqbank(bank, isr, 1);
|
||||
desc->chip->unmask(irq);
|
||||
while(1) {
|
||||
isr = __raw_readl(isr_reg);
|
||||
_enable_gpio_irqbank(bank, isr, 0);
|
||||
_clear_gpio_irqbank(bank, isr);
|
||||
_enable_gpio_irqbank(bank, isr, 1);
|
||||
desc->chip->unmask(irq);
|
||||
|
||||
if (unlikely(!isr))
|
||||
return;
|
||||
if (!isr)
|
||||
break;
|
||||
|
||||
gpio_irq = bank->virtual_irq_start;
|
||||
for (; isr != 0; isr >>= 1, gpio_irq++) {
|
||||
struct irqdesc *d;
|
||||
if (!(isr & 1))
|
||||
continue;
|
||||
d = irq_desc + gpio_irq;
|
||||
desc_handle_irq(gpio_irq, d, regs);
|
||||
}
|
||||
gpio_irq = bank->virtual_irq_start;
|
||||
for (; isr != 0; isr >>= 1, gpio_irq++) {
|
||||
struct irqdesc *d;
|
||||
if (!(isr & 1))
|
||||
continue;
|
||||
d = irq_desc + gpio_irq;
|
||||
desc_handle_irq(gpio_irq, d, regs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_ack_irq(unsigned int irq)
|
||||
|
@ -613,14 +796,10 @@ static void gpio_mask_irq(unsigned int irq)
|
|||
static void gpio_unmask_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int gpio = irq - IH_GPIO_BASE;
|
||||
unsigned int gpio_idx = get_gpio_index(gpio);
|
||||
struct gpio_bank *bank = get_gpio_bank(gpio);
|
||||
|
||||
if (_get_gpio_edge_ctrl(bank, get_gpio_index(gpio)) == OMAP_GPIO_NO_EDGE) {
|
||||
printk(KERN_ERR "OMAP GPIO %d: trying to enable GPIO IRQ while no edge is set\n",
|
||||
gpio);
|
||||
_set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE);
|
||||
}
|
||||
_set_gpio_irqenable(bank, gpio, 1);
|
||||
_set_gpio_irqenable(bank, gpio_idx, 1);
|
||||
}
|
||||
|
||||
static void mpuio_ack_irq(unsigned int irq)
|
||||
|
@ -645,9 +824,11 @@ static void mpuio_unmask_irq(unsigned int irq)
|
|||
}
|
||||
|
||||
static struct irqchip gpio_irq_chip = {
|
||||
.ack = gpio_ack_irq,
|
||||
.mask = gpio_mask_irq,
|
||||
.unmask = gpio_unmask_irq,
|
||||
.ack = gpio_ack_irq,
|
||||
.mask = gpio_mask_irq,
|
||||
.unmask = gpio_unmask_irq,
|
||||
.set_type = gpio_irq_type,
|
||||
.set_wake = gpio_wake_enable,
|
||||
};
|
||||
|
||||
static struct irqchip mpuio_irq_chip = {
|
||||
|
@ -657,6 +838,7 @@ static struct irqchip mpuio_irq_chip = {
|
|||
};
|
||||
|
||||
static int initialized = 0;
|
||||
static struct clk * gpio_ck = NULL;
|
||||
|
||||
static int __init _omap_gpio_init(void)
|
||||
{
|
||||
|
@ -665,6 +847,14 @@ static int __init _omap_gpio_init(void)
|
|||
|
||||
initialized = 1;
|
||||
|
||||
if (cpu_is_omap1510()) {
|
||||
gpio_ck = clk_get(NULL, "arm_gpio_ck");
|
||||
if (IS_ERR(gpio_ck))
|
||||
printk("Could not get arm_gpio_ck\n");
|
||||
else
|
||||
clk_use(gpio_ck);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1510
|
||||
if (cpu_is_omap1510()) {
|
||||
printk(KERN_INFO "OMAP1510 GPIO hardware\n");
|
||||
|
@ -674,7 +864,7 @@ static int __init _omap_gpio_init(void)
|
|||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP16XX)
|
||||
if (cpu_is_omap16xx()) {
|
||||
int rev;
|
||||
u32 rev;
|
||||
|
||||
gpio_bank_count = 5;
|
||||
gpio_bank = gpio_bank_1610;
|
||||
|
@ -689,6 +879,17 @@ static int __init _omap_gpio_init(void)
|
|||
gpio_bank_count = 7;
|
||||
gpio_bank = gpio_bank_730;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP24XX
|
||||
if (cpu_is_omap24xx()) {
|
||||
int rev;
|
||||
|
||||
gpio_bank_count = 4;
|
||||
gpio_bank = gpio_bank_24xx;
|
||||
rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
|
||||
printk(KERN_INFO "OMAP24xx GPIO hardware version %d.%d\n",
|
||||
(rev >> 4) & 0x0f, rev & 0x0f);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < gpio_bank_count; i++) {
|
||||
int j, gpio_count = 16;
|
||||
|
@ -710,6 +911,7 @@ static int __init _omap_gpio_init(void)
|
|||
if (bank->method == METHOD_GPIO_1610) {
|
||||
__raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1);
|
||||
__raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1);
|
||||
__raw_writew(0x0014, bank->base + OMAP1610_GPIO_SYSCONFIG);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP730
|
||||
|
@ -719,6 +921,14 @@ static int __init _omap_gpio_init(void)
|
|||
|
||||
gpio_count = 32; /* 730 has 32-bit GPIOs */
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_OMAP24XX
|
||||
if (bank->method == METHOD_GPIO_24XX) {
|
||||
__raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1);
|
||||
__raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1);
|
||||
|
||||
gpio_count = 32;
|
||||
}
|
||||
#endif
|
||||
for (j = bank->virtual_irq_start;
|
||||
j < bank->virtual_irq_start + gpio_count; j++) {
|
||||
|
@ -735,12 +945,97 @@ static int __init _omap_gpio_init(void)
|
|||
|
||||
/* Enable system clock for GPIO module.
|
||||
* The CAM_CLK_CTRL *is* really the right place. */
|
||||
if (cpu_is_omap1610() || cpu_is_omap1710())
|
||||
if (cpu_is_omap16xx())
|
||||
omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX)
|
||||
static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!cpu_is_omap24xx() && !cpu_is_omap16xx())
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < gpio_bank_count; i++) {
|
||||
struct gpio_bank *bank = &gpio_bank[i];
|
||||
void __iomem *wake_status;
|
||||
void __iomem *wake_clear;
|
||||
void __iomem *wake_set;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_GPIO_1610:
|
||||
wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
|
||||
wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
|
||||
wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
|
||||
break;
|
||||
case METHOD_GPIO_24XX:
|
||||
wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA;
|
||||
wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
|
||||
wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock(&bank->lock);
|
||||
bank->saved_wakeup = __raw_readl(wake_status);
|
||||
__raw_writel(0xffffffff, wake_clear);
|
||||
__raw_writel(bank->suspend_wakeup, wake_set);
|
||||
spin_unlock(&bank->lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_gpio_resume(struct sys_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!cpu_is_omap24xx() && !cpu_is_omap16xx())
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < gpio_bank_count; i++) {
|
||||
struct gpio_bank *bank = &gpio_bank[i];
|
||||
void __iomem *wake_clear;
|
||||
void __iomem *wake_set;
|
||||
|
||||
switch (bank->method) {
|
||||
case METHOD_GPIO_1610:
|
||||
wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
|
||||
wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
|
||||
break;
|
||||
case METHOD_GPIO_24XX:
|
||||
wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
|
||||
wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock(&bank->lock);
|
||||
__raw_writel(0xffffffff, wake_clear);
|
||||
__raw_writel(bank->saved_wakeup, wake_set);
|
||||
spin_unlock(&bank->lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sysdev_class omap_gpio_sysclass = {
|
||||
set_kset_name("gpio"),
|
||||
.suspend = omap_gpio_suspend,
|
||||
.resume = omap_gpio_resume,
|
||||
};
|
||||
|
||||
static struct sys_device omap_gpio_device = {
|
||||
.id = 0,
|
||||
.cls = &omap_gpio_sysclass,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This may get called early from board specific init
|
||||
*/
|
||||
|
@ -752,11 +1047,30 @@ int omap_gpio_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init omap_gpio_sysinit(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!initialized)
|
||||
ret = _omap_gpio_init();
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX)
|
||||
if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
|
||||
if (ret == 0) {
|
||||
ret = sysdev_class_register(&omap_gpio_sysclass);
|
||||
if (ret == 0)
|
||||
ret = sysdev_register(&omap_gpio_device);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(omap_request_gpio);
|
||||
EXPORT_SYMBOL(omap_free_gpio);
|
||||
EXPORT_SYMBOL(omap_set_gpio_direction);
|
||||
EXPORT_SYMBOL(omap_set_gpio_dataout);
|
||||
EXPORT_SYMBOL(omap_get_gpio_datain);
|
||||
EXPORT_SYMBOL(omap_set_gpio_edge_ctrl);
|
||||
|
||||
arch_initcall(omap_gpio_init);
|
||||
arch_initcall(omap_gpio_sysinit);
|
||||
|
|
|
@ -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 {
|
||||
} else
|
||||
omap_sram_idle();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
58
arch/arm/plat-omap/sram-fn.S
Normal file
58
arch/arm/plat-omap/sram-fn.S
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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
|
116
arch/arm/plat-omap/sram.c
Normal file
116
arch/arm/plat-omap/sram.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
21
arch/arm/plat-omap/sram.h
Normal file
21
arch/arm/plat-omap/sram.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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.
|
||||
|
|
Loading…
Reference in a new issue