aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-msm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-msm')
-rw-r--r--arch/arm/mach-msm/Kconfig18
-rw-r--r--arch/arm/mach-msm/Makefile7
-rw-r--r--arch/arm/mach-msm/Makefile.boot3
-rw-r--r--arch/arm/mach-msm/board-halibut.c114
-rw-r--r--arch/arm/mach-msm/common.c116
-rw-r--r--arch/arm/mach-msm/dma.c214
-rw-r--r--arch/arm/mach-msm/idle.S36
-rw-r--r--arch/arm/mach-msm/io.c85
-rw-r--r--arch/arm/mach-msm/irq.c154
-rw-r--r--arch/arm/mach-msm/timer.c205
10 files changed, 952 insertions, 0 deletions
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
new file mode 100644
index 000000000000..3553babbbf05
--- /dev/null
+++ b/arch/arm/mach-msm/Kconfig
@@ -0,0 +1,18 @@
1if ARCH_MSM7X00A
2
3comment "MSM7X00A Board Type"
4 depends on ARCH_MSM7X00A
5
6config MACH_HALIBUT
7 depends on ARCH_MSM7X00A
8 default y
9 bool "Halibut Board (QCT SURF7200A)"
10 help
11 Support for the Qualcomm SURF7200A eval board.
12
13config MSM7X00A_IDLE
14 depends on ARCH_MSM7X00A
15 default y
16 bool "Idle Support for MSM7X00A"
17
18endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
new file mode 100644
index 000000000000..d12f23655850
--- /dev/null
+++ b/arch/arm/mach-msm/Makefile
@@ -0,0 +1,7 @@
1obj-y += io.o idle.o irq.o timer.o dma.o
2
3# Common code for board init
4obj-y += common.o
5
6obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
7
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
new file mode 100644
index 000000000000..24dfbf8c07c4
--- /dev/null
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -0,0 +1,3 @@
1 zreladdr-y := 0x10008000
2params_phys-y := 0x10000100
3initrd_phys-y := 0x10800000
diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
new file mode 100644
index 000000000000..86dfb2b5261c
--- /dev/null
+++ b/arch/arm/mach-msm/board-halibut.c
@@ -0,0 +1,114 @@
1/* linux/arch/arm/mach-msm/board-halibut.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Author: Brian Swetland <swetland@google.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/platform_device.h>
20#include <linux/input.h>
21
22#include <asm/hardware.h>
23#include <asm/mach-types.h>
24#include <asm/mach/arch.h>
25#include <asm/mach/map.h>
26#include <asm/mach/flash.h>
27
28#include <asm/arch/board.h>
29#include <asm/arch/msm_iomap.h>
30
31#include <asm/io.h>
32#include <asm/delay.h>
33
34#include <linux/mtd/nand.h>
35#include <linux/mtd/partitions.h>
36
37static struct resource smc91x_resources[] = {
38 [0] = {
39 .start = 0x9C004300,
40 .end = 0x9C004400,
41 .flags = IORESOURCE_MEM,
42 },
43 [1] = {
44 .start = MSM_GPIO_TO_INT(49),
45 .end = MSM_GPIO_TO_INT(49),
46 .flags = IORESOURCE_IRQ,
47 },
48};
49
50static struct platform_device smc91x_device = {
51 .name = "smc91x",
52 .id = 0,
53 .num_resources = ARRAY_SIZE(smc91x_resources),
54 .resource = smc91x_resources,
55};
56
57static void mddi0_panel_power(int on)
58{
59}
60
61static struct msm_mddi_platform_data msm_mddi0_pdata = {
62 .panel_power = mddi0_panel_power,
63 .has_vsync_irq = 0,
64};
65
66static struct platform_device msm_mddi0_device = {
67 .name = "msm_mddi",
68 .id = 0,
69 .dev = {
70 .platform_data = &msm_mddi0_pdata
71 },
72};
73
74static struct platform_device msm_serial0_device = {
75 .name = "msm_serial",
76 .id = 0,
77};
78
79static struct platform_device *devices[] __initdata = {
80 &msm_serial0_device,
81 &msm_mddi0_device,
82 &smc91x_device,
83};
84
85extern struct sys_timer msm_timer;
86
87static void __init halibut_init_irq(void)
88{
89 msm_init_irq();
90}
91
92static void __init halibut_init(void)
93{
94 platform_add_devices(devices, ARRAY_SIZE(devices));
95 msm_add_devices();
96}
97
98static void __init halibut_map_io(void)
99{
100 msm_map_common_io();
101}
102
103MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
104
105/* UART for LL DEBUG */
106 .phys_io = MSM_UART1_PHYS,
107 .io_pg_offst = ((MSM_UART1_BASE) >> 18) & 0xfffc,
108
109 .boot_params = 0x10000100,
110 .map_io = halibut_map_io,
111 .init_irq = halibut_init_irq,
112 .init_machine = halibut_init,
113 .timer = &msm_timer,
114MACHINE_END
diff --git a/arch/arm/mach-msm/common.c b/arch/arm/mach-msm/common.c
new file mode 100644
index 000000000000..3f5d3362f887
--- /dev/null
+++ b/arch/arm/mach-msm/common.c
@@ -0,0 +1,116 @@
1/* linux/arch/arm/mach-msm/common.c
2 *
3 * Common setup code for MSM7K Boards
4 *
5 * Copyright (C) 2007 Google, Inc.
6 * Author: Brian Swetland <swetland@google.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/platform_device.h>
22
23#include <asm/mach/flash.h>
24#include <asm/io.h>
25
26#include <asm/setup.h>
27
28#include <linux/mtd/nand.h>
29#include <linux/mtd/partitions.h>
30
31#include <asm/arch/msm_iomap.h>
32
33#include <asm/arch/board.h>
34
35struct flash_platform_data msm_nand_data = {
36 .parts = 0,
37 .nr_parts = 0,
38};
39
40static struct resource msm_nand_resources[] = {
41 [0] = {
42 .start = 7,
43 .end = 7,
44 .flags = IORESOURCE_DMA,
45 },
46};
47
48static struct platform_device msm_nand_device = {
49 .name = "msm_nand",
50 .id = -1,
51 .num_resources = ARRAY_SIZE(msm_nand_resources),
52 .resource = msm_nand_resources,
53 .dev = {
54 .platform_data = &msm_nand_data,
55 },
56};
57
58static struct platform_device msm_smd_device = {
59 .name = "msm_smd",
60 .id = -1,
61};
62
63static struct resource msm_i2c_resources[] = {
64 {
65 .start = MSM_I2C_BASE,
66 .end = MSM_I2C_BASE + MSM_I2C_SIZE - 1,
67 .flags = IORESOURCE_MEM,
68 },
69 {
70 .start = INT_PWB_I2C,
71 .end = INT_PWB_I2C,
72 .flags = IORESOURCE_IRQ,
73 },
74};
75
76static struct platform_device msm_i2c_device = {
77 .name = "msm_i2c",
78 .id = 0,
79 .num_resources = ARRAY_SIZE(msm_i2c_resources),
80 .resource = msm_i2c_resources,
81};
82
83static struct resource usb_resources[] = {
84 {
85 .start = MSM_HSUSB_PHYS,
86 .end = MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
87 .flags = IORESOURCE_MEM,
88 },
89 {
90 .start = INT_USB_HS,
91 .end = INT_USB_HS,
92 .flags = IORESOURCE_IRQ,
93 },
94};
95
96static struct platform_device msm_hsusb_device = {
97 .name = "msm_hsusb",
98 .id = -1,
99 .num_resources = ARRAY_SIZE(usb_resources),
100 .resource = usb_resources,
101 .dev = {
102 .coherent_dma_mask = 0xffffffff,
103 },
104};
105
106static struct platform_device *devices[] __initdata = {
107 &msm_nand_device,
108 &msm_smd_device,
109 &msm_i2c_device,
110 &msm_hsusb_device,
111};
112
113void __init msm_add_devices(void)
114{
115 platform_add_devices(devices, ARRAY_SIZE(devices));
116}
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
new file mode 100644
index 000000000000..8b0f339b3274
--- /dev/null
+++ b/arch/arm/mach-msm/dma.c
@@ -0,0 +1,214 @@
1/* linux/arch/arm/mach-msm/dma.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <asm/io.h>
17#include <linux/interrupt.h>
18#include <asm/arch/dma.h>
19
20#define MSM_DMOV_CHANNEL_COUNT 16
21
22enum {
23 MSM_DMOV_PRINT_ERRORS = 1,
24 MSM_DMOV_PRINT_IO = 2,
25 MSM_DMOV_PRINT_FLOW = 4
26};
27
28static DEFINE_SPINLOCK(msm_dmov_lock);
29static struct msm_dmov_cmd active_command;
30static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
31static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
32unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS;
33
34#define MSM_DMOV_DPRINTF(mask, format, args...) \
35 do { \
36 if ((mask) & msm_dmov_print_mask) \
37 printk(KERN_ERR format, args); \
38 } while (0)
39#define PRINT_ERROR(format, args...) \
40 MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_ERRORS, format, args);
41#define PRINT_IO(format, args...) \
42 MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_IO, format, args);
43#define PRINT_FLOW(format, args...) \
44 MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
45
46void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
47{
48 unsigned long irq_flags;
49 unsigned int status;
50
51 spin_lock_irqsave(&msm_dmov_lock, irq_flags);
52 status = readl(DMOV_STATUS(id));
53 if (list_empty(&ready_commands[id]) &&
54 (status & DMOV_STATUS_CMD_PTR_RDY)) {
55#if 0
56 if (list_empty(&active_commands[id])) {
57 PRINT_FLOW("msm_dmov_enqueue_cmd(%d), enable interrupt\n", id);
58 writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id));
59 }
60#endif
61 PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status);
62 list_add_tail(&cmd->list, &active_commands[id]);
63 writel(cmd->cmdptr, DMOV_CMD_PTR(id));
64 } else {
65 if (list_empty(&active_commands[id]))
66 PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status);
67
68 PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status %x\n", id, status);
69 list_add_tail(&cmd->list, &ready_commands[id]);
70 }
71 spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
72}
73
74struct msm_dmov_exec_cmdptr_cmd {
75 struct msm_dmov_cmd dmov_cmd;
76 struct completion complete;
77 unsigned id;
78 unsigned int result;
79 unsigned int flush[6];
80};
81
82static void dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, unsigned int result)
83{
84 struct msm_dmov_exec_cmdptr_cmd *cmd = container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd);
85 cmd->result = result;
86 if (result != 0x80000002) {
87 cmd->flush[0] = readl(DMOV_FLUSH0(cmd->id));
88 cmd->flush[1] = readl(DMOV_FLUSH1(cmd->id));
89 cmd->flush[2] = readl(DMOV_FLUSH2(cmd->id));
90 cmd->flush[3] = readl(DMOV_FLUSH3(cmd->id));
91 cmd->flush[4] = readl(DMOV_FLUSH4(cmd->id));
92 cmd->flush[5] = readl(DMOV_FLUSH5(cmd->id));
93 }
94 complete(&cmd->complete);
95}
96
97int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr)
98{
99 struct msm_dmov_exec_cmdptr_cmd cmd;
100
101 PRINT_FLOW("dmov_exec_cmdptr(%d, %x)\n", id, cmdptr);
102
103 cmd.dmov_cmd.cmdptr = cmdptr;
104 cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func;
105 cmd.id = id;
106 init_completion(&cmd.complete);
107
108 msm_dmov_enqueue_cmd(id, &cmd.dmov_cmd);
109 wait_for_completion(&cmd.complete);
110
111 if (cmd.result != 0x80000002) {
112 PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result);
113 PRINT_ERROR("dmov_exec_cmdptr(%d): flush: %x %x %x %x\n",
114 id, cmd.flush[0], cmd.flush[1], cmd.flush[2], cmd.flush[3]);
115 return -EIO;
116 }
117 PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr);
118 return 0;
119}
120
121
122static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
123{
124 unsigned int int_status, mask, id;
125 unsigned long irq_flags;
126 unsigned int ch_status;
127 unsigned int ch_result;
128 struct msm_dmov_cmd *cmd;
129
130 spin_lock_irqsave(&msm_dmov_lock, irq_flags);
131
132 int_status = readl(DMOV_ISR); /* read and clear interrupt */
133 PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
134
135 while (int_status) {
136 mask = int_status & -int_status;
137 id = fls(mask) - 1;
138 PRINT_FLOW("msm_datamover_irq_handler %08x %08x id %d\n", int_status, mask, id);
139 int_status &= ~mask;
140 ch_status = readl(DMOV_STATUS(id));
141 if (!(ch_status & DMOV_STATUS_RSLT_VALID)) {
142 PRINT_FLOW("msm_datamover_irq_handler id %d, result not valid %x\n", id, ch_status);
143 continue;
144 }
145 do {
146 ch_result = readl(DMOV_RSLT(id));
147 if (list_empty(&active_commands[id])) {
148 PRINT_ERROR("msm_datamover_irq_handler id %d, got result "
149 "with no active command, status %x, result %x\n",
150 id, ch_status, ch_result);
151 cmd = NULL;
152 } else
153 cmd = list_entry(active_commands[id].next, typeof(*cmd), list);
154 PRINT_FLOW("msm_datamover_irq_handler id %d, status %x, result %x\n", id, ch_status, ch_result);
155 if (ch_result & DMOV_RSLT_DONE) {
156 PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n",
157 id, ch_status);
158 PRINT_IO("msm_datamover_irq_handler id %d, got result "
159 "for %p, result %x\n", id, cmd, ch_result);
160 if (cmd) {
161 list_del(&cmd->list);
162 cmd->complete_func(cmd, ch_result);
163 }
164 }
165 if (ch_result & DMOV_RSLT_FLUSH) {
166 unsigned int flush0 = readl(DMOV_FLUSH0(id));
167 PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
168 PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, flush0);
169 if (cmd) {
170 list_del(&cmd->list);
171 cmd->complete_func(cmd, ch_result);
172 }
173 }
174 if (ch_result & DMOV_RSLT_ERROR) {
175 unsigned int flush0 = readl(DMOV_FLUSH0(id));
176 PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
177 PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, flush0);
178 if (cmd) {
179 list_del(&cmd->list);
180 cmd->complete_func(cmd, ch_result);
181 }
182 /* this does not seem to work, once we get an error */
183 /* the datamover will no longer accept commands */
184 writel(0, DMOV_FLUSH0(id));
185 }
186 ch_status = readl(DMOV_STATUS(id));
187 PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
188 if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) && !list_empty(&ready_commands[id])) {
189 cmd = list_entry(ready_commands[id].next, typeof(*cmd), list);
190 list_del(&cmd->list);
191 list_add_tail(&cmd->list, &active_commands[id]);
192 PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id);
193 writel(cmd->cmdptr, DMOV_CMD_PTR(id));
194 }
195 } while (ch_status & DMOV_STATUS_RSLT_VALID);
196 PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
197 }
198 spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
199 return IRQ_HANDLED;
200}
201
202static int __init msm_init_datamover(void)
203{
204 int i;
205 for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
206 INIT_LIST_HEAD(&ready_commands[i]);
207 INIT_LIST_HEAD(&active_commands[i]);
208 writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i));
209 }
210 return request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL);
211}
212
213arch_initcall(msm_init_datamover);
214
diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S
new file mode 100644
index 000000000000..2b1cb7f16943
--- /dev/null
+++ b/arch/arm/mach-msm/idle.S
@@ -0,0 +1,36 @@
1/* linux/include/asm-arm/arch-msm/idle.S
2 *
3 * Idle processing for MSM7K - work around bugs with SWFI.
4 *
5 * Copyright (c) 2007 QUALCOMM Incorporated.
6 * Copyright (C) 2007 Google, Inc.
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/linkage.h>
20#include <asm/assembler.h>
21
22ENTRY(arch_idle)
23#ifdef CONFIG_MSM7X00A_IDLE
24 mrc p15, 0, r1, c1, c0, 0 /* read current CR */
25 bic r0, r1, #(1 << 2) /* clear dcache bit */
26 bic r0, r0, #(1 << 12) /* clear icache bit */
27 mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
28
29 mov r0, #0 /* prepare wfi value */
30 mcr p15, 0, r0, c7, c10, 0 /* flush the cache */
31 mcr p15, 0, r0, c7, c10, 4 /* memory barrier */
32 mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */
33
34 mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */
35#endif
36 mov pc, lr
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
new file mode 100644
index 000000000000..c39edb994a88
--- /dev/null
+++ b/arch/arm/mach-msm/io.c
@@ -0,0 +1,85 @@
1/* arch/arm/mach-msm/io.c
2 *
3 * MSM7K io support
4 *
5 * Copyright (C) 2007 Google, Inc.
6 * Author: Brian Swetland <swetland@google.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/init.h>
21
22#include <asm/hardware.h>
23#include <asm/io.h>
24#include <asm/page.h>
25#include <asm/arch/msm_iomap.h>
26#include <asm/mach/map.h>
27
28#include <asm/arch/board.h>
29
30#define MSM_DEVICE(name) { \
31 .virtual = MSM_##name##_BASE, \
32 .pfn = __phys_to_pfn(MSM_##name##_PHYS), \
33 .length = MSM_##name##_SIZE, \
34 .type = MT_DEVICE_NONSHARED, \
35 }
36
37static struct map_desc msm_io_desc[] __initdata = {
38 MSM_DEVICE(VIC),
39 MSM_DEVICE(CSR),
40 MSM_DEVICE(GPT),
41 MSM_DEVICE(DMOV),
42 MSM_DEVICE(UART1),
43 MSM_DEVICE(UART2),
44 MSM_DEVICE(UART3),
45 MSM_DEVICE(I2C),
46 MSM_DEVICE(GPIO1),
47 MSM_DEVICE(GPIO2),
48 MSM_DEVICE(HSUSB),
49 MSM_DEVICE(CLK_CTL),
50 MSM_DEVICE(PMDH),
51 MSM_DEVICE(EMDH),
52 MSM_DEVICE(MDP),
53 {
54 .virtual = MSM_SHARED_RAM_BASE,
55 .pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS),
56 .length = MSM_SHARED_RAM_SIZE,
57 .type = MT_DEVICE,
58 },
59};
60
61void __init msm_map_common_io(void)
62{
63 /* Make sure the peripheral register window is closed, since
64 * we will use PTE flags (TEX[1]=1,B=0,C=1) to determine which
65 * pages are peripheral interface or not.
66 */
67 asm("mcr p15, 0, %0, c15, c2, 4" : : "r" (0));
68
69 iotable_init(msm_io_desc, ARRAY_SIZE(msm_io_desc));
70}
71
72void __iomem *
73__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
74{
75 if (mtype == MT_DEVICE) {
76 /* The peripherals in the 88000000 - D0000000 range
77 * are only accessable by type MT_DEVICE_NONSHARED.
78 * Adjust mtype as necessary to make this "just work."
79 */
80 if ((phys_addr >= 0x88000000) && (phys_addr < 0xD0000000))
81 mtype = MT_DEVICE_NONSHARED;
82 }
83
84 return __arm_ioremap(phys_addr, size, mtype);
85}
diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c
new file mode 100644
index 000000000000..24158040b789
--- /dev/null
+++ b/arch/arm/mach-msm/irq.c
@@ -0,0 +1,154 @@
1/* linux/arch/arm/mach-msm/irq.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/sched.h>
19#include <linux/interrupt.h>
20#include <linux/ptrace.h>
21#include <linux/timer.h>
22
23#include <linux/irq.h>
24#include <asm/hardware.h>
25
26#include <asm/io.h>
27
28#include <asm/arch/msm_iomap.h>
29
30#define VIC_REG(off) (MSM_VIC_BASE + (off))
31
32#define VIC_INT_SELECT0 VIC_REG(0x0000) /* 1: FIQ, 0: IRQ */
33#define VIC_INT_SELECT1 VIC_REG(0x0004) /* 1: FIQ, 0: IRQ */
34#define VIC_INT_EN0 VIC_REG(0x0010)
35#define VIC_INT_EN1 VIC_REG(0x0014)
36#define VIC_INT_ENCLEAR0 VIC_REG(0x0020)
37#define VIC_INT_ENCLEAR1 VIC_REG(0x0024)
38#define VIC_INT_ENSET0 VIC_REG(0x0030)
39#define VIC_INT_ENSET1 VIC_REG(0x0034)
40#define VIC_INT_TYPE0 VIC_REG(0x0040) /* 1: EDGE, 0: LEVEL */
41#define VIC_INT_TYPE1 VIC_REG(0x0044) /* 1: EDGE, 0: LEVEL */
42#define VIC_INT_POLARITY0 VIC_REG(0x0050) /* 1: NEG, 0: POS */
43#define VIC_INT_POLARITY1 VIC_REG(0x0054) /* 1: NEG, 0: POS */
44#define VIC_NO_PEND_VAL VIC_REG(0x0060)
45#define VIC_INT_MASTEREN VIC_REG(0x0064) /* 1: IRQ, 2: FIQ */
46#define VIC_PROTECTION VIC_REG(0x006C) /* 1: ENABLE */
47#define VIC_CONFIG VIC_REG(0x0068) /* 1: USE ARM1136 VIC */
48#define VIC_IRQ_STATUS0 VIC_REG(0x0080)
49#define VIC_IRQ_STATUS1 VIC_REG(0x0084)
50#define VIC_FIQ_STATUS0 VIC_REG(0x0090)
51#define VIC_FIQ_STATUS1 VIC_REG(0x0094)
52#define VIC_RAW_STATUS0 VIC_REG(0x00A0)
53#define VIC_RAW_STATUS1 VIC_REG(0x00A4)
54#define VIC_INT_CLEAR0 VIC_REG(0x00B0)
55#define VIC_INT_CLEAR1 VIC_REG(0x00B4)
56#define VIC_SOFTINT0 VIC_REG(0x00C0)
57#define VIC_SOFTINT1 VIC_REG(0x00C4)
58#define VIC_IRQ_VEC_RD VIC_REG(0x00D0) /* pending int # */
59#define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4) /* pending vector addr */
60#define VIC_IRQ_VEC_WR VIC_REG(0x00D8)
61#define VIC_IRQ_IN_SERVICE VIC_REG(0x00E0)
62#define VIC_IRQ_IN_STACK VIC_REG(0x00E4)
63#define VIC_TEST_BUS_SEL VIC_REG(0x00E8)
64
65#define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
66#define VIC_VECTADDR(n) VIC_REG(0x0400+((n) * 4))
67
68static void msm_irq_ack(unsigned int irq)
69{
70 unsigned reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0);
71 irq = 1 << (irq & 31);
72 writel(irq, reg);
73}
74
75static void msm_irq_mask(unsigned int irq)
76{
77 unsigned reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0);
78 writel(1 << (irq & 31), reg);
79}
80
81static void msm_irq_unmask(unsigned int irq)
82{
83 unsigned reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0);
84 writel(1 << (irq & 31), reg);
85}
86
87static int msm_irq_set_wake(unsigned int irq, unsigned int on)
88{
89 return -EINVAL;
90}
91
92static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
93{
94 unsigned treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0);
95 unsigned preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0);
96 int b = 1 << (irq & 31);
97
98 if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
99 writel(readl(preg) | b, preg);
100 if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
101 writel(readl(preg) & (~b), preg);
102
103 if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
104 writel(readl(treg) | b, treg);
105 set_irq_handler(irq, handle_edge_irq);
106 }
107 if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
108 writel(readl(treg) & (~b), treg);
109 set_irq_handler(irq, handle_level_irq);
110 }
111 return 0;
112}
113
114static struct irq_chip msm_irq_chip = {
115 .name = "msm",
116 .ack = msm_irq_ack,
117 .mask = msm_irq_mask,
118 .unmask = msm_irq_unmask,
119 .set_wake = msm_irq_set_wake,
120 .set_type = msm_irq_set_type,
121};
122
123void __init msm_init_irq(void)
124{
125 unsigned n;
126
127 /* select level interrupts */
128 writel(0, VIC_INT_TYPE0);
129 writel(0, VIC_INT_TYPE1);
130
131 /* select highlevel interrupts */
132 writel(0, VIC_INT_POLARITY0);
133 writel(0, VIC_INT_POLARITY1);
134
135 /* select IRQ for all INTs */
136 writel(0, VIC_INT_SELECT0);
137 writel(0, VIC_INT_SELECT1);
138
139 /* disable all INTs */
140 writel(0, VIC_INT_EN0);
141 writel(0, VIC_INT_EN1);
142
143 /* don't use 1136 vic */
144 writel(0, VIC_CONFIG);
145
146 /* enable interrupt controller */
147 writel(1, VIC_INT_MASTEREN);
148
149 for (n = 0; n < NR_MSM_IRQS; n++) {
150 set_irq_chip(n, &msm_irq_chip);
151 set_irq_handler(n, handle_level_irq);
152 set_irq_flags(n, IRQF_VALID);
153 }
154}
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
new file mode 100644
index 000000000000..bd4732d1ab3e
--- /dev/null
+++ b/arch/arm/mach-msm/timer.c
@@ -0,0 +1,205 @@
1/* linux/arch/arm/mach-msm/timer.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/init.h>
17#include <linux/time.h>
18#include <linux/interrupt.h>
19#include <linux/irq.h>
20#include <linux/clk.h>
21#include <linux/clockchips.h>
22#include <linux/delay.h>
23
24#include <asm/mach/time.h>
25#include <asm/arch/msm_iomap.h>
26
27#include <asm/io.h>
28
29#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
30#define MSM_DGT_SHIFT (5)
31
32#define TIMER_MATCH_VAL 0x0000
33#define TIMER_COUNT_VAL 0x0004
34#define TIMER_ENABLE 0x0008
35#define TIMER_ENABLE_CLR_ON_MATCH_EN 2
36#define TIMER_ENABLE_EN 1
37#define TIMER_CLEAR 0x000C
38
39#define CSR_PROTECTION 0x0020
40#define CSR_PROTECTION_EN 1
41
42#define GPT_HZ 32768
43#define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
44
45struct msm_clock {
46 struct clock_event_device clockevent;
47 struct clocksource clocksource;
48 struct irqaction irq;
49 uint32_t regbase;
50 uint32_t freq;
51 uint32_t shift;
52};
53
54static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
55{
56 struct clock_event_device *evt = dev_id;
57 evt->event_handler(evt);
58 return IRQ_HANDLED;
59}
60
61static cycle_t msm_gpt_read(void)
62{
63 return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
64}
65
66static cycle_t msm_dgt_read(void)
67{
68 return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
69}
70
71static int msm_timer_set_next_event(unsigned long cycles,
72 struct clock_event_device *evt)
73{
74 struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
75 uint32_t now = readl(clock->regbase + TIMER_COUNT_VAL);
76 uint32_t alarm = now + (cycles << clock->shift);
77 int late;
78
79 writel(alarm, clock->regbase + TIMER_MATCH_VAL);
80 now = readl(clock->regbase + TIMER_COUNT_VAL);
81 late = now - alarm;
82 if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
83 printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
84 "alarm already expired, now %x, alarm %x, late %d\n",
85 cycles, clock->clockevent.name, now, alarm, late);
86 return -ETIME;
87 }
88 return 0;
89}
90
91static void msm_timer_set_mode(enum clock_event_mode mode,
92 struct clock_event_device *evt)
93{
94 struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
95 switch (mode) {
96 case CLOCK_EVT_MODE_RESUME:
97 case CLOCK_EVT_MODE_PERIODIC:
98 break;
99 case CLOCK_EVT_MODE_ONESHOT:
100 writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
101 break;
102 case CLOCK_EVT_MODE_UNUSED:
103 case CLOCK_EVT_MODE_SHUTDOWN:
104 writel(0, clock->regbase + TIMER_ENABLE);
105 break;
106 }
107}
108
109static struct msm_clock msm_clocks[] = {
110 {
111 .clockevent = {
112 .name = "gp_timer",
113 .features = CLOCK_EVT_FEAT_ONESHOT,
114 .shift = 32,
115 .rating = 200,
116 .set_next_event = msm_timer_set_next_event,
117 .set_mode = msm_timer_set_mode,
118 },
119 .clocksource = {
120 .name = "gp_timer",
121 .rating = 200,
122 .read = msm_gpt_read,
123 .mask = CLOCKSOURCE_MASK(32),
124 .shift = 24,
125 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
126 },
127 .irq = {
128 .name = "gp_timer",
129 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
130 .handler = msm_timer_interrupt,
131 .dev_id = &msm_clocks[0].clockevent,
132 .irq = INT_GP_TIMER_EXP
133 },
134 .regbase = MSM_GPT_BASE,
135 .freq = GPT_HZ
136 },
137 {
138 .clockevent = {
139 .name = "dg_timer",
140 .features = CLOCK_EVT_FEAT_ONESHOT,
141 .shift = 32 + MSM_DGT_SHIFT,
142 .rating = 300,
143 .set_next_event = msm_timer_set_next_event,
144 .set_mode = msm_timer_set_mode,
145 },
146 .clocksource = {
147 .name = "dg_timer",
148 .rating = 300,
149 .read = msm_dgt_read,
150 .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
151 .shift = 24 - MSM_DGT_SHIFT,
152 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
153 },
154 .irq = {
155 .name = "dg_timer",
156 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
157 .handler = msm_timer_interrupt,
158 .dev_id = &msm_clocks[1].clockevent,
159 .irq = INT_DEBUG_TIMER_EXP
160 },
161 .regbase = MSM_DGT_BASE,
162 .freq = DGT_HZ >> MSM_DGT_SHIFT,
163 .shift = MSM_DGT_SHIFT
164 }
165};
166
167static void __init msm_timer_init(void)
168{
169 int i;
170 int res;
171
172 for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) {
173 struct msm_clock *clock = &msm_clocks[i];
174 struct clock_event_device *ce = &clock->clockevent;
175 struct clocksource *cs = &clock->clocksource;
176 writel(0, clock->regbase + TIMER_ENABLE);
177 writel(0, clock->regbase + TIMER_CLEAR);
178 writel(~0, clock->regbase + TIMER_MATCH_VAL);
179
180 ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
181 /* allow at least 10 seconds to notice that the timer wrapped */
182 ce->max_delta_ns =
183 clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
184 /* 4 gets rounded down to 3 */
185 ce->min_delta_ns = clockevent_delta2ns(4, ce);
186 ce->cpumask = cpumask_of_cpu(0);
187
188 cs->mult = clocksource_hz2mult(clock->freq, cs->shift);
189 res = clocksource_register(cs);
190 if (res)
191 printk(KERN_ERR "msm_timer_init: clocksource_register "
192 "failed for %s\n", cs->name);
193
194 res = setup_irq(clock->irq.irq, &clock->irq);
195 if (res)
196 printk(KERN_ERR "msm_timer_init: setup_irq "
197 "failed for %s\n", cs->name);
198
199 clockevents_register_device(ce);
200 }
201}
202
203struct sys_timer msm_timer = {
204 .init = msm_timer_init
205};