Commit 92105bb70634abacc08bbe12bf6f888fbd7dad38
Committed by
Russell King
1 parent
7efb833d64
Exists in
master
and in
4 other branches
[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>
Showing 16 changed files with 1115 additions and 307 deletions Side-by-side Diff
- arch/arm/plat-omap/Kconfig
- arch/arm/plat-omap/Makefile
- arch/arm/plat-omap/clock.c
- arch/arm/plat-omap/common.c
- arch/arm/plat-omap/dma.c
- arch/arm/plat-omap/dmtimer.c
- arch/arm/plat-omap/gpio.c
- arch/arm/plat-omap/mcbsp.c
- arch/arm/plat-omap/mux.c
- arch/arm/plat-omap/ocpi.c
- arch/arm/plat-omap/pm.c
- arch/arm/plat-omap/sleep.S
- arch/arm/plat-omap/sram-fn.S
- arch/arm/plat-omap/sram.c
- arch/arm/plat-omap/sram.h
- arch/arm/plat-omap/usb.c
arch/arm/plat-omap/Kconfig
... | ... | @@ -91,6 +91,13 @@ |
91 | 91 | Kernel internal timer frequency should be a divisor of 32768, |
92 | 92 | such as 64 or 128. |
93 | 93 | |
94 | +config OMAP_DM_TIMER | |
95 | + bool "Use dual-mode timer" | |
96 | + default n | |
97 | + depends on ARCH_OMAP16XX | |
98 | + help | |
99 | + Select this option if you want to use OMAP Dual-Mode timers. | |
100 | + | |
94 | 101 | choice |
95 | 102 | prompt "Low-level debug console UART" |
96 | 103 | depends on ARCH_OMAP |
... | ... | @@ -106,6 +113,15 @@ |
106 | 113 | bool "UART3" |
107 | 114 | |
108 | 115 | endchoice |
116 | + | |
117 | +config OMAP_SERIAL_WAKE | |
118 | + bool "Enable wake-up events for serial ports" | |
119 | + depends OMAP_MUX | |
120 | + default y | |
121 | + help | |
122 | + Select this option if you want to have your system wake up | |
123 | + to data on the serial RX line. This allows you to wake the | |
124 | + system from serial console. | |
109 | 125 | |
110 | 126 | endmenu |
111 | 127 |
arch/arm/plat-omap/Makefile
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | # |
4 | 4 | |
5 | 5 | # Common support |
6 | -obj-y := common.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o | |
6 | +obj-y := common.o sram.o sram-fn.o clock.o dma.o mux.o gpio.o mcbsp.o usb.o | |
7 | 7 | obj-m := |
8 | 8 | obj-n := |
9 | 9 | obj- := |
... | ... | @@ -15,4 +15,5 @@ |
15 | 15 | obj-$(CONFIG_PM) += pm.o sleep.o |
16 | 16 | |
17 | 17 | obj-$(CONFIG_CPU_FREQ) += cpu-omap.o |
18 | +obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o |
arch/arm/plat-omap/clock.c
... | ... | @@ -21,6 +21,7 @@ |
21 | 21 | #include <asm/arch/usb.h> |
22 | 22 | |
23 | 23 | #include "clock.h" |
24 | +#include "sram.h" | |
24 | 25 | |
25 | 26 | static LIST_HEAD(clocks); |
26 | 27 | static DECLARE_MUTEX(clocks_sem); |
... | ... | @@ -141,7 +142,7 @@ |
141 | 142 | static struct clk armper_ck = { |
142 | 143 | .name = "armper_ck", |
143 | 144 | .parent = &ck_dpll1, |
144 | - .flags = CLOCK_IN_OMAP730 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | |
145 | + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | |
145 | 146 | RATE_CKCTL, |
146 | 147 | .enable_reg = ARM_IDLECT2, |
147 | 148 | .enable_bit = EN_PERCK, |
... | ... | @@ -385,7 +386,8 @@ |
385 | 386 | .name = "uart2_ck", |
386 | 387 | /* Direct from ULPD, no parent */ |
387 | 388 | .rate = 12000000, |
388 | - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT, | |
389 | + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT | | |
390 | + ALWAYS_ENABLED, | |
389 | 391 | .enable_reg = MOD_CONF_CTRL_0, |
390 | 392 | .enable_bit = 30, /* Chooses between 12MHz and 48MHz */ |
391 | 393 | .set_rate = &set_uart_rate, |
... | ... | @@ -443,6 +445,15 @@ |
443 | 445 | .enable_bit = 8 /* UHOST_EN */, |
444 | 446 | }; |
445 | 447 | |
448 | +static struct clk usb_dc_ck = { | |
449 | + .name = "usb_dc_ck", | |
450 | + /* Direct from ULPD, no parent */ | |
451 | + .rate = 48000000, | |
452 | + .flags = CLOCK_IN_OMAP16XX | RATE_FIXED, | |
453 | + .enable_reg = SOFT_REQ_REG, | |
454 | + .enable_bit = 4, | |
455 | +}; | |
456 | + | |
446 | 457 | static struct clk mclk_1510 = { |
447 | 458 | .name = "mclk", |
448 | 459 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ |
... | ... | @@ -552,6 +563,7 @@ |
552 | 563 | &uart3_16xx, |
553 | 564 | &usb_clko, |
554 | 565 | &usb_hhc_ck1510, &usb_hhc_ck16xx, |
566 | + &usb_dc_ck, | |
555 | 567 | &mclk_1510, &mclk_16xx, |
556 | 568 | &bclk_1510, &bclk_16xx, |
557 | 569 | &mmc1_ck, |
558 | 570 | |
... | ... | @@ -946,14 +958,13 @@ |
946 | 958 | if (!ptr->rate) |
947 | 959 | return -EINVAL; |
948 | 960 | |
949 | - if (!ptr->rate) | |
950 | - return -EINVAL; | |
961 | + /* | |
962 | + * In most cases we should not need to reprogram DPLL. | |
963 | + * Reprogramming the DPLL is tricky, it must be done from SRAM. | |
964 | + */ | |
965 | + omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); | |
951 | 966 | |
952 | - if (unlikely(ck_dpll1.rate == 0)) { | |
953 | - omap_writew(ptr->dpllctl_val, DPLL_CTL); | |
954 | - ck_dpll1.rate = ptr->pll_rate; | |
955 | - } | |
956 | - omap_writew(ptr->ckctl_val, ARM_CKCTL); | |
967 | + ck_dpll1.rate = ptr->pll_rate; | |
957 | 968 | propagate_rate(&ck_dpll1); |
958 | 969 | return 0; |
959 | 970 | } |
960 | 971 | |
... | ... | @@ -1224,9 +1235,11 @@ |
1224 | 1235 | #endif |
1225 | 1236 | /* Cache rates for clocks connected to ck_ref (not dpll1) */ |
1226 | 1237 | propagate_rate(&ck_ref); |
1227 | - printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n", | |
1238 | + printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): " | |
1239 | + "%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n", | |
1228 | 1240 | ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10, |
1229 | - ck_dpll1.rate, arm_ck.rate); | |
1241 | + ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10, | |
1242 | + arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10); | |
1230 | 1243 | |
1231 | 1244 | #ifdef CONFIG_MACH_OMAP_PERSEUS2 |
1232 | 1245 | /* Select slicer output as OMAP input clock */ |
... | ... | @@ -1271,7 +1284,9 @@ |
1271 | 1284 | struct clk *p; |
1272 | 1285 | __u32 regval32; |
1273 | 1286 | |
1274 | - omap_writew(0, SOFT_REQ_REG); | |
1287 | + /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ | |
1288 | + regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4); | |
1289 | + omap_writew(regval32, SOFT_REQ_REG); | |
1275 | 1290 | omap_writew(0, SOFT_REQ_REG2); |
1276 | 1291 | |
1277 | 1292 | list_for_each_entry(p, &clocks, node) { |
arch/arm/plat-omap/common.c
... | ... | @@ -26,6 +26,7 @@ |
26 | 26 | #include <asm/hardware/clock.h> |
27 | 27 | #include <asm/io.h> |
28 | 28 | #include <asm/mach-types.h> |
29 | +#include <asm/setup.h> | |
29 | 30 | |
30 | 31 | #include <asm/arch/board.h> |
31 | 32 | #include <asm/arch/mux.h> |
32 | 33 | |
... | ... | @@ -35,11 +36,11 @@ |
35 | 36 | |
36 | 37 | #define NO_LENGTH_CHECK 0xffffffff |
37 | 38 | |
38 | -extern int omap_bootloader_tag_len; | |
39 | -extern u8 omap_bootloader_tag[]; | |
39 | +unsigned char omap_bootloader_tag[512]; | |
40 | +int omap_bootloader_tag_len; | |
40 | 41 | |
41 | 42 | struct omap_board_config_kernel *omap_board_config; |
42 | -int omap_board_config_size = 0; | |
43 | +int omap_board_config_size; | |
43 | 44 | |
44 | 45 | static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out) |
45 | 46 | { |
arch/arm/plat-omap/dma.c
... | ... | @@ -425,7 +425,7 @@ |
425 | 425 | dma_chan[ch + 6].saved_csr = csr >> 7; |
426 | 426 | csr &= 0x7f; |
427 | 427 | } |
428 | - if (!csr) | |
428 | + if ((csr & 0x3f) == 0) | |
429 | 429 | return 0; |
430 | 430 | if (unlikely(dma_chan[ch].dev_id == -1)) { |
431 | 431 | printk(KERN_WARNING "Spurious interrupt from DMA channel %d (CSR %04x)\n", |
432 | 432 | |
... | ... | @@ -890,11 +890,11 @@ |
890 | 890 | w |= 1 << 8; |
891 | 891 | omap_writew(w, OMAP1610_DMA_LCD_CTRL); |
892 | 892 | |
893 | + lcd_dma.active = 1; | |
894 | + | |
893 | 895 | w = omap_readw(OMAP1610_DMA_LCD_CCR); |
894 | 896 | w |= 1 << 7; |
895 | 897 | omap_writew(w, OMAP1610_DMA_LCD_CCR); |
896 | - | |
897 | - lcd_dma.active = 1; | |
898 | 898 | } |
899 | 899 | |
900 | 900 | void omap_setup_lcd_dma(void) |
... | ... | @@ -965,8 +965,8 @@ |
965 | 965 | */ |
966 | 966 | dma_addr_t omap_get_dma_src_pos(int lch) |
967 | 967 | { |
968 | - return (dma_addr_t) (OMAP_DMA_CSSA_L(lch) | | |
969 | - (OMAP_DMA_CSSA_U(lch) << 16)); | |
968 | + return (dma_addr_t) (omap_readw(OMAP_DMA_CSSA_L(lch)) | | |
969 | + (omap_readw(OMAP_DMA_CSSA_U(lch)) << 16)); | |
970 | 970 | } |
971 | 971 | |
972 | 972 | /* |
973 | 973 | |
... | ... | @@ -979,10 +979,20 @@ |
979 | 979 | */ |
980 | 980 | dma_addr_t omap_get_dma_dst_pos(int lch) |
981 | 981 | { |
982 | - return (dma_addr_t) (OMAP_DMA_CDSA_L(lch) | | |
983 | - (OMAP_DMA_CDSA_U(lch) << 16)); | |
982 | + return (dma_addr_t) (omap_readw(OMAP_DMA_CDSA_L(lch)) | | |
983 | + (omap_readw(OMAP_DMA_CDSA_U(lch)) << 16)); | |
984 | 984 | } |
985 | 985 | |
986 | +/* | |
987 | + * Returns current source transfer counting for the given DMA channel. | |
988 | + * Can be used to monitor the progress of a transfer inside a block. | |
989 | + * It must be called with disabled interrupts. | |
990 | + */ | |
991 | +int omap_get_dma_src_addr_counter(int lch) | |
992 | +{ | |
993 | + return (dma_addr_t) omap_readw(OMAP_DMA_CSAC(lch)); | |
994 | +} | |
995 | + | |
986 | 996 | int omap_dma_running(void) |
987 | 997 | { |
988 | 998 | int lch; |
... | ... | @@ -1076,6 +1086,7 @@ |
1076 | 1086 | |
1077 | 1087 | EXPORT_SYMBOL(omap_get_dma_src_pos); |
1078 | 1088 | EXPORT_SYMBOL(omap_get_dma_dst_pos); |
1089 | +EXPORT_SYMBOL(omap_get_dma_src_addr_counter); | |
1079 | 1090 | EXPORT_SYMBOL(omap_clear_dma); |
1080 | 1091 | EXPORT_SYMBOL(omap_set_dma_priority); |
1081 | 1092 | EXPORT_SYMBOL(omap_request_dma); |
arch/arm/plat-omap/dmtimer.c
1 | +/* | |
2 | + * linux/arch/arm/plat-omap/dmtimer.c | |
3 | + * | |
4 | + * OMAP Dual-Mode Timers | |
5 | + * | |
6 | + * Copyright (C) 2005 Nokia Corporation | |
7 | + * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com> | |
8 | + * | |
9 | + * This program is free software; you can redistribute it and/or modify it | |
10 | + * under the terms of the GNU General Public License as published by the | |
11 | + * Free Software Foundation; either version 2 of the License, or (at your | |
12 | + * option) any later version. | |
13 | + * | |
14 | + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
15 | + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
16 | + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
17 | + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
18 | + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
19 | + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
20 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
21 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
22 | + * | |
23 | + * You should have received a copy of the GNU General Public License along | |
24 | + * with this program; if not, write to the Free Software Foundation, Inc., | |
25 | + * 675 Mass Ave, Cambridge, MA 02139, USA. | |
26 | + */ | |
27 | + | |
28 | +#include <linux/init.h> | |
29 | +#include <asm/arch/hardware.h> | |
30 | +#include <asm/arch/dmtimer.h> | |
31 | +#include <asm/io.h> | |
32 | +#include <asm/arch/irqs.h> | |
33 | +#include <linux/spinlock.h> | |
34 | +#include <linux/list.h> | |
35 | + | |
36 | +#define OMAP_TIMER_COUNT 8 | |
37 | + | |
38 | +#define OMAP_TIMER_ID_REG 0x00 | |
39 | +#define OMAP_TIMER_OCP_CFG_REG 0x10 | |
40 | +#define OMAP_TIMER_SYS_STAT_REG 0x14 | |
41 | +#define OMAP_TIMER_STAT_REG 0x18 | |
42 | +#define OMAP_TIMER_INT_EN_REG 0x1c | |
43 | +#define OMAP_TIMER_WAKEUP_EN_REG 0x20 | |
44 | +#define OMAP_TIMER_CTRL_REG 0x24 | |
45 | +#define OMAP_TIMER_COUNTER_REG 0x28 | |
46 | +#define OMAP_TIMER_LOAD_REG 0x2c | |
47 | +#define OMAP_TIMER_TRIGGER_REG 0x30 | |
48 | +#define OMAP_TIMER_WRITE_PEND_REG 0x34 | |
49 | +#define OMAP_TIMER_MATCH_REG 0x38 | |
50 | +#define OMAP_TIMER_CAPTURE_REG 0x3c | |
51 | +#define OMAP_TIMER_IF_CTRL_REG 0x40 | |
52 | + | |
53 | + | |
54 | +static struct dmtimer_info_struct { | |
55 | + struct list_head unused_timers; | |
56 | + struct list_head reserved_timers; | |
57 | +} dm_timer_info; | |
58 | + | |
59 | +static struct omap_dm_timer dm_timers[] = { | |
60 | + { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 }, | |
61 | + { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 }, | |
62 | + { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 }, | |
63 | + { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 }, | |
64 | + { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 }, | |
65 | + { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 }, | |
66 | + { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 }, | |
67 | + { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 }, | |
68 | + { .base=0x0 }, | |
69 | +}; | |
70 | + | |
71 | + | |
72 | +static spinlock_t dm_timer_lock; | |
73 | + | |
74 | + | |
75 | +inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) | |
76 | +{ | |
77 | + omap_writel(value, timer->base + reg); | |
78 | + while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) | |
79 | + ; | |
80 | +} | |
81 | + | |
82 | +u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) | |
83 | +{ | |
84 | + return omap_readl(timer->base + reg); | |
85 | +} | |
86 | + | |
87 | +int omap_dm_timers_active(void) | |
88 | +{ | |
89 | + struct omap_dm_timer *timer; | |
90 | + | |
91 | + for (timer = &dm_timers[0]; timer->base; ++timer) | |
92 | + if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & | |
93 | + OMAP_TIMER_CTRL_ST) | |
94 | + return 1; | |
95 | + | |
96 | + return 0; | |
97 | +} | |
98 | + | |
99 | + | |
100 | +void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) | |
101 | +{ | |
102 | + int n = (timer - dm_timers) << 1; | |
103 | + u32 l; | |
104 | + | |
105 | + l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); | |
106 | + l |= source << n; | |
107 | + omap_writel(l, MOD_CONF_CTRL_1); | |
108 | +} | |
109 | + | |
110 | + | |
111 | +static void omap_dm_timer_reset(struct omap_dm_timer *timer) | |
112 | +{ | |
113 | + /* Reset and set posted mode */ | |
114 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); | |
115 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02); | |
116 | + | |
117 | + omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR); | |
118 | +} | |
119 | + | |
120 | + | |
121 | + | |
122 | +struct omap_dm_timer * omap_dm_timer_request(void) | |
123 | +{ | |
124 | + struct omap_dm_timer *timer = NULL; | |
125 | + unsigned long flags; | |
126 | + | |
127 | + spin_lock_irqsave(&dm_timer_lock, flags); | |
128 | + if (!list_empty(&dm_timer_info.unused_timers)) { | |
129 | + timer = (struct omap_dm_timer *) | |
130 | + dm_timer_info.unused_timers.next; | |
131 | + list_move_tail((struct list_head *)timer, | |
132 | + &dm_timer_info.reserved_timers); | |
133 | + } | |
134 | + spin_unlock_irqrestore(&dm_timer_lock, flags); | |
135 | + | |
136 | + return timer; | |
137 | +} | |
138 | + | |
139 | + | |
140 | +void omap_dm_timer_free(struct omap_dm_timer *timer) | |
141 | +{ | |
142 | + unsigned long flags; | |
143 | + | |
144 | + omap_dm_timer_reset(timer); | |
145 | + | |
146 | + spin_lock_irqsave(&dm_timer_lock, flags); | |
147 | + list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers); | |
148 | + spin_unlock_irqrestore(&dm_timer_lock, flags); | |
149 | +} | |
150 | + | |
151 | +void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, | |
152 | + unsigned int value) | |
153 | +{ | |
154 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); | |
155 | +} | |
156 | + | |
157 | +unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) | |
158 | +{ | |
159 | + return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); | |
160 | +} | |
161 | + | |
162 | +void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) | |
163 | +{ | |
164 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); | |
165 | +} | |
166 | + | |
167 | +void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer) | |
168 | +{ | |
169 | + u32 l; | |
170 | + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | |
171 | + l |= OMAP_TIMER_CTRL_AR; | |
172 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | |
173 | +} | |
174 | + | |
175 | +void omap_dm_timer_trigger(struct omap_dm_timer *timer) | |
176 | +{ | |
177 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1); | |
178 | +} | |
179 | + | |
180 | +void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value) | |
181 | +{ | |
182 | + u32 l; | |
183 | + | |
184 | + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | |
185 | + l |= value & 0x3; | |
186 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | |
187 | +} | |
188 | + | |
189 | +void omap_dm_timer_start(struct omap_dm_timer *timer) | |
190 | +{ | |
191 | + u32 l; | |
192 | + | |
193 | + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | |
194 | + l |= OMAP_TIMER_CTRL_ST; | |
195 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | |
196 | +} | |
197 | + | |
198 | +void omap_dm_timer_stop(struct omap_dm_timer *timer) | |
199 | +{ | |
200 | + u32 l; | |
201 | + | |
202 | + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | |
203 | + l &= ~0x1; | |
204 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | |
205 | +} | |
206 | + | |
207 | +unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) | |
208 | +{ | |
209 | + return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); | |
210 | +} | |
211 | + | |
212 | +void omap_dm_timer_reset_counter(struct omap_dm_timer *timer) | |
213 | +{ | |
214 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0); | |
215 | +} | |
216 | + | |
217 | +void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load) | |
218 | +{ | |
219 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); | |
220 | +} | |
221 | + | |
222 | +void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match) | |
223 | +{ | |
224 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); | |
225 | +} | |
226 | + | |
227 | +void omap_dm_timer_enable_compare(struct omap_dm_timer *timer) | |
228 | +{ | |
229 | + u32 l; | |
230 | + | |
231 | + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | |
232 | + l |= OMAP_TIMER_CTRL_CE; | |
233 | + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | |
234 | +} | |
235 | + | |
236 | + | |
237 | +static inline void __dm_timer_init(void) | |
238 | +{ | |
239 | + struct omap_dm_timer *timer; | |
240 | + | |
241 | + spin_lock_init(&dm_timer_lock); | |
242 | + INIT_LIST_HEAD(&dm_timer_info.unused_timers); | |
243 | + INIT_LIST_HEAD(&dm_timer_info.reserved_timers); | |
244 | + | |
245 | + timer = &dm_timers[0]; | |
246 | + while (timer->base) { | |
247 | + list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers); | |
248 | + omap_dm_timer_reset(timer); | |
249 | + timer++; | |
250 | + } | |
251 | +} | |
252 | + | |
253 | +static int __init omap_dm_timer_init(void) | |
254 | +{ | |
255 | + if (cpu_is_omap16xx()) | |
256 | + __dm_timer_init(); | |
257 | + return 0; | |
258 | +} | |
259 | + | |
260 | +arch_initcall(omap_dm_timer_init); |
arch/arm/plat-omap/gpio.c
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | * |
4 | 4 | * Support functions for OMAP GPIO |
5 | 5 | * |
6 | - * Copyright (C) 2003 Nokia Corporation | |
6 | + * Copyright (C) 2003-2005 Nokia Corporation | |
7 | 7 | * Written by Juha Yrjรถlรค <juha.yrjola@nokia.com> |
8 | 8 | * |
9 | 9 | * This program is free software; you can redistribute it and/or modify |
10 | 10 | |
... | ... | @@ -17,8 +17,11 @@ |
17 | 17 | #include <linux/sched.h> |
18 | 18 | #include <linux/interrupt.h> |
19 | 19 | #include <linux/ptrace.h> |
20 | +#include <linux/sysdev.h> | |
21 | +#include <linux/err.h> | |
20 | 22 | |
21 | 23 | #include <asm/hardware.h> |
24 | +#include <asm/hardware/clock.h> | |
22 | 25 | #include <asm/irq.h> |
23 | 26 | #include <asm/arch/irqs.h> |
24 | 27 | #include <asm/arch/gpio.h> |
... | ... | @@ -29,7 +32,7 @@ |
29 | 32 | /* |
30 | 33 | * OMAP1510 GPIO registers |
31 | 34 | */ |
32 | -#define OMAP1510_GPIO_BASE 0xfffce000 | |
35 | +#define OMAP1510_GPIO_BASE (void __iomem *)0xfffce000 | |
33 | 36 | #define OMAP1510_GPIO_DATA_INPUT 0x00 |
34 | 37 | #define OMAP1510_GPIO_DATA_OUTPUT 0x04 |
35 | 38 | #define OMAP1510_GPIO_DIR_CONTROL 0x08 |
36 | 39 | |
37 | 40 | |
38 | 41 | |
39 | 42 | |
... | ... | @@ -43,34 +46,37 @@ |
43 | 46 | /* |
44 | 47 | * OMAP1610 specific GPIO registers |
45 | 48 | */ |
46 | -#define OMAP1610_GPIO1_BASE 0xfffbe400 | |
47 | -#define OMAP1610_GPIO2_BASE 0xfffbec00 | |
48 | -#define OMAP1610_GPIO3_BASE 0xfffbb400 | |
49 | -#define OMAP1610_GPIO4_BASE 0xfffbbc00 | |
49 | +#define OMAP1610_GPIO1_BASE (void __iomem *)0xfffbe400 | |
50 | +#define OMAP1610_GPIO2_BASE (void __iomem *)0xfffbec00 | |
51 | +#define OMAP1610_GPIO3_BASE (void __iomem *)0xfffbb400 | |
52 | +#define OMAP1610_GPIO4_BASE (void __iomem *)0xfffbbc00 | |
50 | 53 | #define OMAP1610_GPIO_REVISION 0x0000 |
51 | 54 | #define OMAP1610_GPIO_SYSCONFIG 0x0010 |
52 | 55 | #define OMAP1610_GPIO_SYSSTATUS 0x0014 |
53 | 56 | #define OMAP1610_GPIO_IRQSTATUS1 0x0018 |
54 | 57 | #define OMAP1610_GPIO_IRQENABLE1 0x001c |
58 | +#define OMAP1610_GPIO_WAKEUPENABLE 0x0028 | |
55 | 59 | #define OMAP1610_GPIO_DATAIN 0x002c |
56 | 60 | #define OMAP1610_GPIO_DATAOUT 0x0030 |
57 | 61 | #define OMAP1610_GPIO_DIRECTION 0x0034 |
58 | 62 | #define OMAP1610_GPIO_EDGE_CTRL1 0x0038 |
59 | 63 | #define OMAP1610_GPIO_EDGE_CTRL2 0x003c |
60 | 64 | #define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c |
65 | +#define OMAP1610_GPIO_CLEAR_WAKEUPENA 0x00a8 | |
61 | 66 | #define OMAP1610_GPIO_CLEAR_DATAOUT 0x00b0 |
62 | 67 | #define OMAP1610_GPIO_SET_IRQENABLE1 0x00dc |
68 | +#define OMAP1610_GPIO_SET_WAKEUPENA 0x00e8 | |
63 | 69 | #define OMAP1610_GPIO_SET_DATAOUT 0x00f0 |
64 | 70 | |
65 | 71 | /* |
66 | 72 | * OMAP730 specific GPIO registers |
67 | 73 | */ |
68 | -#define OMAP730_GPIO1_BASE 0xfffbc000 | |
69 | -#define OMAP730_GPIO2_BASE 0xfffbc800 | |
70 | -#define OMAP730_GPIO3_BASE 0xfffbd000 | |
71 | -#define OMAP730_GPIO4_BASE 0xfffbd800 | |
72 | -#define OMAP730_GPIO5_BASE 0xfffbe000 | |
73 | -#define OMAP730_GPIO6_BASE 0xfffbe800 | |
74 | +#define OMAP730_GPIO1_BASE (void __iomem *)0xfffbc000 | |
75 | +#define OMAP730_GPIO2_BASE (void __iomem *)0xfffbc800 | |
76 | +#define OMAP730_GPIO3_BASE (void __iomem *)0xfffbd000 | |
77 | +#define OMAP730_GPIO4_BASE (void __iomem *)0xfffbd800 | |
78 | +#define OMAP730_GPIO5_BASE (void __iomem *)0xfffbe000 | |
79 | +#define OMAP730_GPIO6_BASE (void __iomem *)0xfffbe800 | |
74 | 80 | #define OMAP730_GPIO_DATA_INPUT 0x00 |
75 | 81 | #define OMAP730_GPIO_DATA_OUTPUT 0x04 |
76 | 82 | #define OMAP730_GPIO_DIR_CONTROL 0x08 |
77 | 83 | |
78 | 84 | |
79 | 85 | |
... | ... | @@ -78,14 +84,43 @@ |
78 | 84 | #define OMAP730_GPIO_INT_MASK 0x10 |
79 | 85 | #define OMAP730_GPIO_INT_STATUS 0x14 |
80 | 86 | |
87 | +/* | |
88 | + * omap24xx specific GPIO registers | |
89 | + */ | |
90 | +#define OMAP24XX_GPIO1_BASE (void __iomem *)0x48018000 | |
91 | +#define OMAP24XX_GPIO2_BASE (void __iomem *)0x4801a000 | |
92 | +#define OMAP24XX_GPIO3_BASE (void __iomem *)0x4801c000 | |
93 | +#define OMAP24XX_GPIO4_BASE (void __iomem *)0x4801e000 | |
94 | +#define OMAP24XX_GPIO_REVISION 0x0000 | |
95 | +#define OMAP24XX_GPIO_SYSCONFIG 0x0010 | |
96 | +#define OMAP24XX_GPIO_SYSSTATUS 0x0014 | |
97 | +#define OMAP24XX_GPIO_IRQSTATUS1 0x0018 | |
98 | +#define OMAP24XX_GPIO_IRQENABLE1 0x001c | |
99 | +#define OMAP24XX_GPIO_CTRL 0x0030 | |
100 | +#define OMAP24XX_GPIO_OE 0x0034 | |
101 | +#define OMAP24XX_GPIO_DATAIN 0x0038 | |
102 | +#define OMAP24XX_GPIO_DATAOUT 0x003c | |
103 | +#define OMAP24XX_GPIO_LEVELDETECT0 0x0040 | |
104 | +#define OMAP24XX_GPIO_LEVELDETECT1 0x0044 | |
105 | +#define OMAP24XX_GPIO_RISINGDETECT 0x0048 | |
106 | +#define OMAP24XX_GPIO_FALLINGDETECT 0x004c | |
107 | +#define OMAP24XX_GPIO_CLEARIRQENABLE1 0x0060 | |
108 | +#define OMAP24XX_GPIO_SETIRQENABLE1 0x0064 | |
109 | +#define OMAP24XX_GPIO_CLEARWKUENA 0x0080 | |
110 | +#define OMAP24XX_GPIO_SETWKUENA 0x0084 | |
111 | +#define OMAP24XX_GPIO_CLEARDATAOUT 0x0090 | |
112 | +#define OMAP24XX_GPIO_SETDATAOUT 0x0094 | |
113 | + | |
81 | 114 | #define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff) |
82 | 115 | |
83 | 116 | struct gpio_bank { |
84 | - u32 base; | |
117 | + void __iomem *base; | |
85 | 118 | u16 irq; |
86 | 119 | u16 virtual_irq_start; |
87 | - u8 method; | |
120 | + int method; | |
88 | 121 | u32 reserved_map; |
122 | + u32 suspend_wakeup; | |
123 | + u32 saved_wakeup; | |
89 | 124 | spinlock_t lock; |
90 | 125 | }; |
91 | 126 | |
92 | 127 | |
... | ... | @@ -93,8 +128,9 @@ |
93 | 128 | #define METHOD_GPIO_1510 1 |
94 | 129 | #define METHOD_GPIO_1610 2 |
95 | 130 | #define METHOD_GPIO_730 3 |
131 | +#define METHOD_GPIO_24XX 4 | |
96 | 132 | |
97 | -#if defined(CONFIG_ARCH_OMAP16XX) | |
133 | +#ifdef CONFIG_ARCH_OMAP16XX | |
98 | 134 | static struct gpio_bank gpio_bank_1610[5] = { |
99 | 135 | { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO}, |
100 | 136 | { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 }, |
... | ... | @@ -123,6 +159,15 @@ |
123 | 159 | }; |
124 | 160 | #endif |
125 | 161 | |
162 | +#ifdef CONFIG_ARCH_OMAP24XX | |
163 | +static struct gpio_bank gpio_bank_24xx[4] = { | |
164 | + { OMAP24XX_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX }, | |
165 | + { OMAP24XX_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX }, | |
166 | + { OMAP24XX_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX }, | |
167 | + { OMAP24XX_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX }, | |
168 | +}; | |
169 | +#endif | |
170 | + | |
126 | 171 | static struct gpio_bank *gpio_bank; |
127 | 172 | static int gpio_bank_count; |
128 | 173 | |
129 | 174 | |
130 | 175 | |
... | ... | @@ -149,14 +194,23 @@ |
149 | 194 | return &gpio_bank[1 + (gpio >> 5)]; |
150 | 195 | } |
151 | 196 | #endif |
197 | +#ifdef CONFIG_ARCH_OMAP24XX | |
198 | + if (cpu_is_omap24xx()) | |
199 | + return &gpio_bank[gpio >> 5]; | |
200 | +#endif | |
152 | 201 | } |
153 | 202 | |
154 | 203 | static inline int get_gpio_index(int gpio) |
155 | 204 | { |
205 | +#ifdef CONFIG_ARCH_OMAP730 | |
156 | 206 | if (cpu_is_omap730()) |
157 | 207 | return gpio & 0x1f; |
158 | - else | |
159 | - return gpio & 0x0f; | |
208 | +#endif | |
209 | +#ifdef CONFIG_ARCH_OMAP24XX | |
210 | + if (cpu_is_omap24xx()) | |
211 | + return gpio & 0x1f; | |
212 | +#endif | |
213 | + return gpio & 0x0f; | |
160 | 214 | } |
161 | 215 | |
162 | 216 | static inline int gpio_valid(int gpio) |
... | ... | @@ -180,6 +234,10 @@ |
180 | 234 | if (cpu_is_omap730() && gpio < 192) |
181 | 235 | return 0; |
182 | 236 | #endif |
237 | +#ifdef CONFIG_ARCH_OMAP24XX | |
238 | + if (cpu_is_omap24xx() && gpio < 128) | |
239 | + return 0; | |
240 | +#endif | |
183 | 241 | return -1; |
184 | 242 | } |
185 | 243 | |
... | ... | @@ -195,7 +253,7 @@ |
195 | 253 | |
196 | 254 | static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) |
197 | 255 | { |
198 | - u32 reg = bank->base; | |
256 | + void __iomem *reg = bank->base; | |
199 | 257 | u32 l; |
200 | 258 | |
201 | 259 | switch (bank->method) { |
... | ... | @@ -211,6 +269,9 @@ |
211 | 269 | case METHOD_GPIO_730: |
212 | 270 | reg += OMAP730_GPIO_DIR_CONTROL; |
213 | 271 | break; |
272 | + case METHOD_GPIO_24XX: | |
273 | + reg += OMAP24XX_GPIO_OE; | |
274 | + break; | |
214 | 275 | } |
215 | 276 | l = __raw_readl(reg); |
216 | 277 | if (is_input) |
... | ... | @@ -234,7 +295,7 @@ |
234 | 295 | |
235 | 296 | static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable) |
236 | 297 | { |
237 | - u32 reg = bank->base; | |
298 | + void __iomem *reg = bank->base; | |
238 | 299 | u32 l = 0; |
239 | 300 | |
240 | 301 | switch (bank->method) { |
... | ... | @@ -269,6 +330,13 @@ |
269 | 330 | else |
270 | 331 | l &= ~(1 << gpio); |
271 | 332 | break; |
333 | + case METHOD_GPIO_24XX: | |
334 | + if (enable) | |
335 | + reg += OMAP24XX_GPIO_SETDATAOUT; | |
336 | + else | |
337 | + reg += OMAP24XX_GPIO_CLEARDATAOUT; | |
338 | + l = 1 << gpio; | |
339 | + break; | |
272 | 340 | default: |
273 | 341 | BUG(); |
274 | 342 | return; |
... | ... | @@ -291,7 +359,7 @@ |
291 | 359 | int omap_get_gpio_datain(int gpio) |
292 | 360 | { |
293 | 361 | struct gpio_bank *bank; |
294 | - u32 reg; | |
362 | + void __iomem *reg; | |
295 | 363 | |
296 | 364 | if (check_gpio(gpio) < 0) |
297 | 365 | return -1; |
298 | 366 | |
299 | 367 | |
300 | 368 | |
301 | 369 | |
302 | 370 | |
303 | 371 | |
304 | 372 | |
305 | 373 | |
306 | 374 | |
307 | 375 | |
308 | 376 | |
309 | 377 | |
310 | 378 | |
311 | 379 | |
312 | 380 | |
313 | 381 | |
314 | 382 | |
315 | 383 | |
316 | 384 | |
317 | 385 | |
318 | 386 | |
319 | 387 | |
320 | 388 | |
321 | 389 | |
322 | 390 | |
323 | 391 | |
324 | 392 | |
... | ... | @@ -310,109 +378,132 @@ |
310 | 378 | case METHOD_GPIO_730: |
311 | 379 | reg += OMAP730_GPIO_DATA_INPUT; |
312 | 380 | break; |
381 | + case METHOD_GPIO_24XX: | |
382 | + reg += OMAP24XX_GPIO_DATAIN; | |
383 | + break; | |
313 | 384 | default: |
314 | 385 | BUG(); |
315 | 386 | return -1; |
316 | 387 | } |
317 | - return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0; | |
388 | + return (__raw_readl(reg) | |
389 | + & (1 << get_gpio_index(gpio))) != 0; | |
318 | 390 | } |
319 | 391 | |
320 | -static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge) | |
392 | +#define MOD_REG_BIT(reg, bit_mask, set) \ | |
393 | +do { \ | |
394 | + int l = __raw_readl(base + reg); \ | |
395 | + if (set) l |= bit_mask; \ | |
396 | + else l &= ~bit_mask; \ | |
397 | + __raw_writel(l, base + reg); \ | |
398 | +} while(0) | |
399 | + | |
400 | +static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int trigger) | |
321 | 401 | { |
322 | - u32 reg = bank->base; | |
323 | - u32 l; | |
402 | + u32 gpio_bit = 1 << gpio; | |
324 | 403 | |
404 | + MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, | |
405 | + trigger & IRQT_LOW); | |
406 | + MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, | |
407 | + trigger & IRQT_HIGH); | |
408 | + MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit, | |
409 | + trigger & IRQT_RISING); | |
410 | + MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, | |
411 | + trigger & IRQT_FALLING); | |
412 | + /* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level | |
413 | + * triggering requested. */ | |
414 | +} | |
415 | + | |
416 | +static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) | |
417 | +{ | |
418 | + void __iomem *reg = bank->base; | |
419 | + u32 l = 0; | |
420 | + | |
325 | 421 | switch (bank->method) { |
326 | 422 | case METHOD_MPUIO: |
327 | 423 | reg += OMAP_MPUIO_GPIO_INT_EDGE; |
328 | 424 | l = __raw_readl(reg); |
329 | - if (edge == OMAP_GPIO_RISING_EDGE) | |
425 | + if (trigger == IRQT_RISING) | |
330 | 426 | l |= 1 << gpio; |
331 | - else | |
427 | + else if (trigger == IRQT_FALLING) | |
332 | 428 | l &= ~(1 << gpio); |
333 | - __raw_writel(l, reg); | |
429 | + else | |
430 | + goto bad; | |
334 | 431 | break; |
335 | 432 | case METHOD_GPIO_1510: |
336 | 433 | reg += OMAP1510_GPIO_INT_CONTROL; |
337 | 434 | l = __raw_readl(reg); |
338 | - if (edge == OMAP_GPIO_RISING_EDGE) | |
435 | + if (trigger == IRQT_RISING) | |
339 | 436 | l |= 1 << gpio; |
340 | - else | |
437 | + else if (trigger == IRQT_FALLING) | |
341 | 438 | l &= ~(1 << gpio); |
342 | - __raw_writel(l, reg); | |
439 | + else | |
440 | + goto bad; | |
343 | 441 | break; |
344 | 442 | case METHOD_GPIO_1610: |
345 | - edge &= 0x03; | |
346 | 443 | if (gpio & 0x08) |
347 | 444 | reg += OMAP1610_GPIO_EDGE_CTRL2; |
348 | 445 | else |
349 | 446 | reg += OMAP1610_GPIO_EDGE_CTRL1; |
350 | 447 | gpio &= 0x07; |
448 | + /* We allow only edge triggering, i.e. two lowest bits */ | |
449 | + if (trigger & ~IRQT_BOTHEDGE) | |
450 | + BUG(); | |
451 | + /* NOTE: knows __IRQT_{FAL,RIS}EDGE match OMAP hardware */ | |
452 | + trigger &= 0x03; | |
351 | 453 | l = __raw_readl(reg); |
352 | 454 | l &= ~(3 << (gpio << 1)); |
353 | - l |= edge << (gpio << 1); | |
354 | - __raw_writel(l, reg); | |
455 | + l |= trigger << (gpio << 1); | |
355 | 456 | break; |
356 | 457 | case METHOD_GPIO_730: |
357 | 458 | reg += OMAP730_GPIO_INT_CONTROL; |
358 | 459 | l = __raw_readl(reg); |
359 | - if (edge == OMAP_GPIO_RISING_EDGE) | |
460 | + if (trigger == IRQT_RISING) | |
360 | 461 | l |= 1 << gpio; |
361 | - else | |
462 | + else if (trigger == IRQT_FALLING) | |
362 | 463 | l &= ~(1 << gpio); |
363 | - __raw_writel(l, reg); | |
464 | + else | |
465 | + goto bad; | |
364 | 466 | break; |
467 | + case METHOD_GPIO_24XX: | |
468 | + set_24xx_gpio_triggering(reg, gpio, trigger); | |
469 | + break; | |
365 | 470 | default: |
366 | 471 | BUG(); |
367 | - return; | |
472 | + goto bad; | |
368 | 473 | } |
474 | + __raw_writel(l, reg); | |
475 | + return 0; | |
476 | +bad: | |
477 | + return -EINVAL; | |
369 | 478 | } |
370 | 479 | |
371 | -void omap_set_gpio_edge_ctrl(int gpio, int edge) | |
480 | +static int gpio_irq_type(unsigned irq, unsigned type) | |
372 | 481 | { |
373 | 482 | struct gpio_bank *bank; |
483 | + unsigned gpio; | |
484 | + int retval; | |
374 | 485 | |
486 | + if (irq > IH_MPUIO_BASE) | |
487 | + gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); | |
488 | + else | |
489 | + gpio = irq - IH_GPIO_BASE; | |
490 | + | |
375 | 491 | if (check_gpio(gpio) < 0) |
376 | - return; | |
492 | + return -EINVAL; | |
493 | + | |
494 | + if (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL|IRQT_PROBE)) | |
495 | + return -EINVAL; | |
496 | + | |
377 | 497 | bank = get_gpio_bank(gpio); |
378 | 498 | spin_lock(&bank->lock); |
379 | - _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), edge); | |
499 | + retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type); | |
380 | 500 | spin_unlock(&bank->lock); |
501 | + return retval; | |
381 | 502 | } |
382 | 503 | |
383 | - | |
384 | -static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio) | |
385 | -{ | |
386 | - u32 reg = bank->base, l; | |
387 | - | |
388 | - switch (bank->method) { | |
389 | - case METHOD_MPUIO: | |
390 | - l = __raw_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE); | |
391 | - return (l & (1 << gpio)) ? | |
392 | - OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; | |
393 | - case METHOD_GPIO_1510: | |
394 | - l = __raw_readl(reg + OMAP1510_GPIO_INT_CONTROL); | |
395 | - return (l & (1 << gpio)) ? | |
396 | - OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; | |
397 | - case METHOD_GPIO_1610: | |
398 | - if (gpio & 0x08) | |
399 | - reg += OMAP1610_GPIO_EDGE_CTRL2; | |
400 | - else | |
401 | - reg += OMAP1610_GPIO_EDGE_CTRL1; | |
402 | - return (__raw_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03; | |
403 | - case METHOD_GPIO_730: | |
404 | - l = __raw_readl(reg + OMAP730_GPIO_INT_CONTROL); | |
405 | - return (l & (1 << gpio)) ? | |
406 | - OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE; | |
407 | - default: | |
408 | - BUG(); | |
409 | - return -1; | |
410 | - } | |
411 | -} | |
412 | - | |
413 | 504 | static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) |
414 | 505 | { |
415 | - u32 reg = bank->base; | |
506 | + void __iomem *reg = bank->base; | |
416 | 507 | |
417 | 508 | switch (bank->method) { |
418 | 509 | case METHOD_MPUIO: |
... | ... | @@ -428,6 +519,9 @@ |
428 | 519 | case METHOD_GPIO_730: |
429 | 520 | reg += OMAP730_GPIO_INT_STATUS; |
430 | 521 | break; |
522 | + case METHOD_GPIO_24XX: | |
523 | + reg += OMAP24XX_GPIO_IRQSTATUS1; | |
524 | + break; | |
431 | 525 | default: |
432 | 526 | BUG(); |
433 | 527 | return; |
... | ... | @@ -442,7 +536,7 @@ |
442 | 536 | |
443 | 537 | static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) |
444 | 538 | { |
445 | - u32 reg = bank->base; | |
539 | + void __iomem *reg = bank->base; | |
446 | 540 | u32 l; |
447 | 541 | |
448 | 542 | switch (bank->method) { |
... | ... | @@ -477,6 +571,13 @@ |
477 | 571 | else |
478 | 572 | l |= gpio_mask; |
479 | 573 | break; |
574 | + case METHOD_GPIO_24XX: | |
575 | + if (enable) | |
576 | + reg += OMAP24XX_GPIO_SETIRQENABLE1; | |
577 | + else | |
578 | + reg += OMAP24XX_GPIO_CLEARIRQENABLE1; | |
579 | + l = gpio_mask; | |
580 | + break; | |
480 | 581 | default: |
481 | 582 | BUG(); |
482 | 583 | return; |
... | ... | @@ -489,6 +590,50 @@ |
489 | 590 | _enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable); |
490 | 591 | } |
491 | 592 | |
593 | +/* | |
594 | + * Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register. | |
595 | + * 1510 does not seem to have a wake-up register. If JTAG is connected | |
596 | + * to the target, system will wake up always on GPIO events. While | |
597 | + * system is running all registered GPIO interrupts need to have wake-up | |
598 | + * enabled. When system is suspended, only selected GPIO interrupts need | |
599 | + * to have wake-up enabled. | |
600 | + */ | |
601 | +static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) | |
602 | +{ | |
603 | + switch (bank->method) { | |
604 | + case METHOD_GPIO_1610: | |
605 | + case METHOD_GPIO_24XX: | |
606 | + spin_lock(&bank->lock); | |
607 | + if (enable) | |
608 | + bank->suspend_wakeup |= (1 << gpio); | |
609 | + else | |
610 | + bank->suspend_wakeup &= ~(1 << gpio); | |
611 | + spin_unlock(&bank->lock); | |
612 | + return 0; | |
613 | + default: | |
614 | + printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n", | |
615 | + bank->method); | |
616 | + return -EINVAL; | |
617 | + } | |
618 | +} | |
619 | + | |
620 | +/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ | |
621 | +static int gpio_wake_enable(unsigned int irq, unsigned int enable) | |
622 | +{ | |
623 | + unsigned int gpio = irq - IH_GPIO_BASE; | |
624 | + struct gpio_bank *bank; | |
625 | + int retval; | |
626 | + | |
627 | + if (check_gpio(gpio) < 0) | |
628 | + return -ENODEV; | |
629 | + bank = get_gpio_bank(gpio); | |
630 | + spin_lock(&bank->lock); | |
631 | + retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable); | |
632 | + spin_unlock(&bank->lock); | |
633 | + | |
634 | + return retval; | |
635 | +} | |
636 | + | |
492 | 637 | int omap_request_gpio(int gpio) |
493 | 638 | { |
494 | 639 | struct gpio_bank *bank; |
495 | 640 | |
496 | 641 | |
497 | 642 | |
... | ... | @@ -505,15 +650,33 @@ |
505 | 650 | return -1; |
506 | 651 | } |
507 | 652 | bank->reserved_map |= (1 << get_gpio_index(gpio)); |
653 | + | |
654 | + /* Set trigger to none. You need to enable the trigger after request_irq */ | |
655 | + _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE); | |
656 | + | |
508 | 657 | #ifdef CONFIG_ARCH_OMAP1510 |
509 | 658 | if (bank->method == METHOD_GPIO_1510) { |
510 | - u32 reg; | |
659 | + void __iomem *reg; | |
511 | 660 | |
512 | - /* Claim the pin for the ARM */ | |
661 | + /* Claim the pin for MPU */ | |
513 | 662 | reg = bank->base + OMAP1510_GPIO_PIN_CONTROL; |
514 | 663 | __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg); |
515 | 664 | } |
516 | 665 | #endif |
666 | +#ifdef CONFIG_ARCH_OMAP16XX | |
667 | + if (bank->method == METHOD_GPIO_1610) { | |
668 | + /* Enable wake-up during idle for dynamic tick */ | |
669 | + void __iomem *reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; | |
670 | + __raw_writel(1 << get_gpio_index(gpio), reg); | |
671 | + } | |
672 | +#endif | |
673 | +#ifdef CONFIG_ARCH_OMAP24XX | |
674 | + if (bank->method == METHOD_GPIO_24XX) { | |
675 | + /* Enable wake-up during idle for dynamic tick */ | |
676 | + void __iomem *reg = bank->base + OMAP24XX_GPIO_SETWKUENA; | |
677 | + __raw_writel(1 << get_gpio_index(gpio), reg); | |
678 | + } | |
679 | +#endif | |
517 | 680 | spin_unlock(&bank->lock); |
518 | 681 | |
519 | 682 | return 0; |
... | ... | @@ -533,6 +696,20 @@ |
533 | 696 | spin_unlock(&bank->lock); |
534 | 697 | return; |
535 | 698 | } |
699 | +#ifdef CONFIG_ARCH_OMAP16XX | |
700 | + if (bank->method == METHOD_GPIO_1610) { | |
701 | + /* Disable wake-up during idle for dynamic tick */ | |
702 | + void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; | |
703 | + __raw_writel(1 << get_gpio_index(gpio), reg); | |
704 | + } | |
705 | +#endif | |
706 | +#ifdef CONFIG_ARCH_OMAP24XX | |
707 | + if (bank->method == METHOD_GPIO_24XX) { | |
708 | + /* Disable wake-up during idle for dynamic tick */ | |
709 | + void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA; | |
710 | + __raw_writel(1 << get_gpio_index(gpio), reg); | |
711 | + } | |
712 | +#endif | |
536 | 713 | bank->reserved_map &= ~(1 << get_gpio_index(gpio)); |
537 | 714 | _set_gpio_direction(bank, get_gpio_index(gpio), 1); |
538 | 715 | _set_gpio_irqenable(bank, gpio, 0); |
... | ... | @@ -552,7 +729,7 @@ |
552 | 729 | static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, |
553 | 730 | struct pt_regs *regs) |
554 | 731 | { |
555 | - u32 isr_reg = 0; | |
732 | + void __iomem *isr_reg = NULL; | |
556 | 733 | u32 isr; |
557 | 734 | unsigned int gpio_irq; |
558 | 735 | struct gpio_bank *bank; |
559 | 736 | |
560 | 737 | |
561 | 738 | |
... | ... | @@ -574,24 +751,30 @@ |
574 | 751 | if (bank->method == METHOD_GPIO_730) |
575 | 752 | isr_reg = bank->base + OMAP730_GPIO_INT_STATUS; |
576 | 753 | #endif |
754 | +#ifdef CONFIG_ARCH_OMAP24XX | |
755 | + if (bank->method == METHOD_GPIO_24XX) | |
756 | + isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1; | |
757 | +#endif | |
577 | 758 | |
578 | - isr = __raw_readl(isr_reg); | |
579 | - _enable_gpio_irqbank(bank, isr, 0); | |
580 | - _clear_gpio_irqbank(bank, isr); | |
581 | - _enable_gpio_irqbank(bank, isr, 1); | |
582 | - desc->chip->unmask(irq); | |
759 | + while(1) { | |
760 | + isr = __raw_readl(isr_reg); | |
761 | + _enable_gpio_irqbank(bank, isr, 0); | |
762 | + _clear_gpio_irqbank(bank, isr); | |
763 | + _enable_gpio_irqbank(bank, isr, 1); | |
764 | + desc->chip->unmask(irq); | |
583 | 765 | |
584 | - if (unlikely(!isr)) | |
585 | - return; | |
766 | + if (!isr) | |
767 | + break; | |
586 | 768 | |
587 | - gpio_irq = bank->virtual_irq_start; | |
588 | - for (; isr != 0; isr >>= 1, gpio_irq++) { | |
589 | - struct irqdesc *d; | |
590 | - if (!(isr & 1)) | |
591 | - continue; | |
592 | - d = irq_desc + gpio_irq; | |
593 | - desc_handle_irq(gpio_irq, d, regs); | |
594 | - } | |
769 | + gpio_irq = bank->virtual_irq_start; | |
770 | + for (; isr != 0; isr >>= 1, gpio_irq++) { | |
771 | + struct irqdesc *d; | |
772 | + if (!(isr & 1)) | |
773 | + continue; | |
774 | + d = irq_desc + gpio_irq; | |
775 | + desc_handle_irq(gpio_irq, d, regs); | |
776 | + } | |
777 | + } | |
595 | 778 | } |
596 | 779 | |
597 | 780 | static void gpio_ack_irq(unsigned int irq) |
598 | 781 | |
... | ... | @@ -613,14 +796,10 @@ |
613 | 796 | static void gpio_unmask_irq(unsigned int irq) |
614 | 797 | { |
615 | 798 | unsigned int gpio = irq - IH_GPIO_BASE; |
799 | + unsigned int gpio_idx = get_gpio_index(gpio); | |
616 | 800 | struct gpio_bank *bank = get_gpio_bank(gpio); |
617 | 801 | |
618 | - if (_get_gpio_edge_ctrl(bank, get_gpio_index(gpio)) == OMAP_GPIO_NO_EDGE) { | |
619 | - printk(KERN_ERR "OMAP GPIO %d: trying to enable GPIO IRQ while no edge is set\n", | |
620 | - gpio); | |
621 | - _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE); | |
622 | - } | |
623 | - _set_gpio_irqenable(bank, gpio, 1); | |
802 | + _set_gpio_irqenable(bank, gpio_idx, 1); | |
624 | 803 | } |
625 | 804 | |
626 | 805 | static void mpuio_ack_irq(unsigned int irq) |
... | ... | @@ -645,9 +824,11 @@ |
645 | 824 | } |
646 | 825 | |
647 | 826 | static struct irqchip gpio_irq_chip = { |
648 | - .ack = gpio_ack_irq, | |
649 | - .mask = gpio_mask_irq, | |
650 | - .unmask = gpio_unmask_irq, | |
827 | + .ack = gpio_ack_irq, | |
828 | + .mask = gpio_mask_irq, | |
829 | + .unmask = gpio_unmask_irq, | |
830 | + .set_type = gpio_irq_type, | |
831 | + .set_wake = gpio_wake_enable, | |
651 | 832 | }; |
652 | 833 | |
653 | 834 | static struct irqchip mpuio_irq_chip = { |
... | ... | @@ -657,6 +838,7 @@ |
657 | 838 | }; |
658 | 839 | |
659 | 840 | static int initialized = 0; |
841 | +static struct clk * gpio_ck = NULL; | |
660 | 842 | |
661 | 843 | static int __init _omap_gpio_init(void) |
662 | 844 | { |
... | ... | @@ -665,6 +847,14 @@ |
665 | 847 | |
666 | 848 | initialized = 1; |
667 | 849 | |
850 | + if (cpu_is_omap1510()) { | |
851 | + gpio_ck = clk_get(NULL, "arm_gpio_ck"); | |
852 | + if (IS_ERR(gpio_ck)) | |
853 | + printk("Could not get arm_gpio_ck\n"); | |
854 | + else | |
855 | + clk_use(gpio_ck); | |
856 | + } | |
857 | + | |
668 | 858 | #ifdef CONFIG_ARCH_OMAP1510 |
669 | 859 | if (cpu_is_omap1510()) { |
670 | 860 | printk(KERN_INFO "OMAP1510 GPIO hardware\n"); |
... | ... | @@ -674,7 +864,7 @@ |
674 | 864 | #endif |
675 | 865 | #if defined(CONFIG_ARCH_OMAP16XX) |
676 | 866 | if (cpu_is_omap16xx()) { |
677 | - int rev; | |
867 | + u32 rev; | |
678 | 868 | |
679 | 869 | gpio_bank_count = 5; |
680 | 870 | gpio_bank = gpio_bank_1610; |
... | ... | @@ -690,6 +880,17 @@ |
690 | 880 | gpio_bank = gpio_bank_730; |
691 | 881 | } |
692 | 882 | #endif |
883 | +#ifdef CONFIG_ARCH_OMAP24XX | |
884 | + if (cpu_is_omap24xx()) { | |
885 | + int rev; | |
886 | + | |
887 | + gpio_bank_count = 4; | |
888 | + gpio_bank = gpio_bank_24xx; | |
889 | + rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION); | |
890 | + printk(KERN_INFO "OMAP24xx GPIO hardware version %d.%d\n", | |
891 | + (rev >> 4) & 0x0f, rev & 0x0f); | |
892 | + } | |
893 | +#endif | |
693 | 894 | for (i = 0; i < gpio_bank_count; i++) { |
694 | 895 | int j, gpio_count = 16; |
695 | 896 | |
... | ... | @@ -710,6 +911,7 @@ |
710 | 911 | if (bank->method == METHOD_GPIO_1610) { |
711 | 912 | __raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1); |
712 | 913 | __raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1); |
914 | + __raw_writew(0x0014, bank->base + OMAP1610_GPIO_SYSCONFIG); | |
713 | 915 | } |
714 | 916 | #endif |
715 | 917 | #ifdef CONFIG_ARCH_OMAP730 |
... | ... | @@ -720,6 +922,14 @@ |
720 | 922 | gpio_count = 32; /* 730 has 32-bit GPIOs */ |
721 | 923 | } |
722 | 924 | #endif |
925 | +#ifdef CONFIG_ARCH_OMAP24XX | |
926 | + if (bank->method == METHOD_GPIO_24XX) { | |
927 | + __raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1); | |
928 | + __raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1); | |
929 | + | |
930 | + gpio_count = 32; | |
931 | + } | |
932 | +#endif | |
723 | 933 | for (j = bank->virtual_irq_start; |
724 | 934 | j < bank->virtual_irq_start + gpio_count; j++) { |
725 | 935 | if (bank->method == METHOD_MPUIO) |
726 | 936 | |
... | ... | @@ -735,12 +945,97 @@ |
735 | 945 | |
736 | 946 | /* Enable system clock for GPIO module. |
737 | 947 | * The CAM_CLK_CTRL *is* really the right place. */ |
738 | - if (cpu_is_omap1610() || cpu_is_omap1710()) | |
948 | + if (cpu_is_omap16xx()) | |
739 | 949 | omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL); |
740 | 950 | |
741 | 951 | return 0; |
742 | 952 | } |
743 | 953 | |
954 | +#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX) | |
955 | +static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) | |
956 | +{ | |
957 | + int i; | |
958 | + | |
959 | + if (!cpu_is_omap24xx() && !cpu_is_omap16xx()) | |
960 | + return 0; | |
961 | + | |
962 | + for (i = 0; i < gpio_bank_count; i++) { | |
963 | + struct gpio_bank *bank = &gpio_bank[i]; | |
964 | + void __iomem *wake_status; | |
965 | + void __iomem *wake_clear; | |
966 | + void __iomem *wake_set; | |
967 | + | |
968 | + switch (bank->method) { | |
969 | + case METHOD_GPIO_1610: | |
970 | + wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE; | |
971 | + wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; | |
972 | + wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; | |
973 | + break; | |
974 | + case METHOD_GPIO_24XX: | |
975 | + wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA; | |
976 | + wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA; | |
977 | + wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA; | |
978 | + break; | |
979 | + default: | |
980 | + continue; | |
981 | + } | |
982 | + | |
983 | + spin_lock(&bank->lock); | |
984 | + bank->saved_wakeup = __raw_readl(wake_status); | |
985 | + __raw_writel(0xffffffff, wake_clear); | |
986 | + __raw_writel(bank->suspend_wakeup, wake_set); | |
987 | + spin_unlock(&bank->lock); | |
988 | + } | |
989 | + | |
990 | + return 0; | |
991 | +} | |
992 | + | |
993 | +static int omap_gpio_resume(struct sys_device *dev) | |
994 | +{ | |
995 | + int i; | |
996 | + | |
997 | + if (!cpu_is_omap24xx() && !cpu_is_omap16xx()) | |
998 | + return 0; | |
999 | + | |
1000 | + for (i = 0; i < gpio_bank_count; i++) { | |
1001 | + struct gpio_bank *bank = &gpio_bank[i]; | |
1002 | + void __iomem *wake_clear; | |
1003 | + void __iomem *wake_set; | |
1004 | + | |
1005 | + switch (bank->method) { | |
1006 | + case METHOD_GPIO_1610: | |
1007 | + wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; | |
1008 | + wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; | |
1009 | + break; | |
1010 | + case METHOD_GPIO_24XX: | |
1011 | + wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA; | |
1012 | + wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA; | |
1013 | + break; | |
1014 | + default: | |
1015 | + continue; | |
1016 | + } | |
1017 | + | |
1018 | + spin_lock(&bank->lock); | |
1019 | + __raw_writel(0xffffffff, wake_clear); | |
1020 | + __raw_writel(bank->saved_wakeup, wake_set); | |
1021 | + spin_unlock(&bank->lock); | |
1022 | + } | |
1023 | + | |
1024 | + return 0; | |
1025 | +} | |
1026 | + | |
1027 | +static struct sysdev_class omap_gpio_sysclass = { | |
1028 | + set_kset_name("gpio"), | |
1029 | + .suspend = omap_gpio_suspend, | |
1030 | + .resume = omap_gpio_resume, | |
1031 | +}; | |
1032 | + | |
1033 | +static struct sys_device omap_gpio_device = { | |
1034 | + .id = 0, | |
1035 | + .cls = &omap_gpio_sysclass, | |
1036 | +}; | |
1037 | +#endif | |
1038 | + | |
744 | 1039 | /* |
745 | 1040 | * This may get called early from board specific init |
746 | 1041 | */ |
747 | 1042 | |
748 | 1043 | |
... | ... | @@ -752,12 +1047,31 @@ |
752 | 1047 | return 0; |
753 | 1048 | } |
754 | 1049 | |
1050 | +static int __init omap_gpio_sysinit(void) | |
1051 | +{ | |
1052 | + int ret = 0; | |
1053 | + | |
1054 | + if (!initialized) | |
1055 | + ret = _omap_gpio_init(); | |
1056 | + | |
1057 | +#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) | |
1058 | + if (cpu_is_omap16xx() || cpu_is_omap24xx()) { | |
1059 | + if (ret == 0) { | |
1060 | + ret = sysdev_class_register(&omap_gpio_sysclass); | |
1061 | + if (ret == 0) | |
1062 | + ret = sysdev_register(&omap_gpio_device); | |
1063 | + } | |
1064 | + } | |
1065 | +#endif | |
1066 | + | |
1067 | + return ret; | |
1068 | +} | |
1069 | + | |
755 | 1070 | EXPORT_SYMBOL(omap_request_gpio); |
756 | 1071 | EXPORT_SYMBOL(omap_free_gpio); |
757 | 1072 | EXPORT_SYMBOL(omap_set_gpio_direction); |
758 | 1073 | EXPORT_SYMBOL(omap_set_gpio_dataout); |
759 | 1074 | EXPORT_SYMBOL(omap_get_gpio_datain); |
760 | -EXPORT_SYMBOL(omap_set_gpio_edge_ctrl); | |
761 | 1075 | |
762 | -arch_initcall(omap_gpio_init); | |
1076 | +arch_initcall(omap_gpio_sysinit); |
arch/arm/plat-omap/mcbsp.c
... | ... | @@ -27,6 +27,7 @@ |
27 | 27 | #include <asm/arch/dma.h> |
28 | 28 | #include <asm/arch/mux.h> |
29 | 29 | #include <asm/arch/irqs.h> |
30 | +#include <asm/arch/dsp_common.h> | |
30 | 31 | #include <asm/arch/mcbsp.h> |
31 | 32 | |
32 | 33 | #include <asm/hardware/clock.h> |
... | ... | @@ -187,9 +188,6 @@ |
187 | 188 | return -1; |
188 | 189 | } |
189 | 190 | |
190 | -#define EN_XORPCK 1 | |
191 | -#define DSP_RSTCT2 0xe1008014 | |
192 | - | |
193 | 191 | static void omap_mcbsp_dsp_request(void) |
194 | 192 | { |
195 | 193 | if (cpu_is_omap1510() || cpu_is_omap16xx()) { |
... | ... | @@ -198,6 +196,11 @@ |
198 | 196 | |
199 | 197 | /* enable 12MHz clock to mcbsp 1 & 3 */ |
200 | 198 | clk_use(mcbsp_dspxor_ck); |
199 | + | |
200 | + /* | |
201 | + * DSP external peripheral reset | |
202 | + * FIXME: This should be moved to dsp code | |
203 | + */ | |
201 | 204 | __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1, |
202 | 205 | DSP_RSTCT2); |
203 | 206 | } |
arch/arm/plat-omap/mux.c
arch/arm/plat-omap/ocpi.c
arch/arm/plat-omap/pm.c
... | ... | @@ -39,24 +39,32 @@ |
39 | 39 | #include <linux/sched.h> |
40 | 40 | #include <linux/proc_fs.h> |
41 | 41 | #include <linux/pm.h> |
42 | +#include <linux/interrupt.h> | |
42 | 43 | |
43 | 44 | #include <asm/io.h> |
45 | +#include <asm/irq.h> | |
44 | 46 | #include <asm/mach/time.h> |
45 | -#include <asm/mach-types.h> | |
47 | +#include <asm/mach/irq.h> | |
46 | 48 | |
47 | -#include <asm/arch/omap16xx.h> | |
49 | +#include <asm/mach-types.h> | |
50 | +#include <asm/arch/irqs.h> | |
51 | +#include <asm/arch/tc.h> | |
48 | 52 | #include <asm/arch/pm.h> |
49 | 53 | #include <asm/arch/mux.h> |
50 | -#include <asm/arch/tc.h> | |
51 | 54 | #include <asm/arch/tps65010.h> |
55 | +#include <asm/arch/dsp_common.h> | |
52 | 56 | |
53 | 57 | #include "clock.h" |
58 | +#include "sram.h" | |
54 | 59 | |
55 | 60 | static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE]; |
56 | 61 | static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE]; |
57 | 62 | static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE]; |
58 | 63 | static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; |
59 | 64 | |
65 | +static void (*omap_sram_idle)(void) = NULL; | |
66 | +static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL; | |
67 | + | |
60 | 68 | /* |
61 | 69 | * Let's power down on idle, but only if we are really |
62 | 70 | * idle, because once we start down the path of |
... | ... | @@ -65,7 +73,6 @@ |
65 | 73 | */ |
66 | 74 | void omap_pm_idle(void) |
67 | 75 | { |
68 | - int (*func_ptr)(void) = 0; | |
69 | 76 | unsigned int mask32 = 0; |
70 | 77 | |
71 | 78 | /* |
... | ... | @@ -84,6 +91,13 @@ |
84 | 91 | mask32 = omap_readl(ARM_SYSST); |
85 | 92 | |
86 | 93 | /* |
94 | + * Prevent the ULPD from entering low power state by setting | |
95 | + * POWER_CTRL_REG:4 = 0 | |
96 | + */ | |
97 | + omap_writew(omap_readw(ULPD_POWER_CTRL) & | |
98 | + ~ULPD_DEEP_SLEEP_TRANSITION_EN, ULPD_POWER_CTRL); | |
99 | + | |
100 | + /* | |
87 | 101 | * Since an interrupt may set up a timer, we don't want to |
88 | 102 | * reprogram the hardware timer with interrupts enabled. |
89 | 103 | * Re-enable interrupts only after returning from idle. |
90 | 104 | |
... | ... | @@ -92,18 +106,9 @@ |
92 | 106 | |
93 | 107 | if ((mask32 & DSP_IDLE) == 0) { |
94 | 108 | __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4"); |
95 | - } else { | |
109 | + } else | |
110 | + omap_sram_idle(); | |
96 | 111 | |
97 | - if (cpu_is_omap1510()) { | |
98 | - func_ptr = (void *)(OMAP1510_SRAM_IDLE_SUSPEND); | |
99 | - } else if (cpu_is_omap1610() || cpu_is_omap1710()) { | |
100 | - func_ptr = (void *)(OMAP1610_SRAM_IDLE_SUSPEND); | |
101 | - } else if (cpu_is_omap5912()) { | |
102 | - func_ptr = (void *)(OMAP5912_SRAM_IDLE_SUSPEND); | |
103 | - } | |
104 | - | |
105 | - func_ptr(); | |
106 | - } | |
107 | 112 | local_fiq_enable(); |
108 | 113 | local_irq_enable(); |
109 | 114 | } |
110 | 115 | |
111 | 116 | |
112 | 117 | |
113 | 118 | |
114 | 119 | |
115 | 120 | |
116 | 121 | |
117 | 122 | |
118 | 123 | |
119 | 124 | |
120 | 125 | |
121 | 126 | |
122 | 127 | |
123 | 128 | |
124 | 129 | |
... | ... | @@ -115,58 +120,55 @@ |
115 | 120 | */ |
116 | 121 | static void omap_pm_wakeup_setup(void) |
117 | 122 | { |
118 | - /* | |
119 | - * Enable ARM XOR clock and release peripheral from reset by | |
120 | - * writing 1 to PER_EN bit in ARM_RSTCT2, this is required | |
121 | - * for UART configuration to use UART2 to wake up. | |
122 | - */ | |
123 | + u32 level1_wake = OMAP_IRQ_BIT(INT_IH2_IRQ); | |
124 | + u32 level2_wake = OMAP_IRQ_BIT(INT_UART2) | OMAP_IRQ_BIT(INT_KEYBOARD); | |
123 | 125 | |
124 | - omap_writel(omap_readl(ARM_IDLECT2) | ENABLE_XORCLK, ARM_IDLECT2); | |
125 | - omap_writel(omap_readl(ARM_RSTCT2) | PER_EN, ARM_RSTCT2); | |
126 | - omap_writew(MODEM_32K_EN, ULPD_CLOCK_CTRL); | |
127 | - | |
128 | 126 | /* |
129 | - * Turn off all interrupts except L1-2nd level cascade, | |
130 | - * and the L2 wakeup interrupts: keypad and UART2. | |
127 | + * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade, | |
128 | + * and the L2 wakeup interrupts: keypad and UART2. Note that the | |
129 | + * drivers must still separately call omap_set_gpio_wakeup() to | |
130 | + * wake up to a GPIO interrupt. | |
131 | 131 | */ |
132 | + if (cpu_is_omap1510() || cpu_is_omap16xx()) | |
133 | + level1_wake |= OMAP_IRQ_BIT(INT_GPIO_BANK1); | |
134 | + else if (cpu_is_omap730()) | |
135 | + level1_wake |= OMAP_IRQ_BIT(INT_730_GPIO_BANK1); | |
132 | 136 | |
133 | - omap_writel(~IRQ_LEVEL2, OMAP_IH1_MIR); | |
137 | + omap_writel(~level1_wake, OMAP_IH1_MIR); | |
134 | 138 | |
135 | - if (cpu_is_omap1510()) { | |
136 | - omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_MIR); | |
137 | - } | |
139 | + if (cpu_is_omap1510()) | |
140 | + omap_writel(~level2_wake, OMAP_IH2_MIR); | |
138 | 141 | |
142 | + /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */ | |
139 | 143 | if (cpu_is_omap16xx()) { |
140 | - omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_0_MIR); | |
141 | - | |
142 | - omap_writel(~0x0, OMAP_IH2_1_MIR); | |
144 | + omap_writel(~level2_wake, OMAP_IH2_0_MIR); | |
145 | + omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR); | |
143 | 146 | omap_writel(~0x0, OMAP_IH2_2_MIR); |
144 | 147 | omap_writel(~0x0, OMAP_IH2_3_MIR); |
145 | 148 | } |
146 | 149 | |
147 | - /* New IRQ agreement */ | |
150 | + /* New IRQ agreement, recalculate in cascade order */ | |
151 | + omap_writel(1, OMAP_IH2_CONTROL); | |
148 | 152 | omap_writel(1, OMAP_IH1_CONTROL); |
149 | - | |
150 | - /* external PULL to down, bit 22 = 0 */ | |
151 | - omap_writel(omap_readl(PULL_DWN_CTRL_2) & ~(1<<22), PULL_DWN_CTRL_2); | |
152 | 153 | } |
153 | 154 | |
154 | 155 | void omap_pm_suspend(void) |
155 | 156 | { |
156 | - unsigned int mask32 = 0; | |
157 | 157 | unsigned long arg0 = 0, arg1 = 0; |
158 | - int (*func_ptr)(unsigned short, unsigned short) = 0; | |
159 | - unsigned short save_dsp_idlect2; | |
160 | 158 | |
161 | - printk("PM: OMAP%x is entering deep sleep now ...\n", system_rev); | |
159 | + printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev); | |
162 | 160 | |
161 | + omap_serial_wake_trigger(1); | |
162 | + | |
163 | 163 | if (machine_is_omap_osk()) { |
164 | 164 | /* Stop LED1 (D9) blink */ |
165 | 165 | tps65010_set_led(LED1, OFF); |
166 | 166 | } |
167 | 167 | |
168 | + omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG); | |
169 | + | |
168 | 170 | /* |
169 | - * Step 1: turn off interrupts | |
171 | + * Step 1: turn off interrupts (FIXME: NOTE: already disabled) | |
170 | 172 | */ |
171 | 173 | |
172 | 174 | local_irq_disable(); |
... | ... | @@ -207,6 +209,8 @@ |
207 | 209 | ARM_SAVE(ARM_CKCTL); |
208 | 210 | ARM_SAVE(ARM_IDLECT1); |
209 | 211 | ARM_SAVE(ARM_IDLECT2); |
212 | + if (!(cpu_is_omap1510())) | |
213 | + ARM_SAVE(ARM_IDLECT3); | |
210 | 214 | ARM_SAVE(ARM_EWUPCT); |
211 | 215 | ARM_SAVE(ARM_RSTCT1); |
212 | 216 | ARM_SAVE(ARM_RSTCT2); |
213 | 217 | |
214 | 218 | |
215 | 219 | |
... | ... | @@ -214,43 +218,13 @@ |
214 | 218 | ULPD_SAVE(ULPD_CLOCK_CTRL); |
215 | 219 | ULPD_SAVE(ULPD_STATUS_REQ); |
216 | 220 | |
217 | - /* | |
218 | - * Step 3: LOW_PWR signal enabling | |
219 | - * | |
220 | - * Allow the LOW_PWR signal to be visible on MPUIO5 ball. | |
221 | - */ | |
222 | - if (cpu_is_omap1510()) { | |
223 | - /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */ | |
224 | - omap_writew(omap_readw(ULPD_POWER_CTRL) | | |
225 | - OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL); | |
226 | - } else if (cpu_is_omap16xx()) { | |
227 | - /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */ | |
228 | - omap_writew(omap_readw(ULPD_POWER_CTRL) | | |
229 | - OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL); | |
230 | - } | |
221 | + /* (Step 3 removed - we now allow deep sleep by default) */ | |
231 | 222 | |
232 | - /* configure LOW_PWR pin */ | |
233 | - omap_cfg_reg(T20_1610_LOW_PWR); | |
234 | - | |
235 | 223 | /* |
236 | 224 | * Step 4: OMAP DSP Shutdown |
237 | 225 | */ |
238 | 226 | |
239 | - /* Set DSP_RST = 1 and DSP_EN = 0, put DSP block into reset */ | |
240 | - omap_writel((omap_readl(ARM_RSTCT1) | DSP_RST) & ~DSP_ENABLE, | |
241 | - ARM_RSTCT1); | |
242 | 227 | |
243 | - /* Set DSP boot mode to DSP-IDLE, DSP_BOOT_MODE = 0x2 */ | |
244 | - omap_writel(DSP_IDLE_MODE, MPUI_DSP_BOOT_CONFIG); | |
245 | - | |
246 | - /* Set EN_DSPCK = 0, stop DSP block clock */ | |
247 | - omap_writel(omap_readl(ARM_CKCTL) & ~DSP_CLOCK_ENABLE, ARM_CKCTL); | |
248 | - | |
249 | - /* Stop any DSP domain clocks */ | |
250 | - omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2); | |
251 | - save_dsp_idlect2 = __raw_readw(DSP_IDLECT2); | |
252 | - __raw_writew(0, DSP_IDLECT2); | |
253 | - | |
254 | 228 | /* |
255 | 229 | * Step 5: Wakeup Event Setup |
256 | 230 | */ |
257 | 231 | |
... | ... | @@ -258,24 +232,9 @@ |
258 | 232 | omap_pm_wakeup_setup(); |
259 | 233 | |
260 | 234 | /* |
261 | - * Step 6a: ARM and Traffic controller shutdown | |
262 | - * | |
263 | - * Step 6 starts here with clock and watchdog disable | |
235 | + * Step 6: ARM and Traffic controller shutdown | |
264 | 236 | */ |
265 | 237 | |
266 | - /* stop clocks */ | |
267 | - mask32 = omap_readl(ARM_IDLECT2); | |
268 | - mask32 &= ~(1<<EN_WDTCK); /* bit 0 -> 0 (WDT clock) */ | |
269 | - mask32 |= (1<<EN_XORPCK); /* bit 1 -> 1 (XORPCK clock) */ | |
270 | - mask32 &= ~(1<<EN_PERCK); /* bit 2 -> 0 (MPUPER_CK clock) */ | |
271 | - mask32 &= ~(1<<EN_LCDCK); /* bit 3 -> 0 (LCDC clock) */ | |
272 | - mask32 &= ~(1<<EN_LBCK); /* bit 4 -> 0 (local bus clock) */ | |
273 | - mask32 |= (1<<EN_APICK); /* bit 6 -> 1 (MPUI clock) */ | |
274 | - mask32 &= ~(1<<EN_TIMCK); /* bit 7 -> 0 (MPU timer clock) */ | |
275 | - mask32 &= ~(1<<DMACK_REQ); /* bit 8 -> 0 (DMAC clock) */ | |
276 | - mask32 &= ~(1<<EN_GPIOCK); /* bit 9 -> 0 (GPIO clock) */ | |
277 | - omap_writel(mask32, ARM_IDLECT2); | |
278 | - | |
279 | 238 | /* disable ARM watchdog */ |
280 | 239 | omap_writel(0x00F5, OMAP_WDT_TIMER_MODE); |
281 | 240 | omap_writel(0x00A0, OMAP_WDT_TIMER_MODE); |
282 | 241 | |
283 | 242 | |
284 | 243 | |
285 | 244 | |
... | ... | @@ -295,47 +254,24 @@ |
295 | 254 | arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1]; |
296 | 255 | arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2]; |
297 | 256 | |
298 | - if (cpu_is_omap1510()) { | |
299 | - func_ptr = (void *)(OMAP1510_SRAM_API_SUSPEND); | |
300 | - } else if (cpu_is_omap1610() || cpu_is_omap1710()) { | |
301 | - func_ptr = (void *)(OMAP1610_SRAM_API_SUSPEND); | |
302 | - } else if (cpu_is_omap5912()) { | |
303 | - func_ptr = (void *)(OMAP5912_SRAM_API_SUSPEND); | |
304 | - } | |
305 | - | |
306 | 257 | /* |
307 | 258 | * Step 6c: ARM and Traffic controller shutdown |
308 | 259 | * |
309 | 260 | * Jump to assembly code. The processor will stay there |
310 | 261 | * until wake up. |
311 | 262 | */ |
263 | + omap_sram_suspend(arg0, arg1); | |
312 | 264 | |
313 | - func_ptr(arg0, arg1); | |
314 | - | |
315 | 265 | /* |
316 | 266 | * If we are here, processor is woken up! |
317 | 267 | */ |
318 | 268 | |
319 | - if (cpu_is_omap1510()) { | |
320 | - /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */ | |
321 | - omap_writew(omap_readw(ULPD_POWER_CTRL) & | |
322 | - ~OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL); | |
323 | - } else if (cpu_is_omap16xx()) { | |
324 | - /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */ | |
325 | - omap_writew(omap_readw(ULPD_POWER_CTRL) & | |
326 | - ~OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL); | |
327 | - } | |
328 | - | |
329 | - | |
330 | - /* Restore DSP clocks */ | |
331 | - omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2); | |
332 | - __raw_writew(save_dsp_idlect2, DSP_IDLECT2); | |
333 | - ARM_RESTORE(ARM_IDLECT2); | |
334 | - | |
335 | 269 | /* |
336 | 270 | * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did |
337 | 271 | */ |
338 | 272 | |
273 | + if (!(cpu_is_omap1510())) | |
274 | + ARM_RESTORE(ARM_IDLECT3); | |
339 | 275 | ARM_RESTORE(ARM_CKCTL); |
340 | 276 | ARM_RESTORE(ARM_EWUPCT); |
341 | 277 | ARM_RESTORE(ARM_RSTCT1); |
... | ... | @@ -366,6 +302,8 @@ |
366 | 302 | MPUI1610_RESTORE(OMAP_IH2_3_MIR); |
367 | 303 | } |
368 | 304 | |
305 | + omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG); | |
306 | + | |
369 | 307 | /* |
370 | 308 | * Reenable interrupts |
371 | 309 | */ |
... | ... | @@ -373,6 +311,8 @@ |
373 | 311 | local_irq_enable(); |
374 | 312 | local_fiq_enable(); |
375 | 313 | |
314 | + omap_serial_wake_trigger(0); | |
315 | + | |
376 | 316 | printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev); |
377 | 317 | |
378 | 318 | if (machine_is_omap_osk()) { |
... | ... | @@ -401,6 +341,8 @@ |
401 | 341 | ARM_SAVE(ARM_CKCTL); |
402 | 342 | ARM_SAVE(ARM_IDLECT1); |
403 | 343 | ARM_SAVE(ARM_IDLECT2); |
344 | + if (!(cpu_is_omap1510())) | |
345 | + ARM_SAVE(ARM_IDLECT3); | |
404 | 346 | ARM_SAVE(ARM_EWUPCT); |
405 | 347 | ARM_SAVE(ARM_RSTCT1); |
406 | 348 | ARM_SAVE(ARM_RSTCT2); |
... | ... | @@ -436,6 +378,7 @@ |
436 | 378 | "ARM_CKCTL_REG: 0x%-8x \n" |
437 | 379 | "ARM_IDLECT1_REG: 0x%-8x \n" |
438 | 380 | "ARM_IDLECT2_REG: 0x%-8x \n" |
381 | + "ARM_IDLECT3_REG: 0x%-8x \n" | |
439 | 382 | "ARM_EWUPCT_REG: 0x%-8x \n" |
440 | 383 | "ARM_RSTCT1_REG: 0x%-8x \n" |
441 | 384 | "ARM_RSTCT2_REG: 0x%-8x \n" |
... | ... | @@ -449,6 +392,7 @@ |
449 | 392 | ARM_SHOW(ARM_CKCTL), |
450 | 393 | ARM_SHOW(ARM_IDLECT1), |
451 | 394 | ARM_SHOW(ARM_IDLECT2), |
395 | + ARM_SHOW(ARM_IDLECT3), | |
452 | 396 | ARM_SHOW(ARM_EWUPCT), |
453 | 397 | ARM_SHOW(ARM_RSTCT1), |
454 | 398 | ARM_SHOW(ARM_RSTCT2), |
... | ... | @@ -507,7 +451,7 @@ |
507 | 451 | |
508 | 452 | entry = create_proc_read_entry("driver/omap_pm", |
509 | 453 | S_IWUSR | S_IRUGO, NULL, |
510 | - omap_pm_read_proc, 0); | |
454 | + omap_pm_read_proc, NULL); | |
511 | 455 | } |
512 | 456 | |
513 | 457 | #endif /* DEBUG && CONFIG_PROC_FS */ |
... | ... | @@ -580,7 +524,21 @@ |
580 | 524 | } |
581 | 525 | |
582 | 526 | |
583 | -struct pm_ops omap_pm_ops ={ | |
527 | +static irqreturn_t omap_wakeup_interrupt(int irq, void * dev, | |
528 | + struct pt_regs * regs) | |
529 | +{ | |
530 | + return IRQ_HANDLED; | |
531 | +} | |
532 | + | |
533 | +static struct irqaction omap_wakeup_irq = { | |
534 | + .name = "peripheral wakeup", | |
535 | + .flags = SA_INTERRUPT, | |
536 | + .handler = omap_wakeup_interrupt | |
537 | +}; | |
538 | + | |
539 | + | |
540 | + | |
541 | +static struct pm_ops omap_pm_ops ={ | |
584 | 542 | .pm_disk_mode = 0, |
585 | 543 | .prepare = omap_pm_prepare, |
586 | 544 | .enter = omap_pm_enter, |
587 | 545 | |
588 | 546 | |
589 | 547 | |
590 | 548 | |
... | ... | @@ -590,41 +548,60 @@ |
590 | 548 | static int __init omap_pm_init(void) |
591 | 549 | { |
592 | 550 | printk("Power Management for TI OMAP.\n"); |
593 | - pm_idle = omap_pm_idle; | |
594 | 551 | /* |
595 | 552 | * We copy the assembler sleep/wakeup routines to SRAM. |
596 | 553 | * These routines need to be in SRAM as that's the only |
597 | 554 | * memory the MPU can see when it wakes up. |
598 | 555 | */ |
599 | - | |
600 | -#ifdef CONFIG_ARCH_OMAP1510 | |
601 | 556 | if (cpu_is_omap1510()) { |
602 | - memcpy((void *)OMAP1510_SRAM_IDLE_SUSPEND, | |
603 | - omap1510_idle_loop_suspend, | |
604 | - omap1510_idle_loop_suspend_sz); | |
605 | - memcpy((void *)OMAP1510_SRAM_API_SUSPEND, omap1510_cpu_suspend, | |
606 | - omap1510_cpu_suspend_sz); | |
607 | - } else | |
608 | -#endif | |
609 | - if (cpu_is_omap1610() || cpu_is_omap1710()) { | |
610 | - memcpy((void *)OMAP1610_SRAM_IDLE_SUSPEND, | |
611 | - omap1610_idle_loop_suspend, | |
612 | - omap1610_idle_loop_suspend_sz); | |
613 | - memcpy((void *)OMAP1610_SRAM_API_SUSPEND, omap1610_cpu_suspend, | |
614 | - omap1610_cpu_suspend_sz); | |
615 | - } else if (cpu_is_omap5912()) { | |
616 | - memcpy((void *)OMAP5912_SRAM_IDLE_SUSPEND, | |
617 | - omap1610_idle_loop_suspend, | |
618 | - omap1610_idle_loop_suspend_sz); | |
619 | - memcpy((void *)OMAP5912_SRAM_API_SUSPEND, omap1610_cpu_suspend, | |
620 | - omap1610_cpu_suspend_sz); | |
557 | + omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend, | |
558 | + omap1510_idle_loop_suspend_sz); | |
559 | + omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend, | |
560 | + omap1510_cpu_suspend_sz); | |
561 | + } else if (cpu_is_omap16xx()) { | |
562 | + omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend, | |
563 | + omap1610_idle_loop_suspend_sz); | |
564 | + omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend, | |
565 | + omap1610_cpu_suspend_sz); | |
621 | 566 | } |
622 | 567 | |
568 | + if (omap_sram_idle == NULL || omap_sram_suspend == NULL) { | |
569 | + printk(KERN_ERR "PM not initialized: Missing SRAM support\n"); | |
570 | + return -ENODEV; | |
571 | + } | |
572 | + | |
573 | + pm_idle = omap_pm_idle; | |
574 | + | |
575 | + setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq); | |
576 | +#if 0 | |
577 | + /* --- BEGIN BOARD-DEPENDENT CODE --- */ | |
578 | + /* Sleepx mask direction */ | |
579 | + omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008); | |
580 | + /* Unmask sleepx signal */ | |
581 | + omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004); | |
582 | + /* --- END BOARD-DEPENDENT CODE --- */ | |
583 | +#endif | |
584 | + | |
585 | + /* Program new power ramp-up time | |
586 | + * (0 for most boards since we don't lower voltage when in deep sleep) | |
587 | + */ | |
588 | + omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3); | |
589 | + | |
590 | + /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */ | |
591 | + omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL); | |
592 | + | |
593 | + /* Configure IDLECT3 */ | |
594 | + if (cpu_is_omap16xx()) | |
595 | + omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3); | |
596 | + | |
623 | 597 | pm_set_ops(&omap_pm_ops); |
624 | 598 | |
625 | 599 | #if defined(DEBUG) && defined(CONFIG_PROC_FS) |
626 | 600 | omap_pm_init_proc(); |
627 | 601 | #endif |
602 | + | |
603 | + /* configure LOW_PWR pin */ | |
604 | + omap_cfg_reg(T20_1610_LOW_PWR); | |
628 | 605 | |
629 | 606 | return 0; |
630 | 607 | } |
arch/arm/plat-omap/sleep.S
... | ... | @@ -66,7 +66,7 @@ |
66 | 66 | @ get ARM_IDLECT2 into r2 |
67 | 67 | ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
68 | 68 | mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff |
69 | - orr r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | |
69 | + orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | |
70 | 70 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
71 | 71 | |
72 | 72 | @ request ARM idle |
... | ... | @@ -76,7 +76,7 @@ |
76 | 76 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
77 | 77 | |
78 | 78 | mov r5, #IDLE_WAIT_CYCLES & 0xff |
79 | - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
79 | + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
80 | 80 | l_1510: subs r5, r5, #1 |
81 | 81 | bne l_1510 |
82 | 82 | /* |
... | ... | @@ -96,7 +96,7 @@ |
96 | 96 | strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
97 | 97 | strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
98 | 98 | |
99 | - ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
99 | + ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
100 | 100 | |
101 | 101 | ENTRY(omap1510_idle_loop_suspend_sz) |
102 | 102 | .word . - omap1510_idle_loop_suspend |
... | ... | @@ -115,8 +115,8 @@ |
115 | 115 | @ turn off clock domains |
116 | 116 | @ get ARM_IDLECT2 into r2 |
117 | 117 | ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
118 | - mov r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff | |
119 | - orr r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00 | |
118 | + mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff | |
119 | + orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | |
120 | 120 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
121 | 121 | |
122 | 122 | @ request ARM idle |
... | ... | @@ -126,7 +126,7 @@ |
126 | 126 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
127 | 127 | |
128 | 128 | mov r5, #IDLE_WAIT_CYCLES & 0xff |
129 | - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
129 | + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
130 | 130 | l_1610: subs r5, r5, #1 |
131 | 131 | bne l_1610 |
132 | 132 | /* |
... | ... | @@ -146,7 +146,7 @@ |
146 | 146 | strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
147 | 147 | strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
148 | 148 | |
149 | - ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
149 | + ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
150 | 150 | |
151 | 151 | ENTRY(omap1610_idle_loop_suspend_sz) |
152 | 152 | .word . - omap1610_idle_loop_suspend |
... | ... | @@ -208,7 +208,7 @@ |
208 | 208 | |
209 | 209 | @ turn off clock domains |
210 | 210 | mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff |
211 | - orr r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | |
211 | + orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | |
212 | 212 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
213 | 213 | |
214 | 214 | @ request ARM idle |
... | ... | @@ -217,7 +217,7 @@ |
217 | 217 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
218 | 218 | |
219 | 219 | mov r5, #IDLE_WAIT_CYCLES & 0xff |
220 | - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
220 | + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
221 | 221 | l_1510_2: |
222 | 222 | subs r5, r5, #1 |
223 | 223 | bne l_1510_2 |
... | ... | @@ -237,7 +237,7 @@ |
237 | 237 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
238 | 238 | |
239 | 239 | @ restore regs and return |
240 | - ldmfd sp!, {r0 - r12, pc} | |
240 | + ldmfd sp!, {r0 - r12, pc} | |
241 | 241 | |
242 | 242 | ENTRY(omap1510_cpu_suspend_sz) |
243 | 243 | .word . - omap1510_cpu_suspend |
244 | 244 | |
245 | 245 | |
246 | 246 | |
... | ... | @@ -249,21 +249,26 @@ |
249 | 249 | @ save registers on stack |
250 | 250 | stmfd sp!, {r0 - r12, lr} |
251 | 251 | |
252 | + @ Drain write cache | |
253 | + mov r4, #0 | |
254 | + mcr p15, 0, r0, c7, c10, 4 | |
255 | + nop | |
256 | + | |
252 | 257 | @ load base address of Traffic Controller |
253 | - mov r4, #TCMIF_ASM_BASE & 0xff000000 | |
254 | - orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 | |
255 | - orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 | |
258 | + mov r6, #TCMIF_ASM_BASE & 0xff000000 | |
259 | + orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | |
260 | + orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | |
256 | 261 | |
257 | 262 | @ prepare to put SDRAM into self-refresh manually |
258 | - ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
259 | - orr r5, r5, #SELF_REFRESH_MODE & 0xff000000 | |
260 | - orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff | |
261 | - str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
263 | + ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
264 | + orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | |
265 | + orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | |
266 | + str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
262 | 267 | |
263 | 268 | @ prepare to put EMIFS to Sleep |
264 | - ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
265 | - orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff | |
266 | - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
269 | + ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
270 | + orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | |
271 | + str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
267 | 272 | |
268 | 273 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 |
269 | 274 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 |
270 | 275 | |
271 | 276 | |
272 | 277 | |
... | ... | @@ -271,26 +276,22 @@ |
271 | 276 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 |
272 | 277 | |
273 | 278 | @ turn off clock domains |
274 | - mov r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff | |
275 | - orr r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00 | |
279 | + @ do not disable PERCK (0x04) | |
280 | + mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff | |
281 | + orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | |
276 | 282 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
277 | 283 | |
278 | - @ work around errata of OMAP1610/5912. Enable (!) peripheral | |
279 | - @ clock to let the chip go into deep sleep | |
280 | - ldrh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
281 | - orr r5,r5, #EN_PERCK_BIT & 0xff | |
282 | - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
283 | - | |
284 | 284 | @ request ARM idle |
285 | - mov r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff | |
286 | - orr r3, r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff00 | |
285 | + mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff | |
286 | + orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 | |
287 | 287 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
288 | 288 | |
289 | - mov r5, #IDLE_WAIT_CYCLES & 0xff | |
290 | - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
291 | -l_1610_2: | |
292 | - subs r5, r5, #1 | |
293 | - bne l_1610_2 | |
289 | + @ disable instruction cache | |
290 | + mrc p15, 0, r9, c1, c0, 0 | |
291 | + bic r2, r9, #0x1000 | |
292 | + mcr p15, 0, r2, c1, c0, 0 | |
293 | + nop | |
294 | + | |
294 | 295 | /* |
295 | 296 | * Let's wait for the next wake up event to wake us up. r0 can't be |
296 | 297 | * used here because r0 holds ARM_IDLECT1 |
297 | 298 | |
298 | 299 | |
299 | 300 | |
... | ... | @@ -301,13 +302,21 @@ |
301 | 302 | * omap1610_cpu_suspend()'s resume point. |
302 | 303 | * |
303 | 304 | * It will just start executing here, so we'll restore stuff from the |
304 | - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
305 | + * stack. | |
305 | 306 | */ |
307 | + @ re-enable Icache | |
308 | + mcr p15, 0, r9, c1, c0, 0 | |
309 | + | |
310 | + @ reset the ARM_IDLECT1 and ARM_IDLECT2. | |
306 | 311 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
307 | 312 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
308 | 313 | |
314 | + @ Restore EMIFF controls | |
315 | + str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
316 | + str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
317 | + | |
309 | 318 | @ restore regs and return |
310 | - ldmfd sp!, {r0 - r12, pc} | |
319 | + ldmfd sp!, {r0 - r12, pc} | |
311 | 320 | |
312 | 321 | ENTRY(omap1610_cpu_suspend_sz) |
313 | 322 | .word . - omap1610_cpu_suspend |
arch/arm/plat-omap/sram-fn.S
1 | +/* | |
2 | + * linux/arch/arm/plat-omap/sram.S | |
3 | + * | |
4 | + * Functions that need to be run in internal SRAM | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License version 2 as | |
8 | + * published by the Free Software Foundation. | |
9 | + */ | |
10 | + | |
11 | +#include <linux/config.h> | |
12 | +#include <linux/linkage.h> | |
13 | +#include <asm/assembler.h> | |
14 | +#include <asm/arch/io.h> | |
15 | +#include <asm/arch/hardware.h> | |
16 | + | |
17 | + .text | |
18 | + | |
19 | +/* | |
20 | + * Reprograms ULPD and CKCTL. | |
21 | + */ | |
22 | +ENTRY(sram_reprogram_clock) | |
23 | + stmfd sp!, {r0 - r12, lr} @ save registers on stack | |
24 | + | |
25 | + mov r2, #IO_ADDRESS(DPLL_CTL) & 0xff000000 | |
26 | + orr r2, r2, #IO_ADDRESS(DPLL_CTL) & 0x00ff0000 | |
27 | + orr r2, r2, #IO_ADDRESS(DPLL_CTL) & 0x0000ff00 | |
28 | + | |
29 | + mov r3, #IO_ADDRESS(ARM_CKCTL) & 0xff000000 | |
30 | + orr r3, r3, #IO_ADDRESS(ARM_CKCTL) & 0x00ff0000 | |
31 | + orr r3, r3, #IO_ADDRESS(ARM_CKCTL) & 0x0000ff00 | |
32 | + | |
33 | + tst r0, #1 << 4 @ want lock mode? | |
34 | + beq newck @ nope | |
35 | + bic r0, r0, #1 << 4 @ else clear lock bit | |
36 | + strh r0, [r2] @ set dpll into bypass mode | |
37 | + orr r0, r0, #1 << 4 @ set lock bit again | |
38 | + | |
39 | +newck: | |
40 | + strh r1, [r3] @ write new ckctl value | |
41 | + strh r0, [r2] @ write new dpll value | |
42 | + | |
43 | + mov r4, #0x0700 @ let the clocks settle | |
44 | + orr r4, r4, #0x00ff | |
45 | +delay: sub r4, r4, #1 | |
46 | + cmp r4, #0 | |
47 | + bne delay | |
48 | + | |
49 | +lock: ldrh r4, [r2], #0 @ read back dpll value | |
50 | + tst r0, #1 << 4 @ want lock mode? | |
51 | + beq out @ nope | |
52 | + tst r4, #1 << 0 @ dpll rate locked? | |
53 | + beq lock @ try again | |
54 | + | |
55 | +out: | |
56 | + ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
57 | +ENTRY(sram_reprogram_clock_sz) | |
58 | + .word . - sram_reprogram_clock |
arch/arm/plat-omap/sram.c
1 | +/* | |
2 | + * linux/arch/arm/plat-omap/sram.c | |
3 | + * | |
4 | + * OMAP SRAM detection and management | |
5 | + * | |
6 | + * Copyright (C) 2005 Nokia Corporation | |
7 | + * Written by Tony Lindgren <tony@atomide.com> | |
8 | + * | |
9 | + * This program is free software; you can redistribute it and/or modify | |
10 | + * it under the terms of the GNU General Public License version 2 as | |
11 | + * published by the Free Software Foundation. | |
12 | + */ | |
13 | + | |
14 | +#include <linux/config.h> | |
15 | +#include <linux/module.h> | |
16 | +#include <linux/kernel.h> | |
17 | +#include <linux/init.h> | |
18 | + | |
19 | +#include <asm/mach/map.h> | |
20 | +#include <asm/io.h> | |
21 | +#include <asm/cacheflush.h> | |
22 | + | |
23 | +#include "sram.h" | |
24 | + | |
25 | +#define OMAP1_SRAM_BASE 0xd0000000 | |
26 | +#define OMAP1_SRAM_START 0x20000000 | |
27 | +#define SRAM_BOOTLOADER_SZ 0x80 | |
28 | + | |
29 | +static unsigned long omap_sram_base; | |
30 | +static unsigned long omap_sram_size; | |
31 | +static unsigned long omap_sram_ceil; | |
32 | + | |
33 | +/* | |
34 | + * The amount of SRAM depends on the core type: | |
35 | + * 730 = 200K, 1510 = 512K, 5912 = 256K, 1610 = 16K, 1710 = 16K | |
36 | + * Note that we cannot try to test for SRAM here because writes | |
37 | + * to secure SRAM will hang the system. Also the SRAM is not | |
38 | + * yet mapped at this point. | |
39 | + */ | |
40 | +void __init omap_detect_sram(void) | |
41 | +{ | |
42 | + omap_sram_base = OMAP1_SRAM_BASE; | |
43 | + | |
44 | + if (cpu_is_omap730()) | |
45 | + omap_sram_size = 0x32000; | |
46 | + else if (cpu_is_omap1510()) | |
47 | + omap_sram_size = 0x80000; | |
48 | + else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710()) | |
49 | + omap_sram_size = 0x4000; | |
50 | + else if (cpu_is_omap1611()) | |
51 | + omap_sram_size = 0x3e800; | |
52 | + else { | |
53 | + printk(KERN_ERR "Could not detect SRAM size\n"); | |
54 | + omap_sram_size = 0x4000; | |
55 | + } | |
56 | + | |
57 | + printk(KERN_INFO "SRAM size: 0x%lx\n", omap_sram_size); | |
58 | + omap_sram_ceil = omap_sram_base + omap_sram_size; | |
59 | +} | |
60 | + | |
61 | +static struct map_desc omap_sram_io_desc[] __initdata = { | |
62 | + { OMAP1_SRAM_BASE, OMAP1_SRAM_START, 0, MT_DEVICE } | |
63 | +}; | |
64 | + | |
65 | +/* | |
66 | + * In order to use last 2kB of SRAM on 1611b, we must round the size | |
67 | + * up to multiple of PAGE_SIZE. We cannot use ioremap for SRAM, as | |
68 | + * clock init needs SRAM early. | |
69 | + */ | |
70 | +void __init omap_map_sram(void) | |
71 | +{ | |
72 | + if (omap_sram_size == 0) | |
73 | + return; | |
74 | + | |
75 | + omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE; | |
76 | + omap_sram_io_desc[0].length *= PAGE_SIZE; | |
77 | + iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc)); | |
78 | + | |
79 | + /* | |
80 | + * Looks like we need to preserve some bootloader code at the | |
81 | + * beginning of SRAM for jumping to flash for reboot to work... | |
82 | + */ | |
83 | + memset((void *)omap_sram_base + SRAM_BOOTLOADER_SZ, 0, | |
84 | + omap_sram_size - SRAM_BOOTLOADER_SZ); | |
85 | +} | |
86 | + | |
87 | +static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl) = NULL; | |
88 | + | |
89 | +void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl) | |
90 | +{ | |
91 | + if (_omap_sram_reprogram_clock == NULL) | |
92 | + panic("Cannot use SRAM"); | |
93 | + | |
94 | + return _omap_sram_reprogram_clock(dpllctl, ckctl); | |
95 | +} | |
96 | + | |
97 | +void * omap_sram_push(void * start, unsigned long size) | |
98 | +{ | |
99 | + if (size > (omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ))) { | |
100 | + printk(KERN_ERR "Not enough space in SRAM\n"); | |
101 | + return NULL; | |
102 | + } | |
103 | + omap_sram_ceil -= size; | |
104 | + omap_sram_ceil &= ~0x3; | |
105 | + memcpy((void *)omap_sram_ceil, start, size); | |
106 | + | |
107 | + return (void *)omap_sram_ceil; | |
108 | +} | |
109 | + | |
110 | +void __init omap_sram_init(void) | |
111 | +{ | |
112 | + omap_detect_sram(); | |
113 | + omap_map_sram(); | |
114 | + _omap_sram_reprogram_clock = omap_sram_push(sram_reprogram_clock, | |
115 | + sram_reprogram_clock_sz); | |
116 | +} |
arch/arm/plat-omap/sram.h
1 | +/* | |
2 | + * linux/arch/arm/plat-omap/sram.h | |
3 | + * | |
4 | + * Interface for functions that need to be run in internal SRAM | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License version 2 as | |
8 | + * published by the Free Software Foundation. | |
9 | + */ | |
10 | + | |
11 | +#ifndef __ARCH_ARM_OMAP_SRAM_H | |
12 | +#define __ARCH_ARM_OMAP_SRAM_H | |
13 | + | |
14 | +extern void * omap_sram_push(void * start, unsigned long size); | |
15 | +extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl); | |
16 | + | |
17 | +/* Do not use these */ | |
18 | +extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl); | |
19 | +extern unsigned long sram_reprogram_clock_sz; | |
20 | + | |
21 | +#endif |
arch/arm/plat-omap/usb.c
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 | |
42 | 42 | /* These routines should handle the standard chip-specific modes |
43 | 43 | * for usb0/1/2 ports, covering basic mux and transceiver setup. |
44 | + * Call omap_usb_init() once, from INIT_MACHINE(). | |
44 | 45 | * |
45 | 46 | * Some board-*.c files will need to set up additional mux options, |
46 | 47 | * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup. |