aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel
diff options
context:
space:
mode:
authorBryan Wu <bryan.wu@analog.com>2007-05-06 17:50:22 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:12:58 -0400
commit1394f03221790a988afc3e4b3cb79f2e477246a9 (patch)
tree2c1963c9a4f2d84a5e021307fde240c5d567cf70 /arch/blackfin/kernel
parent73243284463a761e04d69d22c7516b2be7de096c (diff)
blackfin architecture
This adds support for the Analog Devices Blackfin processor architecture, and currently supports the BF533, BF532, BF531, BF537, BF536, BF534, and BF561 (Dual Core) devices, with a variety of development platforms including those avaliable from Analog Devices (BF533-EZKit, BF533-STAMP, BF537-STAMP, BF561-EZKIT), and Bluetechnix! Tinyboards. The Blackfin architecture was jointly developed by Intel and Analog Devices Inc. (ADI) as the Micro Signal Architecture (MSA) core and introduced it in December of 2000. Since then ADI has put this core into its Blackfin processor family of devices. The Blackfin core has the advantages of a clean, orthogonal,RISC-like microprocessor instruction set. It combines a dual-MAC (Multiply/Accumulate), state-of-the-art signal processing engine and single-instruction, multiple-data (SIMD) multimedia capabilities into a single instruction-set architecture. The Blackfin architecture, including the instruction set, is described by the ADSP-BF53x/BF56x Blackfin Processor Programming Reference http://blackfin.uclinux.org/gf/download/frsrelease/29/2549/Blackfin_PRM.pdf The Blackfin processor is already supported by major releases of gcc, and there are binary and source rpms/tarballs for many architectures at: http://blackfin.uclinux.org/gf/project/toolchain/frs There is complete documentation, including "getting started" guides available at: http://docs.blackfin.uclinux.org/ which provides links to the sources and patches you will need in order to set up a cross-compiling environment for bfin-linux-uclibc This patch, as well as the other patches (toolchain, distribution, uClibc) are actively supported by Analog Devices Inc, at: http://blackfin.uclinux.org/ We have tested this on LTP, and our test plan (including pass/fails) can be found at: http://docs.blackfin.uclinux.org/doku.php?id=testing_the_linux_kernel [m.kozlowski@tuxland.pl: balance parenthesis in blackfin header files] Signed-off-by: Bryan Wu <bryan.wu@analog.com> Signed-off-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl> Signed-off-by: Aubrey Li <aubrey.li@analog.com> Signed-off-by: Jie Zhang <jie.zhang@analog.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r--arch/blackfin/kernel/Makefile14
-rw-r--r--arch/blackfin/kernel/asm-offsets.c136
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c742
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c637
-rw-r--r--arch/blackfin/kernel/bfin_ksyms.c119
-rw-r--r--arch/blackfin/kernel/dma-mapping.c183
-rw-r--r--arch/blackfin/kernel/dualcore_test.c49
-rw-r--r--arch/blackfin/kernel/entry.S94
-rw-r--r--arch/blackfin/kernel/flat.c101
-rw-r--r--arch/blackfin/kernel/init_task.c60
-rw-r--r--arch/blackfin/kernel/irqchip.c147
-rw-r--r--arch/blackfin/kernel/module.c429
-rw-r--r--arch/blackfin/kernel/process.c394
-rw-r--r--arch/blackfin/kernel/ptrace.c430
-rw-r--r--arch/blackfin/kernel/setup.c902
-rw-r--r--arch/blackfin/kernel/signal.c356
-rw-r--r--arch/blackfin/kernel/sys_bfin.c115
-rw-r--r--arch/blackfin/kernel/time.c326
-rw-r--r--arch/blackfin/kernel/traps.c649
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S228
20 files changed, 6111 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
new file mode 100644
index 000000000000..f3b7d2f9d49c
--- /dev/null
+++ b/arch/blackfin/kernel/Makefile
@@ -0,0 +1,14 @@
1#
2# arch/blackfin/kernel/Makefile
3#
4
5extra-y := init_task.o vmlinux.lds
6
7obj-y := \
8 entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
9 sys_bfin.o time.o traps.o irqchip.o dma-mapping.o bfin_gpio.o \
10 flat.o
11
12obj-$(CONFIG_MODULES) += module.o
13obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
14obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
new file mode 100644
index 000000000000..41d9a9f89700
--- /dev/null
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -0,0 +1,136 @@
1/*
2 * File: arch/blackfin/kernel/asm-offsets.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: generate definitions needed by assembly language modules.
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/stddef.h>
31#include <linux/sched.h>
32#include <linux/kernel_stat.h>
33#include <linux/ptrace.h>
34#include <linux/hardirq.h>
35#include <asm/irq.h>
36#include <asm/thread_info.h>
37
38#define DEFINE(sym, val) \
39 asm volatile("\n->" #sym " %0 " #val : : "i" (val))
40
41int main(void)
42{
43 /* offsets into the task struct */
44 DEFINE(TASK_STATE, offsetof(struct task_struct, state));
45 DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
46 DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
47 DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
48 DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
49 DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
50 DEFINE(TASK_MM, offsetof(struct task_struct, mm));
51 DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
52 DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
53
54 /* offsets into the irq_cpustat_t struct */
55 DEFINE(CPUSTAT_SOFTIRQ_PENDING,
56 offsetof(irq_cpustat_t, __softirq_pending));
57
58 /* offsets into the thread struct */
59 DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
60 DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
61 DEFINE(THREAD_SR, offsetof(struct thread_struct, seqstat));
62 DEFINE(PT_SR, offsetof(struct thread_struct, seqstat));
63 DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
64 DEFINE(THREAD_PC, offsetof(struct thread_struct, pc));
65 DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE);
66
67 /* offsets into the pt_regs */
68 DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0));
69 DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc));
70 DEFINE(PT_R0, offsetof(struct pt_regs, r0));
71 DEFINE(PT_R1, offsetof(struct pt_regs, r1));
72 DEFINE(PT_R2, offsetof(struct pt_regs, r2));
73 DEFINE(PT_R3, offsetof(struct pt_regs, r3));
74 DEFINE(PT_R4, offsetof(struct pt_regs, r4));
75 DEFINE(PT_R5, offsetof(struct pt_regs, r5));
76 DEFINE(PT_R6, offsetof(struct pt_regs, r6));
77 DEFINE(PT_R7, offsetof(struct pt_regs, r7));
78
79 DEFINE(PT_P0, offsetof(struct pt_regs, p0));
80 DEFINE(PT_P1, offsetof(struct pt_regs, p1));
81 DEFINE(PT_P2, offsetof(struct pt_regs, p2));
82 DEFINE(PT_P3, offsetof(struct pt_regs, p3));
83 DEFINE(PT_P4, offsetof(struct pt_regs, p4));
84 DEFINE(PT_P5, offsetof(struct pt_regs, p5));
85
86 DEFINE(PT_FP, offsetof(struct pt_regs, fp));
87 DEFINE(PT_USP, offsetof(struct pt_regs, usp));
88 DEFINE(PT_I0, offsetof(struct pt_regs, i0));
89 DEFINE(PT_I1, offsetof(struct pt_regs, i1));
90 DEFINE(PT_I2, offsetof(struct pt_regs, i2));
91 DEFINE(PT_I3, offsetof(struct pt_regs, i3));
92 DEFINE(PT_M0, offsetof(struct pt_regs, m0));
93 DEFINE(PT_M1, offsetof(struct pt_regs, m1));
94 DEFINE(PT_M2, offsetof(struct pt_regs, m2));
95 DEFINE(PT_M3, offsetof(struct pt_regs, m3));
96 DEFINE(PT_L0, offsetof(struct pt_regs, l0));
97 DEFINE(PT_L1, offsetof(struct pt_regs, l1));
98 DEFINE(PT_L2, offsetof(struct pt_regs, l2));
99 DEFINE(PT_L3, offsetof(struct pt_regs, l3));
100 DEFINE(PT_B0, offsetof(struct pt_regs, b0));
101 DEFINE(PT_B1, offsetof(struct pt_regs, b1));
102 DEFINE(PT_B2, offsetof(struct pt_regs, b2));
103 DEFINE(PT_B3, offsetof(struct pt_regs, b3));
104 DEFINE(PT_A0X, offsetof(struct pt_regs, a0x));
105 DEFINE(PT_A0W, offsetof(struct pt_regs, a0w));
106 DEFINE(PT_A1X, offsetof(struct pt_regs, a1x));
107 DEFINE(PT_A1W, offsetof(struct pt_regs, a1w));
108 DEFINE(PT_LC0, offsetof(struct pt_regs, lc0));
109 DEFINE(PT_LC1, offsetof(struct pt_regs, lc1));
110 DEFINE(PT_LT0, offsetof(struct pt_regs, lt0));
111 DEFINE(PT_LT1, offsetof(struct pt_regs, lt1));
112 DEFINE(PT_LB0, offsetof(struct pt_regs, lb0));
113 DEFINE(PT_LB1, offsetof(struct pt_regs, lb1));
114 DEFINE(PT_ASTAT, offsetof(struct pt_regs, astat));
115 DEFINE(PT_RESERVED, offsetof(struct pt_regs, reserved));
116 DEFINE(PT_RETS, offsetof(struct pt_regs, rets));
117 DEFINE(PT_PC, offsetof(struct pt_regs, pc));
118 DEFINE(PT_RETX, offsetof(struct pt_regs, retx));
119 DEFINE(PT_RETN, offsetof(struct pt_regs, retn));
120 DEFINE(PT_RETE, offsetof(struct pt_regs, rete));
121 DEFINE(PT_SEQSTAT, offsetof(struct pt_regs, seqstat));
122 DEFINE(PT_SYSCFG, offsetof(struct pt_regs, syscfg));
123 DEFINE(PT_IPEND, offsetof(struct pt_regs, ipend));
124 DEFINE(SIZEOF_PTREGS, sizeof(struct pt_regs));
125 DEFINE(PT_TEXT_ADDR, sizeof(struct pt_regs)); /* Needed by gdb */
126 DEFINE(PT_TEXT_END_ADDR, 4 + sizeof(struct pt_regs));/* Needed by gdb */
127 DEFINE(PT_DATA_ADDR, 8 + sizeof(struct pt_regs)); /* Needed by gdb */
128 DEFINE(PT_FDPIC_EXEC, 12 + sizeof(struct pt_regs)); /* Needed by gdb */
129 DEFINE(PT_FDPIC_INTERP, 16 + sizeof(struct pt_regs));/* Needed by gdb */
130
131 /* signal defines */
132 DEFINE(SIGSEGV, SIGSEGV);
133 DEFINE(SIGTRAP, SIGTRAP);
134
135 return 0;
136}
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
new file mode 100644
index 000000000000..8ea079ebecb5
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -0,0 +1,742 @@
1/*
2 * File: arch/blackfin/kernel/bfin_dma_5xx.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: This file contains the simple DMA Implementation for Blackfin
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/errno.h>
31#include <linux/module.h>
32#include <linux/sched.h>
33#include <linux/interrupt.h>
34#include <linux/kernel.h>
35#include <linux/param.h>
36
37#include <asm/dma.h>
38#include <asm/cacheflush.h>
39
40/* Remove unused code not exported by symbol or internally called */
41#define REMOVE_DEAD_CODE
42
43/**************************************************************************
44 * Global Variables
45***************************************************************************/
46
47static struct dma_channel dma_ch[MAX_BLACKFIN_DMA_CHANNEL];
48#if defined (CONFIG_BF561)
49static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
50 (struct dma_register *) DMA1_0_NEXT_DESC_PTR,
51 (struct dma_register *) DMA1_1_NEXT_DESC_PTR,
52 (struct dma_register *) DMA1_2_NEXT_DESC_PTR,
53 (struct dma_register *) DMA1_3_NEXT_DESC_PTR,
54 (struct dma_register *) DMA1_4_NEXT_DESC_PTR,
55 (struct dma_register *) DMA1_5_NEXT_DESC_PTR,
56 (struct dma_register *) DMA1_6_NEXT_DESC_PTR,
57 (struct dma_register *) DMA1_7_NEXT_DESC_PTR,
58 (struct dma_register *) DMA1_8_NEXT_DESC_PTR,
59 (struct dma_register *) DMA1_9_NEXT_DESC_PTR,
60 (struct dma_register *) DMA1_10_NEXT_DESC_PTR,
61 (struct dma_register *) DMA1_11_NEXT_DESC_PTR,
62 (struct dma_register *) DMA2_0_NEXT_DESC_PTR,
63 (struct dma_register *) DMA2_1_NEXT_DESC_PTR,
64 (struct dma_register *) DMA2_2_NEXT_DESC_PTR,
65 (struct dma_register *) DMA2_3_NEXT_DESC_PTR,
66 (struct dma_register *) DMA2_4_NEXT_DESC_PTR,
67 (struct dma_register *) DMA2_5_NEXT_DESC_PTR,
68 (struct dma_register *) DMA2_6_NEXT_DESC_PTR,
69 (struct dma_register *) DMA2_7_NEXT_DESC_PTR,
70 (struct dma_register *) DMA2_8_NEXT_DESC_PTR,
71 (struct dma_register *) DMA2_9_NEXT_DESC_PTR,
72 (struct dma_register *) DMA2_10_NEXT_DESC_PTR,
73 (struct dma_register *) DMA2_11_NEXT_DESC_PTR,
74 (struct dma_register *) MDMA1_D0_NEXT_DESC_PTR,
75 (struct dma_register *) MDMA1_S0_NEXT_DESC_PTR,
76 (struct dma_register *) MDMA1_D1_NEXT_DESC_PTR,
77 (struct dma_register *) MDMA1_S1_NEXT_DESC_PTR,
78 (struct dma_register *) MDMA2_D0_NEXT_DESC_PTR,
79 (struct dma_register *) MDMA2_S0_NEXT_DESC_PTR,
80 (struct dma_register *) MDMA2_D1_NEXT_DESC_PTR,
81 (struct dma_register *) MDMA2_S1_NEXT_DESC_PTR,
82 (struct dma_register *) IMDMA_D0_NEXT_DESC_PTR,
83 (struct dma_register *) IMDMA_S0_NEXT_DESC_PTR,
84 (struct dma_register *) IMDMA_D1_NEXT_DESC_PTR,
85 (struct dma_register *) IMDMA_S1_NEXT_DESC_PTR,
86};
87#else
88static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
89 (struct dma_register *) DMA0_NEXT_DESC_PTR,
90 (struct dma_register *) DMA1_NEXT_DESC_PTR,
91 (struct dma_register *) DMA2_NEXT_DESC_PTR,
92 (struct dma_register *) DMA3_NEXT_DESC_PTR,
93 (struct dma_register *) DMA4_NEXT_DESC_PTR,
94 (struct dma_register *) DMA5_NEXT_DESC_PTR,
95 (struct dma_register *) DMA6_NEXT_DESC_PTR,
96 (struct dma_register *) DMA7_NEXT_DESC_PTR,
97#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
98 (struct dma_register *) DMA8_NEXT_DESC_PTR,
99 (struct dma_register *) DMA9_NEXT_DESC_PTR,
100 (struct dma_register *) DMA10_NEXT_DESC_PTR,
101 (struct dma_register *) DMA11_NEXT_DESC_PTR,
102#endif
103 (struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
104 (struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
105 (struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
106 (struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
107};
108#endif
109
110/*------------------------------------------------------------------------------
111 * Set the Buffer Clear bit in the Configuration register of specific DMA
112 * channel. This will stop the descriptor based DMA operation.
113 *-----------------------------------------------------------------------------*/
114static void clear_dma_buffer(unsigned int channel)
115{
116 dma_ch[channel].regs->cfg |= RESTART;
117 SSYNC();
118 dma_ch[channel].regs->cfg &= ~RESTART;
119 SSYNC();
120}
121
122int __init blackfin_dma_init(void)
123{
124 int i;
125
126 printk(KERN_INFO "Blackfin DMA Controller\n");
127
128 for (i = 0; i < MAX_BLACKFIN_DMA_CHANNEL; i++) {
129 dma_ch[i].chan_status = DMA_CHANNEL_FREE;
130 dma_ch[i].regs = base_addr[i];
131 mutex_init(&(dma_ch[i].dmalock));
132 }
133
134 return 0;
135}
136
137arch_initcall(blackfin_dma_init);
138
139/*
140 * Form the channel find the irq number for that channel.
141 */
142#if !defined(CONFIG_BF561)
143
144static int bf533_channel2irq(unsigned int channel)
145{
146 int ret_irq = -1;
147
148 switch (channel) {
149 case CH_PPI:
150 ret_irq = IRQ_PPI;
151 break;
152
153#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
154 case CH_EMAC_RX:
155 ret_irq = IRQ_MAC_RX;
156 break;
157
158 case CH_EMAC_TX:
159 ret_irq = IRQ_MAC_TX;
160 break;
161
162 case CH_UART1_RX:
163 ret_irq = IRQ_UART1_RX;
164 break;
165
166 case CH_UART1_TX:
167 ret_irq = IRQ_UART1_TX;
168 break;
169#endif
170
171 case CH_SPORT0_RX:
172 ret_irq = IRQ_SPORT0_RX;
173 break;
174
175 case CH_SPORT0_TX:
176 ret_irq = IRQ_SPORT0_TX;
177 break;
178
179 case CH_SPORT1_RX:
180 ret_irq = IRQ_SPORT1_RX;
181 break;
182
183 case CH_SPORT1_TX:
184 ret_irq = IRQ_SPORT1_TX;
185 break;
186
187 case CH_SPI:
188 ret_irq = IRQ_SPI;
189 break;
190
191 case CH_UART_RX:
192 ret_irq = IRQ_UART_RX;
193 break;
194
195 case CH_UART_TX:
196 ret_irq = IRQ_UART_TX;
197 break;
198
199 case CH_MEM_STREAM0_SRC:
200 case CH_MEM_STREAM0_DEST:
201 ret_irq = IRQ_MEM_DMA0;
202 break;
203
204 case CH_MEM_STREAM1_SRC:
205 case CH_MEM_STREAM1_DEST:
206 ret_irq = IRQ_MEM_DMA1;
207 break;
208 }
209 return ret_irq;
210}
211
212# define channel2irq(channel) bf533_channel2irq(channel)
213
214#else
215
216static int bf561_channel2irq(unsigned int channel)
217{
218 int ret_irq = -1;
219
220 switch (channel) {
221 case CH_PPI0:
222 ret_irq = IRQ_PPI0;
223 break;
224 case CH_PPI1:
225 ret_irq = IRQ_PPI1;
226 break;
227 case CH_SPORT0_RX:
228 ret_irq = IRQ_SPORT0_RX;
229 break;
230 case CH_SPORT0_TX:
231 ret_irq = IRQ_SPORT0_TX;
232 break;
233 case CH_SPORT1_RX:
234 ret_irq = IRQ_SPORT1_RX;
235 break;
236 case CH_SPORT1_TX:
237 ret_irq = IRQ_SPORT1_TX;
238 break;
239 case CH_SPI:
240 ret_irq = IRQ_SPI;
241 break;
242 case CH_UART_RX:
243 ret_irq = IRQ_UART_RX;
244 break;
245 case CH_UART_TX:
246 ret_irq = IRQ_UART_TX;
247 break;
248
249 case CH_MEM_STREAM0_SRC:
250 case CH_MEM_STREAM0_DEST:
251 ret_irq = IRQ_MEM_DMA0;
252 break;
253 case CH_MEM_STREAM1_SRC:
254 case CH_MEM_STREAM1_DEST:
255 ret_irq = IRQ_MEM_DMA1;
256 break;
257 case CH_MEM_STREAM2_SRC:
258 case CH_MEM_STREAM2_DEST:
259 ret_irq = IRQ_MEM_DMA2;
260 break;
261 case CH_MEM_STREAM3_SRC:
262 case CH_MEM_STREAM3_DEST:
263 ret_irq = IRQ_MEM_DMA3;
264 break;
265
266 case CH_IMEM_STREAM0_SRC:
267 case CH_IMEM_STREAM0_DEST:
268 ret_irq = IRQ_IMEM_DMA0;
269 break;
270 case CH_IMEM_STREAM1_SRC:
271 case CH_IMEM_STREAM1_DEST:
272 ret_irq = IRQ_IMEM_DMA1;
273 break;
274 }
275 return ret_irq;
276}
277
278# define channel2irq(channel) bf561_channel2irq(channel)
279
280#endif
281
282/*------------------------------------------------------------------------------
283 * Request the specific DMA channel from the system.
284 *-----------------------------------------------------------------------------*/
285int request_dma(unsigned int channel, char *device_id)
286{
287
288 pr_debug("request_dma() : BEGIN \n");
289 mutex_lock(&(dma_ch[channel].dmalock));
290
291 if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED)
292 || (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) {
293 mutex_unlock(&(dma_ch[channel].dmalock));
294 pr_debug("DMA CHANNEL IN USE \n");
295 return -EBUSY;
296 } else {
297 dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
298 pr_debug("DMA CHANNEL IS ALLOCATED \n");
299 }
300
301 mutex_unlock(&(dma_ch[channel].dmalock));
302
303 dma_ch[channel].device_id = device_id;
304 dma_ch[channel].irq_callback = NULL;
305
306 /* This is to be enabled by putting a restriction -
307 * you have to request DMA, before doing any operations on
308 * descriptor/channel
309 */
310 pr_debug("request_dma() : END \n");
311 return channel;
312}
313EXPORT_SYMBOL(request_dma);
314
315int set_dma_callback(unsigned int channel, dma_interrupt_t callback, void *data)
316{
317 int ret_irq = 0;
318
319 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
320 && channel < MAX_BLACKFIN_DMA_CHANNEL));
321
322 if (callback != NULL) {
323 int ret_val;
324 ret_irq = channel2irq(channel);
325
326 dma_ch[channel].data = data;
327
328 ret_val =
329 request_irq(ret_irq, (void *)callback, IRQF_DISABLED,
330 dma_ch[channel].device_id, data);
331 if (ret_val) {
332 printk(KERN_NOTICE
333 "Request irq in DMA engine failed.\n");
334 return -EPERM;
335 }
336 dma_ch[channel].irq_callback = callback;
337 }
338 return 0;
339}
340EXPORT_SYMBOL(set_dma_callback);
341
342void free_dma(unsigned int channel)
343{
344 int ret_irq;
345
346 pr_debug("freedma() : BEGIN \n");
347 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
348 && channel < MAX_BLACKFIN_DMA_CHANNEL));
349
350 /* Halt the DMA */
351 disable_dma(channel);
352 clear_dma_buffer(channel);
353
354 if (dma_ch[channel].irq_callback != NULL) {
355 ret_irq = channel2irq(channel);
356 free_irq(ret_irq, dma_ch[channel].data);
357 }
358
359 /* Clear the DMA Variable in the Channel */
360 mutex_lock(&(dma_ch[channel].dmalock));
361 dma_ch[channel].chan_status = DMA_CHANNEL_FREE;
362 mutex_unlock(&(dma_ch[channel].dmalock));
363
364 pr_debug("freedma() : END \n");
365}
366EXPORT_SYMBOL(free_dma);
367
368void dma_enable_irq(unsigned int channel)
369{
370 int ret_irq;
371
372 pr_debug("dma_enable_irq() : BEGIN \n");
373 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
374 && channel < MAX_BLACKFIN_DMA_CHANNEL));
375
376 ret_irq = channel2irq(channel);
377 enable_irq(ret_irq);
378}
379EXPORT_SYMBOL(dma_enable_irq);
380
381void dma_disable_irq(unsigned int channel)
382{
383 int ret_irq;
384
385 pr_debug("dma_disable_irq() : BEGIN \n");
386 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
387 && channel < MAX_BLACKFIN_DMA_CHANNEL));
388
389 ret_irq = channel2irq(channel);
390 disable_irq(ret_irq);
391}
392EXPORT_SYMBOL(dma_disable_irq);
393
394int dma_channel_active(unsigned int channel)
395{
396 if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) {
397 return 0;
398 } else {
399 return 1;
400 }
401}
402EXPORT_SYMBOL(dma_channel_active);
403
404/*------------------------------------------------------------------------------
405* stop the specific DMA channel.
406*-----------------------------------------------------------------------------*/
407void disable_dma(unsigned int channel)
408{
409 pr_debug("stop_dma() : BEGIN \n");
410
411 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
412 && channel < MAX_BLACKFIN_DMA_CHANNEL));
413
414 dma_ch[channel].regs->cfg &= ~DMAEN; /* Clean the enable bit */
415 SSYNC();
416 dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
417 /* Needs to be enabled Later */
418 pr_debug("stop_dma() : END \n");
419 return;
420}
421EXPORT_SYMBOL(disable_dma);
422
423void enable_dma(unsigned int channel)
424{
425 pr_debug("enable_dma() : BEGIN \n");
426
427 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
428 && channel < MAX_BLACKFIN_DMA_CHANNEL));
429
430 dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED;
431 dma_ch[channel].regs->curr_x_count = 0;
432 dma_ch[channel].regs->curr_y_count = 0;
433
434 dma_ch[channel].regs->cfg |= DMAEN; /* Set the enable bit */
435 SSYNC();
436 pr_debug("enable_dma() : END \n");
437 return;
438}
439EXPORT_SYMBOL(enable_dma);
440
441/*------------------------------------------------------------------------------
442* Set the Start Address register for the specific DMA channel
443* This function can be used for register based DMA,
444* to setup the start address
445* addr: Starting address of the DMA Data to be transferred.
446*-----------------------------------------------------------------------------*/
447void set_dma_start_addr(unsigned int channel, unsigned long addr)
448{
449 pr_debug("set_dma_start_addr() : BEGIN \n");
450
451 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
452 && channel < MAX_BLACKFIN_DMA_CHANNEL));
453
454 dma_ch[channel].regs->start_addr = addr;
455 SSYNC();
456 pr_debug("set_dma_start_addr() : END\n");
457}
458EXPORT_SYMBOL(set_dma_start_addr);
459
460void set_dma_next_desc_addr(unsigned int channel, unsigned long addr)
461{
462 pr_debug("set_dma_next_desc_addr() : BEGIN \n");
463
464 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
465 && channel < MAX_BLACKFIN_DMA_CHANNEL));
466
467 dma_ch[channel].regs->next_desc_ptr = addr;
468 SSYNC();
469 pr_debug("set_dma_start_addr() : END\n");
470}
471EXPORT_SYMBOL(set_dma_next_desc_addr);
472
473void set_dma_x_count(unsigned int channel, unsigned short x_count)
474{
475 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
476 && channel < MAX_BLACKFIN_DMA_CHANNEL));
477
478 dma_ch[channel].regs->x_count = x_count;
479 SSYNC();
480}
481EXPORT_SYMBOL(set_dma_x_count);
482
483void set_dma_y_count(unsigned int channel, unsigned short y_count)
484{
485 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
486 && channel < MAX_BLACKFIN_DMA_CHANNEL));
487
488 dma_ch[channel].regs->y_count = y_count;
489 SSYNC();
490}
491EXPORT_SYMBOL(set_dma_y_count);
492
493void set_dma_x_modify(unsigned int channel, short x_modify)
494{
495 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
496 && channel < MAX_BLACKFIN_DMA_CHANNEL));
497
498 dma_ch[channel].regs->x_modify = x_modify;
499 SSYNC();
500}
501EXPORT_SYMBOL(set_dma_x_modify);
502
503void set_dma_y_modify(unsigned int channel, short y_modify)
504{
505 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
506 && channel < MAX_BLACKFIN_DMA_CHANNEL));
507
508 dma_ch[channel].regs->y_modify = y_modify;
509 SSYNC();
510}
511EXPORT_SYMBOL(set_dma_y_modify);
512
513void set_dma_config(unsigned int channel, unsigned short config)
514{
515 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
516 && channel < MAX_BLACKFIN_DMA_CHANNEL));
517
518 dma_ch[channel].regs->cfg = config;
519 SSYNC();
520}
521EXPORT_SYMBOL(set_dma_config);
522
523unsigned short
524set_bfin_dma_config(char direction, char flow_mode,
525 char intr_mode, char dma_mode, char width)
526{
527 unsigned short config;
528
529 config =
530 ((direction << 1) | (width << 2) | (dma_mode << 4) |
531 (intr_mode << 6) | (flow_mode << 12) | RESTART);
532 return config;
533}
534EXPORT_SYMBOL(set_bfin_dma_config);
535
536void set_dma_sg(unsigned int channel, struct dmasg * sg, int nr_sg)
537{
538 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
539 && channel < MAX_BLACKFIN_DMA_CHANNEL));
540
541 dma_ch[channel].regs->cfg |= ((nr_sg & 0x0F) << 8);
542
543 dma_ch[channel].regs->next_desc_ptr = (unsigned int)sg;
544
545 SSYNC();
546}
547EXPORT_SYMBOL(set_dma_sg);
548
549/*------------------------------------------------------------------------------
550 * Get the DMA status of a specific DMA channel from the system.
551 *-----------------------------------------------------------------------------*/
552unsigned short get_dma_curr_irqstat(unsigned int channel)
553{
554 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
555 && channel < MAX_BLACKFIN_DMA_CHANNEL));
556
557 return dma_ch[channel].regs->irq_status;
558}
559EXPORT_SYMBOL(get_dma_curr_irqstat);
560
561/*------------------------------------------------------------------------------
562 * Clear the DMA_DONE bit in DMA status. Stop the DMA completion interrupt.
563 *-----------------------------------------------------------------------------*/
564void clear_dma_irqstat(unsigned int channel)
565{
566 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
567 && channel < MAX_BLACKFIN_DMA_CHANNEL));
568 dma_ch[channel].regs->irq_status |= 3;
569}
570EXPORT_SYMBOL(clear_dma_irqstat);
571
572/*------------------------------------------------------------------------------
573 * Get current DMA xcount of a specific DMA channel from the system.
574 *-----------------------------------------------------------------------------*/
575unsigned short get_dma_curr_xcount(unsigned int channel)
576{
577 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
578 && channel < MAX_BLACKFIN_DMA_CHANNEL));
579
580 return dma_ch[channel].regs->curr_x_count;
581}
582EXPORT_SYMBOL(get_dma_curr_xcount);
583
584/*------------------------------------------------------------------------------
585 * Get current DMA ycount of a specific DMA channel from the system.
586 *-----------------------------------------------------------------------------*/
587unsigned short get_dma_curr_ycount(unsigned int channel)
588{
589 BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
590 && channel < MAX_BLACKFIN_DMA_CHANNEL));
591
592 return dma_ch[channel].regs->curr_y_count;
593}
594EXPORT_SYMBOL(get_dma_curr_ycount);
595
596void *dma_memcpy(void *dest, const void *src, size_t size)
597{
598 int direction; /* 1 - address decrease, 0 - address increase */
599 int flag_align; /* 1 - address aligned, 0 - address unaligned */
600 int flag_2D; /* 1 - 2D DMA needed, 0 - 1D DMA needed */
601
602 if (size <= 0)
603 return NULL;
604
605 if ((unsigned long)src < memory_end)
606 blackfin_dcache_flush_range((unsigned int)src,
607 (unsigned int)(src + size));
608
609 bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
610
611 if ((unsigned long)src < (unsigned long)dest)
612 direction = 1;
613 else
614 direction = 0;
615
616 if ((((unsigned long)dest % 2) == 0) && (((unsigned long)src % 2) == 0)
617 && ((size % 2) == 0))
618 flag_align = 1;
619 else
620 flag_align = 0;
621
622 if (size > 0x10000) /* size > 64K */
623 flag_2D = 1;
624 else
625 flag_2D = 0;
626
627 /* Setup destination and source start address */
628 if (direction) {
629 if (flag_align) {
630 bfin_write_MDMA_D0_START_ADDR(dest + size - 2);
631 bfin_write_MDMA_S0_START_ADDR(src + size - 2);
632 } else {
633 bfin_write_MDMA_D0_START_ADDR(dest + size - 1);
634 bfin_write_MDMA_S0_START_ADDR(src + size - 1);
635 }
636 } else {
637 bfin_write_MDMA_D0_START_ADDR(dest);
638 bfin_write_MDMA_S0_START_ADDR(src);
639 }
640
641 /* Setup destination and source xcount */
642 if (flag_2D) {
643 if (flag_align) {
644 bfin_write_MDMA_D0_X_COUNT(1024 / 2);
645 bfin_write_MDMA_S0_X_COUNT(1024 / 2);
646 } else {
647 bfin_write_MDMA_D0_X_COUNT(1024);
648 bfin_write_MDMA_S0_X_COUNT(1024);
649 }
650 bfin_write_MDMA_D0_Y_COUNT(size >> 10);
651 bfin_write_MDMA_S0_Y_COUNT(size >> 10);
652 } else {
653 if (flag_align) {
654 bfin_write_MDMA_D0_X_COUNT(size / 2);
655 bfin_write_MDMA_S0_X_COUNT(size / 2);
656 } else {
657 bfin_write_MDMA_D0_X_COUNT(size);
658 bfin_write_MDMA_S0_X_COUNT(size);
659 }
660 }
661
662 /* Setup destination and source xmodify and ymodify */
663 if (direction) {
664 if (flag_align) {
665 bfin_write_MDMA_D0_X_MODIFY(-2);
666 bfin_write_MDMA_S0_X_MODIFY(-2);
667 if (flag_2D) {
668 bfin_write_MDMA_D0_Y_MODIFY(-2);
669 bfin_write_MDMA_S0_Y_MODIFY(-2);
670 }
671 } else {
672 bfin_write_MDMA_D0_X_MODIFY(-1);
673 bfin_write_MDMA_S0_X_MODIFY(-1);
674 if (flag_2D) {
675 bfin_write_MDMA_D0_Y_MODIFY(-1);
676 bfin_write_MDMA_S0_Y_MODIFY(-1);
677 }
678 }
679 } else {
680 if (flag_align) {
681 bfin_write_MDMA_D0_X_MODIFY(2);
682 bfin_write_MDMA_S0_X_MODIFY(2);
683 if (flag_2D) {
684 bfin_write_MDMA_D0_Y_MODIFY(2);
685 bfin_write_MDMA_S0_Y_MODIFY(2);
686 }
687 } else {
688 bfin_write_MDMA_D0_X_MODIFY(1);
689 bfin_write_MDMA_S0_X_MODIFY(1);
690 if (flag_2D) {
691 bfin_write_MDMA_D0_Y_MODIFY(1);
692 bfin_write_MDMA_S0_Y_MODIFY(1);
693 }
694 }
695 }
696
697 /* Enable source DMA */
698 if (flag_2D) {
699 if (flag_align) {
700 bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D | WDSIZE_16);
701 bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D | WDSIZE_16);
702 } else {
703 bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D);
704 bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D);
705 }
706 } else {
707 if (flag_align) {
708 bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16);
709 bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16);
710 } else {
711 bfin_write_MDMA_S0_CONFIG(DMAEN);
712 bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN);
713 }
714 }
715
716 while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
717 ;
718
719 bfin_write_MDMA_D0_IRQ_STATUS(bfin_read_MDMA_D0_IRQ_STATUS() |
720 (DMA_DONE | DMA_ERR));
721
722 bfin_write_MDMA_S0_CONFIG(0);
723 bfin_write_MDMA_D0_CONFIG(0);
724
725 if ((unsigned long)dest < memory_end)
726 blackfin_dcache_invalidate_range((unsigned int)dest,
727 (unsigned int)(dest + size));
728
729 return dest;
730}
731EXPORT_SYMBOL(dma_memcpy);
732
733void *safe_dma_memcpy(void *dest, const void *src, size_t size)
734{
735 int flags = 0;
736 void *addr;
737 local_irq_save(flags);
738 addr = dma_memcpy(dest, src, size);
739 local_irq_restore(flags);
740 return addr;
741}
742EXPORT_SYMBOL(safe_dma_memcpy);
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
new file mode 100644
index 000000000000..e9f24a9a46ba
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -0,0 +1,637 @@
1/*
2 * File: arch/blackfin/kernel/bfin_gpio.c
3 * Based on:
4 * Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
5 *
6 * Created:
7 * Description: GPIO Abstraction Layer
8 *
9 * Modified:
10 * Copyright 2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30/*
31* Number BF537/6/4 BF561 BF533/2/1
32*
33* GPIO_0 PF0 PF0 PF0
34* GPIO_1 PF1 PF1 PF1
35* GPIO_2 PF2 PF2 PF2
36* GPIO_3 PF3 PF3 PF3
37* GPIO_4 PF4 PF4 PF4
38* GPIO_5 PF5 PF5 PF5
39* GPIO_6 PF6 PF6 PF6
40* GPIO_7 PF7 PF7 PF7
41* GPIO_8 PF8 PF8 PF8
42* GPIO_9 PF9 PF9 PF9
43* GPIO_10 PF10 PF10 PF10
44* GPIO_11 PF11 PF11 PF11
45* GPIO_12 PF12 PF12 PF12
46* GPIO_13 PF13 PF13 PF13
47* GPIO_14 PF14 PF14 PF14
48* GPIO_15 PF15 PF15 PF15
49* GPIO_16 PG0 PF16
50* GPIO_17 PG1 PF17
51* GPIO_18 PG2 PF18
52* GPIO_19 PG3 PF19
53* GPIO_20 PG4 PF20
54* GPIO_21 PG5 PF21
55* GPIO_22 PG6 PF22
56* GPIO_23 PG7 PF23
57* GPIO_24 PG8 PF24
58* GPIO_25 PG9 PF25
59* GPIO_26 PG10 PF26
60* GPIO_27 PG11 PF27
61* GPIO_28 PG12 PF28
62* GPIO_29 PG13 PF29
63* GPIO_30 PG14 PF30
64* GPIO_31 PG15 PF31
65* GPIO_32 PH0 PF32
66* GPIO_33 PH1 PF33
67* GPIO_34 PH2 PF34
68* GPIO_35 PH3 PF35
69* GPIO_36 PH4 PF36
70* GPIO_37 PH5 PF37
71* GPIO_38 PH6 PF38
72* GPIO_39 PH7 PF39
73* GPIO_40 PH8 PF40
74* GPIO_41 PH9 PF41
75* GPIO_42 PH10 PF42
76* GPIO_43 PH11 PF43
77* GPIO_44 PH12 PF44
78* GPIO_45 PH13 PF45
79* GPIO_46 PH14 PF46
80* GPIO_47 PH15 PF47
81*/
82
83#include <linux/module.h>
84#include <linux/err.h>
85#include <asm/blackfin.h>
86#include <asm/gpio.h>
87#include <linux/irq.h>
88
89#ifdef BF533_FAMILY
90static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
91 (struct gpio_port_t *) FIO_FLAG_D,
92};
93#endif
94
95#ifdef BF537_FAMILY
96static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
97 (struct gpio_port_t *) PORTFIO,
98 (struct gpio_port_t *) PORTGIO,
99 (struct gpio_port_t *) PORTHIO,
100};
101
102static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
103 (unsigned short *) PORTF_FER,
104 (unsigned short *) PORTG_FER,
105 (unsigned short *) PORTH_FER,
106};
107
108#endif
109
110#ifdef BF561_FAMILY
111static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
112 (struct gpio_port_t *) FIO0_FLAG_D,
113 (struct gpio_port_t *) FIO1_FLAG_D,
114 (struct gpio_port_t *) FIO2_FLAG_D,
115};
116#endif
117
118static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
119
120#ifdef CONFIG_PM
121static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
122static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS];
123static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)];
124
125#ifdef BF533_FAMILY
126static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB};
127#endif
128
129#ifdef BF537_FAMILY
130static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX};
131#endif
132
133#ifdef BF561_FAMILY
134static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB};
135#endif
136
137#endif /* CONFIG_PM */
138
139inline int check_gpio(unsigned short gpio)
140{
141 if (gpio > MAX_BLACKFIN_GPIOS)
142 return -EINVAL;
143 return 0;
144}
145
146#ifdef BF537_FAMILY
147void port_setup(unsigned short gpio, unsigned short usage)
148{
149 if (usage == GPIO_USAGE) {
150 if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio))
151 printk(KERN_WARNING "bfin-gpio: Possible Conflict with Peripheral "
152 "usage and GPIO %d detected!\n", gpio);
153 *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
154 } else
155 *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
156 SSYNC();
157}
158#else
159# define port_setup(...) do { } while (0)
160#endif
161
162
163void default_gpio(unsigned short gpio)
164{
165 unsigned short bank,bitmask;
166
167 bank = gpio_bank(gpio);
168 bitmask = gpio_bit(gpio);
169
170 gpio_bankb[bank]->maska_clear = bitmask;
171 gpio_bankb[bank]->maskb_clear = bitmask;
172 SSYNC();
173 gpio_bankb[bank]->inen &= ~bitmask;
174 gpio_bankb[bank]->dir &= ~bitmask;
175 gpio_bankb[bank]->polar &= ~bitmask;
176 gpio_bankb[bank]->both &= ~bitmask;
177 gpio_bankb[bank]->edge &= ~bitmask;
178}
179
180
181int __init bfin_gpio_init(void)
182{
183 int i;
184
185 printk(KERN_INFO "Blackfin GPIO Controller\n");
186
187 for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE)
188 reserved_map[gpio_bank(i)] = 0;
189
190#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
191# if defined(CONFIG_BFIN_MAC_RMII)
192 reserved_map[PORT_H] = 0xC373;
193# else
194 reserved_map[PORT_H] = 0xFFFF;
195# endif
196#endif
197
198 return 0;
199}
200
201arch_initcall(bfin_gpio_init);
202
203
204/***********************************************************
205*
206* FUNCTIONS: Blackfin General Purpose Ports Access Functions
207*
208* INPUTS/OUTPUTS:
209* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
210*
211*
212* DESCRIPTION: These functions abstract direct register access
213* to Blackfin processor General Purpose
214* Ports Regsiters
215*
216* CAUTION: These functions do not belong to the GPIO Driver API
217*************************************************************
218* MODIFICATION HISTORY :
219**************************************************************/
220
221/* Set a specific bit */
222
223#define SET_GPIO(name) \
224void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
225{ \
226 unsigned long flags; \
227 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
228 local_irq_save(flags); \
229 if (arg) \
230 gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
231 else \
232 gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \
233 local_irq_restore(flags); \
234} \
235EXPORT_SYMBOL(set_gpio_ ## name);
236
237SET_GPIO(dir)
238SET_GPIO(inen)
239SET_GPIO(polar)
240SET_GPIO(edge)
241SET_GPIO(both)
242
243
244#define SET_GPIO_SC(name) \
245void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
246{ \
247 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
248 if (arg) \
249 gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
250 else \
251 gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
252} \
253EXPORT_SYMBOL(set_gpio_ ## name);
254
255SET_GPIO_SC(maska)
256SET_GPIO_SC(maskb)
257
258#if defined(ANOMALY_05000311)
259void set_gpio_data(unsigned short gpio, unsigned short arg)
260{
261 unsigned long flags;
262 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
263 local_irq_save(flags);
264 if (arg)
265 gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
266 else
267 gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
268 bfin_read_CHIPID();
269 local_irq_restore(flags);
270}
271EXPORT_SYMBOL(set_gpio_data);
272#else
273SET_GPIO_SC(data)
274#endif
275
276
277#if defined(ANOMALY_05000311)
278void set_gpio_toggle(unsigned short gpio)
279{
280 unsigned long flags;
281 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
282 local_irq_save(flags);
283 gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
284 bfin_read_CHIPID();
285 local_irq_restore(flags);
286}
287#else
288void set_gpio_toggle(unsigned short gpio)
289{
290 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
291 gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
292}
293#endif
294EXPORT_SYMBOL(set_gpio_toggle);
295
296
297/*Set current PORT date (16-bit word)*/
298
299#define SET_GPIO_P(name) \
300void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
301{ \
302 gpio_bankb[gpio_bank(gpio)]->name = arg; \
303} \
304EXPORT_SYMBOL(set_gpiop_ ## name);
305
306SET_GPIO_P(dir)
307SET_GPIO_P(inen)
308SET_GPIO_P(polar)
309SET_GPIO_P(edge)
310SET_GPIO_P(both)
311SET_GPIO_P(maska)
312SET_GPIO_P(maskb)
313
314
315#if defined(ANOMALY_05000311)
316void set_gpiop_data(unsigned short gpio, unsigned short arg)
317{
318 unsigned long flags;
319 local_irq_save(flags);
320 gpio_bankb[gpio_bank(gpio)]->data = arg;
321 bfin_read_CHIPID();
322 local_irq_restore(flags);
323}
324EXPORT_SYMBOL(set_gpiop_data);
325#else
326SET_GPIO_P(data)
327#endif
328
329
330
331/* Get a specific bit */
332
333#define GET_GPIO(name) \
334unsigned short get_gpio_ ## name(unsigned short gpio) \
335{ \
336 return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \
337} \
338EXPORT_SYMBOL(get_gpio_ ## name);
339
340GET_GPIO(dir)
341GET_GPIO(inen)
342GET_GPIO(polar)
343GET_GPIO(edge)
344GET_GPIO(both)
345GET_GPIO(maska)
346GET_GPIO(maskb)
347
348
349#if defined(ANOMALY_05000311)
350unsigned short get_gpio_data(unsigned short gpio)
351{
352 unsigned long flags;
353 unsigned short ret;
354 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
355 local_irq_save(flags);
356 ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
357 bfin_read_CHIPID();
358 local_irq_restore(flags);
359 return ret;
360}
361EXPORT_SYMBOL(get_gpio_data);
362#else
363GET_GPIO(data)
364#endif
365
366/*Get current PORT date (16-bit word)*/
367
368#define GET_GPIO_P(name) \
369unsigned short get_gpiop_ ## name(unsigned short gpio) \
370{ \
371 return (gpio_bankb[gpio_bank(gpio)]->name);\
372} \
373EXPORT_SYMBOL(get_gpiop_ ## name);
374
375GET_GPIO_P(dir)
376GET_GPIO_P(inen)
377GET_GPIO_P(polar)
378GET_GPIO_P(edge)
379GET_GPIO_P(both)
380GET_GPIO_P(maska)
381GET_GPIO_P(maskb)
382
383#if defined(ANOMALY_05000311)
384unsigned short get_gpiop_data(unsigned short gpio)
385{
386 unsigned long flags;
387 unsigned short ret;
388 local_irq_save(flags);
389 ret = gpio_bankb[gpio_bank(gpio)]->data;
390 bfin_read_CHIPID();
391 local_irq_restore(flags);
392 return ret;
393}
394EXPORT_SYMBOL(get_gpiop_data);
395#else
396GET_GPIO_P(data)
397#endif
398
399#ifdef CONFIG_PM
400/***********************************************************
401*
402* FUNCTIONS: Blackfin PM Setup API
403*
404* INPUTS/OUTPUTS:
405* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
406* type -
407* PM_WAKE_RISING
408* PM_WAKE_FALLING
409* PM_WAKE_HIGH
410* PM_WAKE_LOW
411* PM_WAKE_BOTH_EDGES
412*
413* DESCRIPTION: Blackfin PM Driver API
414*
415* CAUTION:
416*************************************************************
417* MODIFICATION HISTORY :
418**************************************************************/
419int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
420{
421 unsigned long flags;
422
423 if ((check_gpio(gpio) < 0) || !type)
424 return -EINVAL;
425
426 local_irq_save(flags);
427
428 wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
429 wakeup_flags_map[gpio] = type;
430 local_irq_restore(flags);
431
432 return 0;
433}
434EXPORT_SYMBOL(gpio_pm_wakeup_request);
435
436void gpio_pm_wakeup_free(unsigned short gpio)
437{
438 unsigned long flags;
439
440 if (check_gpio(gpio) < 0)
441 return;
442
443 local_irq_save(flags);
444
445 wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
446
447 local_irq_restore(flags);
448}
449EXPORT_SYMBOL(gpio_pm_wakeup_free);
450
451static int bfin_gpio_wakeup_type(unsigned short gpio, unsigned char type)
452{
453 port_setup(gpio, GPIO_USAGE);
454 set_gpio_dir(gpio, 0);
455 set_gpio_inen(gpio, 1);
456
457 if (type & (PM_WAKE_RISING | PM_WAKE_FALLING))
458 set_gpio_edge(gpio, 1);
459 else
460 set_gpio_edge(gpio, 0);
461
462 if ((type & (PM_WAKE_BOTH_EDGES)) == (PM_WAKE_BOTH_EDGES))
463 set_gpio_both(gpio, 1);
464 else
465 set_gpio_both(gpio, 0);
466
467 if ((type & (PM_WAKE_FALLING | PM_WAKE_LOW)))
468 set_gpio_polar(gpio, 1);
469 else
470 set_gpio_polar(gpio, 0);
471
472 SSYNC();
473
474 return 0;
475}
476
477u32 gpio_pm_setup(void)
478{
479 u32 sic_iwr = 0;
480 u16 bank, mask, i, gpio;
481
482 for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
483 mask = wakeup_map[gpio_bank(i)];
484 bank = gpio_bank(i);
485
486 gpio_bank_saved[bank].maskb = gpio_bankb[bank]->maskb;
487 gpio_bankb[bank]->maskb = 0;
488
489 if (mask) {
490#ifdef BF537_FAMILY
491 gpio_bank_saved[bank].fer = *port_fer[bank];
492#endif
493 gpio_bank_saved[bank].inen = gpio_bankb[bank]->inen;
494 gpio_bank_saved[bank].polar = gpio_bankb[bank]->polar;
495 gpio_bank_saved[bank].dir = gpio_bankb[bank]->dir;
496 gpio_bank_saved[bank].edge = gpio_bankb[bank]->edge;
497 gpio_bank_saved[bank].both = gpio_bankb[bank]->both;
498
499 gpio = i;
500
501 while (mask) {
502 if (mask & 1) {
503 bfin_gpio_wakeup_type(gpio, wakeup_flags_map[gpio]);
504 set_gpio_data(gpio, 0); /*Clear*/
505 }
506 gpio++;
507 mask >>= 1;
508 }
509
510 sic_iwr |= 1 << (sic_iwr_irqs[bank] - (IRQ_CORETMR + 1));
511 gpio_bankb[bank]->maskb_set = wakeup_map[gpio_bank(i)];
512 }
513 }
514
515 if (sic_iwr)
516 return sic_iwr;
517 else
518 return IWR_ENABLE_ALL;
519}
520
521
522void gpio_pm_restore(void)
523{
524 u16 bank, mask, i;
525
526 for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
527 mask = wakeup_map[gpio_bank(i)];
528 bank = gpio_bank(i);
529
530 if (mask) {
531#ifdef BF537_FAMILY
532 *port_fer[bank] = gpio_bank_saved[bank].fer;
533#endif
534 gpio_bankb[bank]->inen = gpio_bank_saved[bank].inen;
535 gpio_bankb[bank]->dir = gpio_bank_saved[bank].dir;
536 gpio_bankb[bank]->polar = gpio_bank_saved[bank].polar;
537 gpio_bankb[bank]->edge = gpio_bank_saved[bank].edge;
538 gpio_bankb[bank]->both = gpio_bank_saved[bank].both;
539 }
540
541 gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb;
542 }
543}
544
545#endif
546
547/***********************************************************
548*
549* FUNCTIONS: Blackfin GPIO Driver
550*
551* INPUTS/OUTPUTS:
552* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
553*
554*
555* DESCRIPTION: Blackfin GPIO Driver API
556*
557* CAUTION:
558*************************************************************
559* MODIFICATION HISTORY :
560**************************************************************/
561
562int gpio_request(unsigned short gpio, const char *label)
563{
564 unsigned long flags;
565
566 if (check_gpio(gpio) < 0)
567 return -EINVAL;
568
569 local_irq_save(flags);
570
571 if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
572 printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio);
573 dump_stack();
574 local_irq_restore(flags);
575 return -EBUSY;
576 }
577 reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio);
578
579 local_irq_restore(flags);
580
581 port_setup(gpio, GPIO_USAGE);
582
583 return 0;
584}
585EXPORT_SYMBOL(gpio_request);
586
587
588void gpio_free(unsigned short gpio)
589{
590 unsigned long flags;
591
592 if (check_gpio(gpio) < 0)
593 return;
594
595 local_irq_save(flags);
596
597 if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
598 printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
599 dump_stack();
600 local_irq_restore(flags);
601 return;
602 }
603
604 default_gpio(gpio);
605
606 reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
607
608 local_irq_restore(flags);
609}
610EXPORT_SYMBOL(gpio_free);
611
612
613void gpio_direction_input(unsigned short gpio)
614{
615 unsigned long flags;
616
617 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
618
619 local_irq_save(flags);
620 gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
621 gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
622 local_irq_restore(flags);
623}
624EXPORT_SYMBOL(gpio_direction_input);
625
626void gpio_direction_output(unsigned short gpio)
627{
628 unsigned long flags;
629
630 BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
631
632 local_irq_save(flags);
633 gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
634 gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
635 local_irq_restore(flags);
636}
637EXPORT_SYMBOL(gpio_direction_output);
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c
new file mode 100644
index 000000000000..f64ecb638fab
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_ksyms.c
@@ -0,0 +1,119 @@
1/*
2 * File: arch/blackfin/kernel/bfin_ksyms.c
3 * Based on: none - original work
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/module.h>
31#include <asm/irq.h>
32#include <asm/checksum.h>
33#include <asm/cacheflush.h>
34#include <asm/uaccess.h>
35
36/* platform dependent support */
37
38EXPORT_SYMBOL(__ioremap);
39EXPORT_SYMBOL(strcmp);
40EXPORT_SYMBOL(strncmp);
41EXPORT_SYMBOL(dump_thread);
42
43EXPORT_SYMBOL(ip_fast_csum);
44
45EXPORT_SYMBOL(kernel_thread);
46
47EXPORT_SYMBOL(__up);
48EXPORT_SYMBOL(__down);
49EXPORT_SYMBOL(__down_trylock);
50EXPORT_SYMBOL(__down_interruptible);
51
52EXPORT_SYMBOL(is_in_rom);
53
54/* Networking helper routines. */
55EXPORT_SYMBOL(csum_partial_copy);
56
57/* The following are special because they're not called
58 * explicitly (the C compiler generates them). Fortunately,
59 * their interface isn't gonna change any time soon now, so
60 * it's OK to leave it out of version control.
61 */
62EXPORT_SYMBOL(memcpy);
63EXPORT_SYMBOL(memset);
64EXPORT_SYMBOL(memcmp);
65EXPORT_SYMBOL(memmove);
66EXPORT_SYMBOL(memchr);
67EXPORT_SYMBOL(get_wchan);
68
69/*
70 * libgcc functions - functions that are used internally by the
71 * compiler... (prototypes are not correct though, but that
72 * doesn't really matter since they're not versioned).
73 */
74extern void __ashldi3(void);
75extern void __ashrdi3(void);
76extern void __smulsi3_highpart(void);
77extern void __umulsi3_highpart(void);
78extern void __divsi3(void);
79extern void __lshrdi3(void);
80extern void __modsi3(void);
81extern void __muldi3(void);
82extern void __udivsi3(void);
83extern void __umodsi3(void);
84
85/* gcc lib functions */
86EXPORT_SYMBOL(__ashldi3);
87EXPORT_SYMBOL(__ashrdi3);
88EXPORT_SYMBOL(__umulsi3_highpart);
89EXPORT_SYMBOL(__smulsi3_highpart);
90EXPORT_SYMBOL(__divsi3);
91EXPORT_SYMBOL(__lshrdi3);
92EXPORT_SYMBOL(__modsi3);
93EXPORT_SYMBOL(__muldi3);
94EXPORT_SYMBOL(__udivsi3);
95EXPORT_SYMBOL(__umodsi3);
96
97EXPORT_SYMBOL(outsb);
98EXPORT_SYMBOL(insb);
99EXPORT_SYMBOL(outsw);
100EXPORT_SYMBOL(insw);
101EXPORT_SYMBOL(outsl);
102EXPORT_SYMBOL(insl);
103EXPORT_SYMBOL(irq_flags);
104EXPORT_SYMBOL(iounmap);
105EXPORT_SYMBOL(blackfin_dcache_invalidate_range);
106EXPORT_SYMBOL(blackfin_icache_dcache_flush_range);
107EXPORT_SYMBOL(blackfin_icache_flush_range);
108EXPORT_SYMBOL(blackfin_dcache_flush_range);
109EXPORT_SYMBOL(blackfin_dflush_page);
110
111EXPORT_SYMBOL(csum_partial);
112EXPORT_SYMBOL(__init_begin);
113EXPORT_SYMBOL(__init_end);
114EXPORT_SYMBOL(_ebss_l1);
115EXPORT_SYMBOL(_stext_l1);
116EXPORT_SYMBOL(_etext_l1);
117EXPORT_SYMBOL(_sdata_l1);
118EXPORT_SYMBOL(_ebss_b_l1);
119EXPORT_SYMBOL(_sdata_b_l1);
diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c
new file mode 100644
index 000000000000..539eb24e062f
--- /dev/null
+++ b/arch/blackfin/kernel/dma-mapping.c
@@ -0,0 +1,183 @@
1/*
2 * File: arch/blackfin/kernel/dma-mapping.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: Dynamic DMA mapping support.
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/types.h>
31#include <linux/mm.h>
32#include <linux/string.h>
33#include <linux/bootmem.h>
34#include <linux/spinlock.h>
35#include <linux/device.h>
36#include <linux/dma-mapping.h>
37#include <asm/cacheflush.h>
38#include <asm/io.h>
39#include <asm/bfin-global.h>
40
41static spinlock_t dma_page_lock;
42static unsigned int *dma_page;
43static unsigned int dma_pages;
44static unsigned long dma_base;
45static unsigned long dma_size;
46static unsigned int dma_initialized;
47
48void dma_alloc_init(unsigned long start, unsigned long end)
49{
50 spin_lock_init(&dma_page_lock);
51 dma_initialized = 0;
52
53 dma_page = (unsigned int *)__get_free_page(GFP_KERNEL);
54 memset(dma_page, 0, PAGE_SIZE);
55 dma_base = PAGE_ALIGN(start);
56 dma_size = PAGE_ALIGN(end) - PAGE_ALIGN(start);
57 dma_pages = dma_size >> PAGE_SHIFT;
58 memset((void *)dma_base, 0, DMA_UNCACHED_REGION);
59 dma_initialized = 1;
60
61 printk(KERN_INFO "%s: dma_page @ 0x%p - %d pages at 0x%08lx\n", __FUNCTION__,
62 dma_page, dma_pages, dma_base);
63}
64
65static inline unsigned int get_pages(size_t size)
66{
67 return ((size - 1) >> PAGE_SHIFT) + 1;
68}
69
70static unsigned long __alloc_dma_pages(unsigned int pages)
71{
72 unsigned long ret = 0, flags;
73 int i, count = 0;
74
75 if (dma_initialized == 0)
76 dma_alloc_init(_ramend - DMA_UNCACHED_REGION, _ramend);
77
78 spin_lock_irqsave(&dma_page_lock, flags);
79
80 for (i = 0; i < dma_pages;) {
81 if (dma_page[i++] == 0) {
82 if (++count == pages) {
83 while (count--)
84 dma_page[--i] = 1;
85 ret = dma_base + (i << PAGE_SHIFT);
86 break;
87 }
88 } else
89 count = 0;
90 }
91 spin_unlock_irqrestore(&dma_page_lock, flags);
92 return ret;
93}
94
95static void __free_dma_pages(unsigned long addr, unsigned int pages)
96{
97 unsigned long page = (addr - dma_base) >> PAGE_SHIFT;
98 unsigned long flags;
99 int i;
100
101 if ((page + pages) > dma_pages) {
102 printk(KERN_ERR "%s: freeing outside range.\n", __FUNCTION__);
103 BUG();
104 }
105
106 spin_lock_irqsave(&dma_page_lock, flags);
107 for (i = page; i < page + pages; i++) {
108 dma_page[i] = 0;
109 }
110 spin_unlock_irqrestore(&dma_page_lock, flags);
111}
112
113void *dma_alloc_coherent(struct device *dev, size_t size,
114 dma_addr_t * dma_handle, gfp_t gfp)
115{
116 void *ret;
117
118 ret = (void *)__alloc_dma_pages(get_pages(size));
119
120 if (ret) {
121 memset(ret, 0, size);
122 *dma_handle = virt_to_phys(ret);
123 }
124
125 return ret;
126}
127EXPORT_SYMBOL(dma_alloc_coherent);
128
129void
130dma_free_coherent(struct device *dev, size_t size, void *vaddr,
131 dma_addr_t dma_handle)
132{
133 __free_dma_pages((unsigned long)vaddr, get_pages(size));
134}
135EXPORT_SYMBOL(dma_free_coherent);
136
137/*
138 * Dummy functions defined for some existing drivers
139 */
140
141dma_addr_t
142dma_map_single(struct device *dev, void *ptr, size_t size,
143 enum dma_data_direction direction)
144{
145 BUG_ON(direction == DMA_NONE);
146
147 invalidate_dcache_range((unsigned long)ptr,
148 (unsigned long)ptr + size);
149
150 return (dma_addr_t) ptr;
151}
152EXPORT_SYMBOL(dma_map_single);
153
154int
155dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
156 enum dma_data_direction direction)
157{
158 int i;
159
160 BUG_ON(direction == DMA_NONE);
161
162 for (i = 0; i < nents; i++)
163 invalidate_dcache_range(sg_dma_address(&sg[i]),
164 sg_dma_address(&sg[i]) +
165 sg_dma_len(&sg[i]));
166
167 return nents;
168}
169EXPORT_SYMBOL(dma_map_sg);
170
171void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
172 enum dma_data_direction direction)
173{
174 BUG_ON(direction == DMA_NONE);
175}
176EXPORT_SYMBOL(dma_unmap_single);
177
178void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
179 int nhwentries, enum dma_data_direction direction)
180{
181 BUG_ON(direction == DMA_NONE);
182}
183EXPORT_SYMBOL(dma_unmap_sg);
diff --git a/arch/blackfin/kernel/dualcore_test.c b/arch/blackfin/kernel/dualcore_test.c
new file mode 100644
index 000000000000..8b89c99f9dfa
--- /dev/null
+++ b/arch/blackfin/kernel/dualcore_test.c
@@ -0,0 +1,49 @@
1/*
2 * File: arch/blackfin/kernel/dualcore_test.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: Small test code for CoreB on a BF561
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/init.h>
31#include <linux/module.h>
32
33static int *testarg = (int*)0xfeb00000;
34
35static int test_init(void)
36{
37 *testarg = 1;
38 printk("Dual core test module inserted: set testarg = [%d]\n @ [%p]\n",
39 *testarg, testarg);
40 return 0;
41}
42
43static void test_exit(void)
44{
45 printk("Dual core test module removed: testarg = [%d]\n", *testarg);
46}
47
48module_init(test_init);
49module_exit(test_exit);
diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S
new file mode 100644
index 000000000000..5880b270bd50
--- /dev/null
+++ b/arch/blackfin/kernel/entry.S
@@ -0,0 +1,94 @@
1/*
2 * File: arch/blackfin/kernel/entry.S
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/linkage.h>
31#include <asm/thread_info.h>
32#include <asm/errno.h>
33#include <asm/asm-offsets.h>
34
35#include <asm/mach-common/context.S>
36
37#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
38.section .l1.text
39#else
40.text
41#endif
42
43ENTRY(_ret_from_fork)
44 SP += -12;
45 call _schedule_tail;
46 SP += 12;
47 r0 = [sp + PT_IPEND];
48 cc = bittst(r0,1);
49 if cc jump .Lin_kernel;
50 RESTORE_CONTEXT
51 rti;
52.Lin_kernel:
53 bitclr(r0,1);
54 [sp + PT_IPEND] = r0;
55 /* do a 'fake' RTI by jumping to [RETI]
56 * to avoid clearing supervisor mode in child
57 */
58 RESTORE_ALL_SYS
59 p0 = reti;
60 jump (p0);
61
62ENTRY(_sys_fork)
63 r0 = -EINVAL;
64 rts;
65
66ENTRY(_sys_vfork)
67 r0 = sp;
68 r0 += 24;
69 [--sp] = rets;
70 SP += -12;
71 call _bfin_vfork;
72 SP += 12;
73 rets = [sp++];
74 rts;
75
76ENTRY(_sys_clone)
77 r0 = sp;
78 r0 += 24;
79 [--sp] = rets;
80 SP += -12;
81 call _bfin_clone;
82 SP += 12;
83 rets = [sp++];
84 rts;
85
86ENTRY(_sys_rt_sigreturn)
87 r0 = sp;
88 r0 += 24;
89 [--sp] = rets;
90 SP += -12;
91 call _do_rt_sigreturn;
92 SP += 12;
93 rets = [sp++];
94 rts;
diff --git a/arch/blackfin/kernel/flat.c b/arch/blackfin/kernel/flat.c
new file mode 100644
index 000000000000..a92587b628b5
--- /dev/null
+++ b/arch/blackfin/kernel/flat.c
@@ -0,0 +1,101 @@
1/*
2 * arch/blackfin/kernel/flat.c
3 *
4 * Copyright (C) 2007 Analog Devices, Inc.
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 as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/module.h>
22#include <linux/sched.h>
23#include <linux/flat.h>
24
25#define FLAT_BFIN_RELOC_TYPE_16_BIT 0
26#define FLAT_BFIN_RELOC_TYPE_16H_BIT 1
27#define FLAT_BFIN_RELOC_TYPE_32_BIT 2
28
29unsigned long bfin_get_addr_from_rp(unsigned long *ptr,
30 unsigned long relval,
31 unsigned long flags,
32 unsigned long *persistent)
33{
34 unsigned short *usptr = (unsigned short *)ptr;
35 int type = (relval >> 26) & 7;
36 unsigned long val;
37
38 switch (type) {
39 case FLAT_BFIN_RELOC_TYPE_16_BIT:
40 case FLAT_BFIN_RELOC_TYPE_16H_BIT:
41 usptr = (unsigned short *)ptr;
42 pr_debug("*usptr = %x", get_unaligned(usptr));
43 val = get_unaligned(usptr);
44 val += *persistent;
45 break;
46
47 case FLAT_BFIN_RELOC_TYPE_32_BIT:
48 pr_debug("*ptr = %lx", get_unaligned(ptr));
49 val = get_unaligned(ptr);
50 break;
51
52 default:
53 pr_debug("BINFMT_FLAT: Unknown relocation type %x\n",
54 type);
55
56 return 0;
57 }
58
59 /*
60 * Stack-relative relocs contain the offset into the stack, we
61 * have to add the stack's start address here and return 1 from
62 * flat_addr_absolute to prevent the normal address calculations
63 */
64 if (relval & (1 << 29))
65 return val + current->mm->context.end_brk;
66
67 if ((flags & FLAT_FLAG_GOTPIC) == 0)
68 val = htonl(val);
69 return val;
70}
71EXPORT_SYMBOL(bfin_get_addr_from_rp);
72
73/*
74 * Insert the address ADDR into the symbol reference at RP;
75 * RELVAL is the raw relocation-table entry from which RP is derived
76 */
77void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
78 unsigned long relval)
79{
80 unsigned short *usptr = (unsigned short *)ptr;
81 int type = (relval >> 26) & 7;
82
83 switch (type) {
84 case FLAT_BFIN_RELOC_TYPE_16_BIT:
85 put_unaligned(addr, usptr);
86 pr_debug("new value %x at %p", get_unaligned(usptr),
87 usptr);
88 break;
89
90 case FLAT_BFIN_RELOC_TYPE_16H_BIT:
91 put_unaligned(addr >> 16, usptr);
92 pr_debug("new value %x", get_unaligned(usptr));
93 break;
94
95 case FLAT_BFIN_RELOC_TYPE_32_BIT:
96 put_unaligned(addr, ptr);
97 pr_debug("new ptr =%lx", get_unaligned(ptr));
98 break;
99 }
100}
101EXPORT_SYMBOL(bfin_put_addr_at_rp);
diff --git a/arch/blackfin/kernel/init_task.c b/arch/blackfin/kernel/init_task.c
new file mode 100644
index 000000000000..b45188f8512e
--- /dev/null
+++ b/arch/blackfin/kernel/init_task.c
@@ -0,0 +1,60 @@
1/*
2 * File: arch/blackfin/kernel/init_task.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: This file contains the simple DMA Implementation for Blackfin
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/mm.h>
31#include <linux/module.h>
32#include <linux/init_task.h>
33#include <linux/mqueue.h>
34
35static struct fs_struct init_fs = INIT_FS;
36static struct files_struct init_files = INIT_FILES;
37static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
38static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
39
40struct mm_struct init_mm = INIT_MM(init_mm);
41EXPORT_SYMBOL(init_mm);
42
43/*
44 * Initial task structure.
45 *
46 * All other task structs will be allocated on slabs in fork.c
47 */
48struct task_struct init_task = INIT_TASK(init_task);
49EXPORT_SYMBOL(init_task);
50
51/*
52 * Initial thread structure.
53 *
54 * We need to make sure that this is 8192-byte aligned due to the
55 * way process stacks are handled. This is done by having a special
56 * "init_task" linker map entry.
57 */
58union thread_union init_thread_union
59 __attribute__ ((__section__(".data.init_task"))) = {
60INIT_THREAD_INFO(init_task)};
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
new file mode 100644
index 000000000000..df5bf022cf79
--- /dev/null
+++ b/arch/blackfin/kernel/irqchip.c
@@ -0,0 +1,147 @@
1/*
2 * File: arch/blackfin/kernel/irqchip.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: This file contains the simple DMA Implementation for Blackfin
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/kernel_stat.h>
31#include <linux/module.h>
32#include <linux/random.h>
33#include <linux/seq_file.h>
34#include <linux/kallsyms.h>
35#include <linux/interrupt.h>
36#include <linux/irq.h>
37
38static unsigned long irq_err_count;
39static spinlock_t irq_controller_lock;
40
41/*
42 * Dummy mask/unmask handler
43 */
44void dummy_mask_unmask_irq(unsigned int irq)
45{
46}
47
48void ack_bad_irq(unsigned int irq)
49{
50 irq_err_count += 1;
51 printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
52}
53EXPORT_SYMBOL(ack_bad_irq);
54
55static struct irq_chip bad_chip = {
56 .ack = dummy_mask_unmask_irq,
57 .mask = dummy_mask_unmask_irq,
58 .unmask = dummy_mask_unmask_irq,
59};
60
61static struct irq_desc bad_irq_desc = {
62 .chip = &bad_chip,
63 .handle_irq = handle_bad_irq,
64 .depth = 1,
65};
66
67int show_interrupts(struct seq_file *p, void *v)
68{
69 int i = *(loff_t *) v;
70 struct irqaction *action;
71 unsigned long flags;
72
73 if (i < NR_IRQS) {
74 spin_lock_irqsave(&irq_desc[i].lock, flags);
75 action = irq_desc[i].action;
76 if (!action)
77 goto unlock;
78
79 seq_printf(p, "%3d: %10u ", i, kstat_irqs(i));
80 seq_printf(p, " %s", action->name);
81 for (action = action->next; action; action = action->next)
82 seq_printf(p, ", %s", action->name);
83
84 seq_putc(p, '\n');
85 unlock:
86 spin_unlock_irqrestore(&irq_desc[i].lock, flags);
87 } else if (i == NR_IRQS) {
88 seq_printf(p, "Err: %10lu\n", irq_err_count);
89 }
90 return 0;
91}
92
93/*
94 * do_IRQ handles all hardware IRQ's. Decoded IRQs should not
95 * come via this function. Instead, they should provide their
96 * own 'handler'
97 */
98
99#ifdef CONFIG_DO_IRQ_L1
100asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)__attribute__((l1_text));
101#endif
102
103asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
104{
105 struct pt_regs *old_regs;
106 struct irq_desc *desc = irq_desc + irq;
107 unsigned short pending, other_ints;
108
109 old_regs = set_irq_regs(regs);
110
111 /*
112 * Some hardware gives randomly wrong interrupts. Rather
113 * than crashing, do something sensible.
114 */
115 if (irq >= NR_IRQS)
116 desc = &bad_irq_desc;
117
118 irq_enter();
119
120 generic_handle_irq(irq);
121
122 /* If we're the only interrupt running (ignoring IRQ15 which is for
123 syscalls), lower our priority to IRQ14 so that softirqs run at
124 that level. If there's another, lower-level interrupt, irq_exit
125 will defer softirqs to that. */
126 CSYNC();
127 pending = bfin_read_IPEND() & ~0x8000;
128 other_ints = pending & (pending - 1);
129 if (other_ints == 0)
130 lower_to_irq14();
131 irq_exit();
132
133 set_irq_regs(old_regs);
134}
135
136void __init init_IRQ(void)
137{
138 struct irq_desc *desc;
139 int irq;
140
141 spin_lock_init(&irq_controller_lock);
142 for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
143 *desc = bad_irq_desc;
144 }
145
146 init_arch_irq();
147}
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c
new file mode 100644
index 000000000000..372f756f1ad9
--- /dev/null
+++ b/arch/blackfin/kernel/module.c
@@ -0,0 +1,429 @@
1/*
2 * File: arch/blackfin/kernel/module.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30
31#include <linux/moduleloader.h>
32#include <linux/elf.h>
33#include <linux/vmalloc.h>
34#include <linux/fs.h>
35#include <linux/string.h>
36#include <linux/kernel.h>
37#include <asm/dma.h>
38#include <asm/cacheflush.h>
39
40/*
41 * handle arithmetic relocations.
42 * See binutils/bfd/elf32-bfin.c for more details
43 */
44#define RELOC_STACK_SIZE 100
45static uint32_t reloc_stack[RELOC_STACK_SIZE];
46static unsigned int reloc_stack_tos;
47
48#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1)
49
50static void reloc_stack_push(uint32_t value)
51{
52 reloc_stack[reloc_stack_tos++] = value;
53}
54
55static uint32_t reloc_stack_pop(void)
56{
57 return reloc_stack[--reloc_stack_tos];
58}
59
60static uint32_t reloc_stack_operate(unsigned int oper, struct module *mod)
61{
62 uint32_t value;
63
64 switch (oper) {
65 case R_add:
66 value = reloc_stack[reloc_stack_tos - 2] +
67 reloc_stack[reloc_stack_tos - 1];
68 reloc_stack_tos -= 2;
69 break;
70 case R_sub:
71 value = reloc_stack[reloc_stack_tos - 2] -
72 reloc_stack[reloc_stack_tos - 1];
73 reloc_stack_tos -= 2;
74 break;
75 case R_mult:
76 value = reloc_stack[reloc_stack_tos - 2] *
77 reloc_stack[reloc_stack_tos - 1];
78 reloc_stack_tos -= 2;
79 break;
80 case R_div:
81 value = reloc_stack[reloc_stack_tos - 2] /
82 reloc_stack[reloc_stack_tos - 1];
83 reloc_stack_tos -= 2;
84 break;
85 case R_mod:
86 value = reloc_stack[reloc_stack_tos - 2] %
87 reloc_stack[reloc_stack_tos - 1];
88 reloc_stack_tos -= 2;
89 break;
90 case R_lshift:
91 value = reloc_stack[reloc_stack_tos - 2] <<
92 reloc_stack[reloc_stack_tos - 1];
93 reloc_stack_tos -= 2;
94 break;
95 case R_rshift:
96 value = reloc_stack[reloc_stack_tos - 2] >>
97 reloc_stack[reloc_stack_tos - 1];
98 reloc_stack_tos -= 2;
99 break;
100 case R_and:
101 value = reloc_stack[reloc_stack_tos - 2] &
102 reloc_stack[reloc_stack_tos - 1];
103 reloc_stack_tos -= 2;
104 break;
105 case R_or:
106 value = reloc_stack[reloc_stack_tos - 2] |
107 reloc_stack[reloc_stack_tos - 1];
108 reloc_stack_tos -= 2;
109 break;
110 case R_xor:
111 value = reloc_stack[reloc_stack_tos - 2] ^
112 reloc_stack[reloc_stack_tos - 1];
113 reloc_stack_tos -= 2;
114 break;
115 case R_land:
116 value = reloc_stack[reloc_stack_tos - 2] &&
117 reloc_stack[reloc_stack_tos - 1];
118 reloc_stack_tos -= 2;
119 break;
120 case R_lor:
121 value = reloc_stack[reloc_stack_tos - 2] ||
122 reloc_stack[reloc_stack_tos - 1];
123 reloc_stack_tos -= 2;
124 break;
125 case R_neg:
126 value = -reloc_stack[reloc_stack_tos - 1];
127 reloc_stack_tos--;
128 break;
129 case R_comp:
130 value = ~reloc_stack[reloc_stack_tos - 1];
131 reloc_stack_tos -= 1;
132 break;
133 default:
134 printk(KERN_WARNING "module %s: unhandled reloction\n",
135 mod->name);
136 return 0;
137 }
138
139 /* now push the new value back on stack */
140 reloc_stack_push(value);
141
142 return value;
143}
144
145void *module_alloc(unsigned long size)
146{
147 if (size == 0)
148 return NULL;
149 return vmalloc(size);
150}
151
152/* Free memory returned from module_alloc */
153void module_free(struct module *mod, void *module_region)
154{
155 vfree(module_region);
156}
157
158/* Transfer the section to the L1 memory */
159int
160module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
161 char *secstrings, struct module *mod)
162{
163 Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
164 void *dest = NULL;
165
166 for (s = sechdrs; s < sechdrs_end; ++s) {
167 if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) ||
168 ((strcmp(".text", secstrings + s->sh_name)==0) &&
169 (hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) {
170 mod->arch.text_l1 = s;
171 dest = l1_inst_sram_alloc(s->sh_size);
172 if (dest == NULL) {
173 printk(KERN_ERR
174 "module %s: L1 instruction memory allocation failed\n",
175 mod->name);
176 return -1;
177 }
178 dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
179 s->sh_flags &= ~SHF_ALLOC;
180 s->sh_addr = (unsigned long)dest;
181 }
182 if ((strcmp(".l1.data", secstrings + s->sh_name) == 0)||
183 ((strcmp(".data", secstrings + s->sh_name)==0) &&
184 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
185 mod->arch.data_a_l1 = s;
186 dest = l1_data_sram_alloc(s->sh_size);
187 if (dest == NULL) {
188 printk(KERN_ERR
189 "module %s: L1 data memory allocation failed\n",
190 mod->name);
191 return -1;
192 }
193 memcpy(dest, (void *)s->sh_addr, s->sh_size);
194 s->sh_flags &= ~SHF_ALLOC;
195 s->sh_addr = (unsigned long)dest;
196 }
197 if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 ||
198 ((strcmp(".bss", secstrings + s->sh_name)==0) &&
199 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
200 mod->arch.bss_a_l1 = s;
201 dest = l1_data_sram_alloc(s->sh_size);
202 if (dest == NULL) {
203 printk(KERN_ERR
204 "module %s: L1 data memory allocation failed\n",
205 mod->name);
206 return -1;
207 }
208 memset(dest, 0, s->sh_size);
209 s->sh_flags &= ~SHF_ALLOC;
210 s->sh_addr = (unsigned long)dest;
211 }
212 if (strcmp(".l1.data.B", secstrings + s->sh_name) == 0) {
213 mod->arch.data_b_l1 = s;
214 dest = l1_data_B_sram_alloc(s->sh_size);
215 if (dest == NULL) {
216 printk(KERN_ERR
217 "module %s: L1 data memory allocation failed\n",
218 mod->name);
219 return -1;
220 }
221 memcpy(dest, (void *)s->sh_addr, s->sh_size);
222 s->sh_flags &= ~SHF_ALLOC;
223 s->sh_addr = (unsigned long)dest;
224 }
225 if (strcmp(".l1.bss.B", secstrings + s->sh_name) == 0) {
226 mod->arch.bss_b_l1 = s;
227 dest = l1_data_B_sram_alloc(s->sh_size);
228 if (dest == NULL) {
229 printk(KERN_ERR
230 "module %s: L1 data memory allocation failed\n",
231 mod->name);
232 return -1;
233 }
234 memset(dest, 0, s->sh_size);
235 s->sh_flags &= ~SHF_ALLOC;
236 s->sh_addr = (unsigned long)dest;
237 }
238 }
239 return 0;
240}
241
242int
243apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
244 unsigned int symindex, unsigned int relsec, struct module *me)
245{
246 printk(KERN_ERR "module %s: .rel unsupported\n", me->name);
247 return -ENOEXEC;
248}
249
250/*************************************************************************/
251/* FUNCTION : apply_relocate_add */
252/* ABSTRACT : Blackfin specific relocation handling for the loadable */
253/* modules. Modules are expected to be .o files. */
254/* Arithmetic relocations are handled. */
255/* We do not expect LSETUP to be split and hence is not */
256/* handled. */
257/* R_byte and R_byte2 are also not handled as the gas */
258/* does not generate it. */
259/*************************************************************************/
260int
261apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
262 unsigned int symindex, unsigned int relsec,
263 struct module *mod)
264{
265 unsigned int i;
266 unsigned short tmp;
267 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
268 Elf32_Sym *sym;
269 uint32_t *location32;
270 uint16_t *location16;
271 uint32_t value;
272
273 pr_debug("Applying relocate section %u to %u\n", relsec,
274 sechdrs[relsec].sh_info);
275 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
276 /* This is where to make the change */
277 location16 =
278 (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr +
279 rel[i].r_offset);
280 location32 = (uint32_t *) location16;
281 /* This is the symbol it is referring to. Note that all
282 undefined symbols have been resolved. */
283 sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
284 + ELF32_R_SYM(rel[i].r_info);
285 if (is_reloc_stack_empty()) {
286 value = sym->st_value;
287 } else {
288 value = reloc_stack_pop();
289 }
290 value += rel[i].r_addend;
291 pr_debug("location is %x, value is %x type is %d \n",
292 (unsigned int) location32, value,
293 ELF32_R_TYPE(rel[i].r_info));
294
295 switch (ELF32_R_TYPE(rel[i].r_info)) {
296
297 case R_pcrel24:
298 case R_pcrel24_jump_l:
299 /* Add the value, subtract its postition */
300 location16 =
301 (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].
302 sh_addr + rel[i].r_offset - 2);
303 location32 = (uint32_t *) location16;
304 value -= (uint32_t) location32;
305 value >>= 1;
306 pr_debug("value is %x, before %x-%x after %x-%x\n", value,
307 *location16, *(location16 + 1),
308 (*location16 & 0xff00) | (value >> 16 & 0x00ff),
309 value & 0xffff);
310 *location16 =
311 (*location16 & 0xff00) | (value >> 16 & 0x00ff);
312 *(location16 + 1) = value & 0xffff;
313 break;
314 case R_pcrel12_jump:
315 case R_pcrel12_jump_s:
316 value -= (uint32_t) location32;
317 value >>= 1;
318 *location16 = (value & 0xfff);
319 break;
320 case R_pcrel10:
321 value -= (uint32_t) location32;
322 value >>= 1;
323 *location16 = (value & 0x3ff);
324 break;
325 case R_luimm16:
326 pr_debug("before %x after %x\n", *location16,
327 (value & 0xffff));
328 tmp = (value & 0xffff);
329 if((unsigned long)location16 >= L1_CODE_START) {
330 dma_memcpy(location16, &tmp, 2);
331 } else
332 *location16 = tmp;
333 break;
334 case R_huimm16:
335 pr_debug("before %x after %x\n", *location16,
336 ((value >> 16) & 0xffff));
337 tmp = ((value >> 16) & 0xffff);
338 if((unsigned long)location16 >= L1_CODE_START) {
339 dma_memcpy(location16, &tmp, 2);
340 } else
341 *location16 = tmp;
342 break;
343 case R_rimm16:
344 *location16 = (value & 0xffff);
345 break;
346 case R_byte4_data:
347 pr_debug("before %x after %x\n", *location32, value);
348 *location32 = value;
349 break;
350 case R_push:
351 reloc_stack_push(value);
352 break;
353 case R_const:
354 reloc_stack_push(rel[i].r_addend);
355 break;
356 case R_add:
357 case R_sub:
358 case R_mult:
359 case R_div:
360 case R_mod:
361 case R_lshift:
362 case R_rshift:
363 case R_and:
364 case R_or:
365 case R_xor:
366 case R_land:
367 case R_lor:
368 case R_neg:
369 case R_comp:
370 reloc_stack_operate(ELF32_R_TYPE(rel[i].r_info), mod);
371 break;
372 default:
373 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
374 mod->name, ELF32_R_TYPE(rel[i].r_info));
375 return -ENOEXEC;
376 }
377 }
378 return 0;
379}
380
381int
382module_finalize(const Elf_Ehdr * hdr,
383 const Elf_Shdr * sechdrs, struct module *mod)
384{
385 unsigned int i, strindex = 0, symindex = 0;
386 char *secstrings;
387
388 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
389
390 for (i = 1; i < hdr->e_shnum; i++) {
391 /* Internal symbols and strings. */
392 if (sechdrs[i].sh_type == SHT_SYMTAB) {
393 symindex = i;
394 strindex = sechdrs[i].sh_link;
395 }
396 }
397
398 for (i = 1; i < hdr->e_shnum; i++) {
399 const char *strtab = (char *)sechdrs[strindex].sh_addr;
400 unsigned int info = sechdrs[i].sh_info;
401
402 /* Not a valid relocation section? */
403 if (info >= hdr->e_shnum)
404 continue;
405
406 if ((sechdrs[i].sh_type == SHT_RELA) &&
407 ((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0)||
408 ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
409 (hdr->e_flags & FLG_CODE_IN_L1)))) {
410 apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
411 symindex, i, mod);
412 }
413 }
414 return 0;
415}
416
417void module_arch_cleanup(struct module *mod)
418{
419 if ((mod->arch.text_l1) && (mod->arch.text_l1->sh_addr))
420 l1_inst_sram_free((void*)mod->arch.text_l1->sh_addr);
421 if ((mod->arch.data_a_l1) && (mod->arch.data_a_l1->sh_addr))
422 l1_data_sram_free((void*)mod->arch.data_a_l1->sh_addr);
423 if ((mod->arch.bss_a_l1) && (mod->arch.bss_a_l1->sh_addr))
424 l1_data_sram_free((void*)mod->arch.bss_a_l1->sh_addr);
425 if ((mod->arch.data_b_l1) && (mod->arch.data_b_l1->sh_addr))
426 l1_data_B_sram_free((void*)mod->arch.data_b_l1->sh_addr);
427 if ((mod->arch.bss_b_l1) && (mod->arch.bss_b_l1->sh_addr))
428 l1_data_B_sram_free((void*)mod->arch.bss_b_l1->sh_addr);
429}
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
new file mode 100644
index 000000000000..3eff7439d8d3
--- /dev/null
+++ b/arch/blackfin/kernel/process.c
@@ -0,0 +1,394 @@
1/*
2 * File: arch/blackfin/kernel/process.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: Blackfin architecture-dependent process handling.
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/module.h>
31#include <linux/smp_lock.h>
32#include <linux/unistd.h>
33#include <linux/user.h>
34#include <linux/a.out.h>
35
36#include <asm/blackfin.h>
37#include <asm/uaccess.h>
38
39#define LED_ON 0
40#define LED_OFF 1
41
42asmlinkage void ret_from_fork(void);
43
44/* Points to the SDRAM backup memory for the stack that is currently in
45 * L1 scratchpad memory.
46 */
47void *current_l1_stack_save;
48
49/* The number of tasks currently using a L1 stack area. The SRAM is
50 * allocated/deallocated whenever this changes from/to zero.
51 */
52int nr_l1stack_tasks;
53
54/* Start and length of the area in L1 scratchpad memory which we've allocated
55 * for process stacks.
56 */
57void *l1_stack_base;
58unsigned long l1_stack_len;
59
60/*
61 * Powermanagement idle function, if any..
62 */
63void (*pm_idle)(void) = NULL;
64EXPORT_SYMBOL(pm_idle);
65
66void (*pm_power_off)(void) = NULL;
67EXPORT_SYMBOL(pm_power_off);
68
69/*
70 * We are using a different LED from the one used to indicate timer interrupt.
71 */
72#if defined(CONFIG_BFIN_IDLE_LED)
73static inline void leds_switch(int flag)
74{
75 unsigned short tmp = 0;
76
77 tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
78 SSYNC();
79
80 if (flag == LED_ON)
81 tmp &= ~CONFIG_BFIN_IDLE_LED_PIN; /* light on */
82 else
83 tmp |= CONFIG_BFIN_IDLE_LED_PIN; /* light off */
84
85 bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp);
86 SSYNC();
87
88}
89#else
90static inline void leds_switch(int flag)
91{
92}
93#endif
94
95/*
96 * The idle loop on BFIN
97 */
98#ifdef CONFIG_IDLE_L1
99void default_idle(void)__attribute__((l1_text));
100void cpu_idle(void)__attribute__((l1_text));
101#endif
102
103void default_idle(void)
104{
105 while (!need_resched()) {
106 leds_switch(LED_OFF);
107 local_irq_disable();
108 if (likely(!need_resched()))
109 idle_with_irq_disabled();
110 local_irq_enable();
111 leds_switch(LED_ON);
112 }
113}
114
115void (*idle)(void) = default_idle;
116
117/*
118 * The idle thread. There's no useful work to be
119 * done, so just try to conserve power and have a
120 * low exit latency (ie sit in a loop waiting for
121 * somebody to say that they'd like to reschedule)
122 */
123void cpu_idle(void)
124{
125 /* endless idle loop with no priority at all */
126 while (1) {
127 idle();
128 preempt_enable_no_resched();
129 schedule();
130 preempt_disable();
131 }
132}
133
134void machine_restart(char *__unused)
135{
136#if defined(CONFIG_BLKFIN_CACHE)
137 bfin_write_IMEM_CONTROL(0x01);
138 SSYNC();
139#endif
140 bfin_reset();
141 /* Dont do anything till the reset occurs */
142 while (1) {
143 SSYNC();
144 }
145}
146
147void machine_halt(void)
148{
149 for (;;)
150 asm volatile ("idle");
151}
152
153void machine_power_off(void)
154{
155 for (;;)
156 asm volatile ("idle");
157}
158
159void show_regs(struct pt_regs *regs)
160{
161 printk(KERN_NOTICE "\n");
162 printk(KERN_NOTICE
163 "PC: %08lu Status: %04lu SysStatus: %04lu RETS: %08lu\n",
164 regs->pc, regs->astat, regs->seqstat, regs->rets);
165 printk(KERN_NOTICE
166 "A0.x: %08lx A0.w: %08lx A1.x: %08lx A1.w: %08lx\n",
167 regs->a0x, regs->a0w, regs->a1x, regs->a1w);
168 printk(KERN_NOTICE "P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n",
169 regs->p0, regs->p1, regs->p2, regs->p3);
170 printk(KERN_NOTICE "P4: %08lx P5: %08lx\n", regs->p4, regs->p5);
171 printk(KERN_NOTICE "R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n",
172 regs->r0, regs->r1, regs->r2, regs->r3);
173 printk(KERN_NOTICE "R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n",
174 regs->r4, regs->r5, regs->r6, regs->r7);
175
176 if (!(regs->ipend))
177 printk("USP: %08lx\n", rdusp());
178}
179
180/* Fill in the fpu structure for a core dump. */
181
182int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs)
183{
184 return 1;
185}
186
187/*
188 * This gets run with P1 containing the
189 * function to call, and R1 containing
190 * the "args". Note P0 is clobbered on the way here.
191 */
192void kernel_thread_helper(void);
193__asm__(".section .text\n"
194 ".align 4\n"
195 "_kernel_thread_helper:\n\t"
196 "\tsp += -12;\n\t"
197 "\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous");
198
199/*
200 * Create a kernel thread.
201 */
202pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags)
203{
204 struct pt_regs regs;
205
206 memset(&regs, 0, sizeof(regs));
207
208 regs.r1 = (unsigned long)arg;
209 regs.p1 = (unsigned long)fn;
210 regs.pc = (unsigned long)kernel_thread_helper;
211 regs.orig_p0 = -1;
212 /* Set bit 2 to tell ret_from_fork we should be returning to kernel
213 mode. */
214 regs.ipend = 0x8002;
215 __asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):);
216 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,
217 NULL);
218}
219
220void flush_thread(void)
221{
222}
223
224asmlinkage int bfin_vfork(struct pt_regs *regs)
225{
226 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL,
227 NULL);
228}
229
230asmlinkage int bfin_clone(struct pt_regs *regs)
231{
232 unsigned long clone_flags;
233 unsigned long newsp;
234
235 /* syscall2 puts clone_flags in r0 and usp in r1 */
236 clone_flags = regs->r0;
237 newsp = regs->r1;
238 if (!newsp)
239 newsp = rdusp();
240 else
241 newsp -= 12;
242 return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
243}
244
245int
246copy_thread(int nr, unsigned long clone_flags,
247 unsigned long usp, unsigned long topstk,
248 struct task_struct *p, struct pt_regs *regs)
249{
250 struct pt_regs *childregs;
251
252 childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
253 *childregs = *regs;
254 childregs->r0 = 0;
255
256 p->thread.usp = usp;
257 p->thread.ksp = (unsigned long)childregs;
258 p->thread.pc = (unsigned long)ret_from_fork;
259
260 return 0;
261}
262
263/*
264 * fill in the user structure for a core dump..
265 */
266void dump_thread(struct pt_regs *regs, struct user *dump)
267{
268 dump->magic = CMAGIC;
269 dump->start_code = 0;
270 dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
271 dump->u_tsize = ((unsigned long)current->mm->end_code) >> PAGE_SHIFT;
272 dump->u_dsize = ((unsigned long)(current->mm->brk +
273 (PAGE_SIZE - 1))) >> PAGE_SHIFT;
274 dump->u_dsize -= dump->u_tsize;
275 dump->u_ssize = 0;
276
277 if (dump->start_stack < TASK_SIZE)
278 dump->u_ssize =
279 ((unsigned long)(TASK_SIZE -
280 dump->start_stack)) >> PAGE_SHIFT;
281
282 dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
283
284 dump->regs.r0 = regs->r0;
285 dump->regs.r1 = regs->r1;
286 dump->regs.r2 = regs->r2;
287 dump->regs.r3 = regs->r3;
288 dump->regs.r4 = regs->r4;
289 dump->regs.r5 = regs->r5;
290 dump->regs.r6 = regs->r6;
291 dump->regs.r7 = regs->r7;
292 dump->regs.p0 = regs->p0;
293 dump->regs.p1 = regs->p1;
294 dump->regs.p2 = regs->p2;
295 dump->regs.p3 = regs->p3;
296 dump->regs.p4 = regs->p4;
297 dump->regs.p5 = regs->p5;
298 dump->regs.orig_p0 = regs->orig_p0;
299 dump->regs.a0w = regs->a0w;
300 dump->regs.a1w = regs->a1w;
301 dump->regs.a0x = regs->a0x;
302 dump->regs.a1x = regs->a1x;
303 dump->regs.rets = regs->rets;
304 dump->regs.astat = regs->astat;
305 dump->regs.pc = regs->pc;
306}
307
308/*
309 * sys_execve() executes a new program.
310 */
311
312asmlinkage int sys_execve(char *name, char **argv, char **envp)
313{
314 int error;
315 char *filename;
316 struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
317
318 lock_kernel();
319 filename = getname(name);
320 error = PTR_ERR(filename);
321 if (IS_ERR(filename))
322 goto out;
323 error = do_execve(filename, argv, envp, regs);
324 putname(filename);
325 out:
326 unlock_kernel();
327 return error;
328}
329
330unsigned long get_wchan(struct task_struct *p)
331{
332 unsigned long fp, pc;
333 unsigned long stack_page;
334 int count = 0;
335 if (!p || p == current || p->state == TASK_RUNNING)
336 return 0;
337
338 stack_page = (unsigned long)p;
339 fp = p->thread.usp;
340 do {
341 if (fp < stack_page + sizeof(struct thread_info) ||
342 fp >= 8184 + stack_page)
343 return 0;
344 pc = ((unsigned long *)fp)[1];
345 if (!in_sched_functions(pc))
346 return pc;
347 fp = *(unsigned long *)fp;
348 }
349 while (count++ < 16);
350 return 0;
351}
352
353#if defined(CONFIG_ACCESS_CHECK)
354int _access_ok(unsigned long addr, unsigned long size)
355{
356
357 if (addr > (addr + size))
358 return 0;
359 if (segment_eq(get_fs(),KERNEL_DS))
360 return 1;
361#ifdef CONFIG_MTD_UCLINUX
362 if (addr >= memory_start && (addr + size) <= memory_end)
363 return 1;
364 if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end)
365 return 1;
366#else
367 if (addr >= memory_start && (addr + size) <= physical_mem_end)
368 return 1;
369#endif
370 if (addr >= (unsigned long)__init_begin &&
371 addr + size <= (unsigned long)__init_end)
372 return 1;
373 if (addr >= L1_SCRATCH_START
374 && addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH)
375 return 1;
376#if L1_CODE_LENGTH != 0
377 if (addr >= L1_CODE_START + (_etext_l1 - _stext_l1)
378 && addr + size <= L1_CODE_START + L1_CODE_LENGTH)
379 return 1;
380#endif
381#if L1_DATA_A_LENGTH != 0
382 if (addr >= L1_DATA_A_START + (_ebss_l1 - _sdata_l1)
383 && addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH)
384 return 1;
385#endif
386#if L1_DATA_B_LENGTH != 0
387 if (addr >= L1_DATA_B_START
388 && addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH)
389 return 1;
390#endif
391 return 0;
392}
393EXPORT_SYMBOL(_access_ok);
394#endif /* CONFIG_ACCESS_CHECK */
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
new file mode 100644
index 000000000000..d7c8e514cb92
--- /dev/null
+++ b/arch/blackfin/kernel/ptrace.c
@@ -0,0 +1,430 @@
1/*
2 * File: arch/blackfin/kernel/ptrace.c
3 * Based on: Taken from linux/kernel/ptrace.c
4 * Author: linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
5 *
6 * Created: 1/23/92
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/kernel.h>
31#include <linux/sched.h>
32#include <linux/mm.h>
33#include <linux/smp.h>
34#include <linux/smp_lock.h>
35#include <linux/errno.h>
36#include <linux/ptrace.h>
37#include <linux/user.h>
38#include <linux/signal.h>
39
40#include <asm/uaccess.h>
41#include <asm/page.h>
42#include <asm/pgtable.h>
43#include <asm/system.h>
44#include <asm/processor.h>
45#include <asm/asm-offsets.h>
46#include <asm/dma.h>
47
48#define MAX_SHARED_LIBS 3
49#define TEXT_OFFSET 0
50/*
51 * does not yet catch signals sent when the child dies.
52 * in exit.c or in signal.c.
53 */
54
55/* determines which bits in the SYSCFG reg the user has access to. */
56/* 1 = access 0 = no access */
57#define SYSCFG_MASK 0x0007 /* SYSCFG reg */
58/* sets the trace bits. */
59#define TRACE_BITS 0x0001
60
61/* Find the stack offset for a register, relative to thread.esp0. */
62#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
63
64/*
65 * Get the address of the live pt_regs for the specified task.
66 * These are saved onto the top kernel stack when the process
67 * is not running.
68 *
69 * Note: if a user thread is execve'd from kernel space, the
70 * kernel stack will not be empty on entry to the kernel, so
71 * ptracing these tasks will fail.
72 */
73static inline struct pt_regs *get_user_regs(struct task_struct *task)
74{
75 return (struct pt_regs *)
76 ((unsigned long)task->thread_info +
77 (THREAD_SIZE - sizeof(struct pt_regs)));
78}
79
80/*
81 * Get all user integer registers.
82 */
83static inline int ptrace_getregs(struct task_struct *tsk, void __user * uregs)
84{
85 struct pt_regs *regs = get_user_regs(tsk);
86 return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
87}
88
89/* Mapping from PT_xxx to the stack offset at which the register is
90 * saved. Notice that usp has no stack-slot and needs to be treated
91 * specially (see get_reg/put_reg below).
92 */
93
94/*
95 * Get contents of register REGNO in task TASK.
96 */
97static inline long get_reg(struct task_struct *task, int regno)
98{
99 unsigned char *reg_ptr;
100
101 struct pt_regs *regs =
102 (struct pt_regs *)((unsigned long)task->thread_info +
103 (THREAD_SIZE - sizeof(struct pt_regs)));
104 reg_ptr = (char *)regs;
105
106 switch (regno) {
107 case PT_USP:
108 return task->thread.usp;
109 default:
110 if (regno <= 216)
111 return *(long *)(reg_ptr + regno);
112 }
113 /* slight mystery ... never seems to come here but kernel misbehaves without this code! */
114
115 printk(KERN_WARNING "Request to get for unknown register %d\n", regno);
116 return 0;
117}
118
119/*
120 * Write contents of register REGNO in task TASK.
121 */
122static inline int
123put_reg(struct task_struct *task, int regno, unsigned long data)
124{
125 char * reg_ptr;
126
127 struct pt_regs *regs =
128 (struct pt_regs *)((unsigned long)task->thread_info +
129 (THREAD_SIZE - sizeof(struct pt_regs)));
130 reg_ptr = (char *)regs;
131
132 switch (regno) {
133 case PT_PC:
134 /*********************************************************************/
135 /* At this point the kernel is most likely in exception. */
136 /* The RETX register will be used to populate the pc of the process. */
137 /*********************************************************************/
138 regs->retx = data;
139 regs->pc = data;
140 break;
141 case PT_RETX:
142 break; /* regs->retx = data; break; */
143 case PT_USP:
144 regs->usp = data;
145 task->thread.usp = data;
146 break;
147 default:
148 if (regno <= 216)
149 *(long *)(reg_ptr + regno) = data;
150 }
151 return 0;
152}
153
154/*
155 * check that an address falls within the bounds of the target process's memory mappings
156 */
157static inline int is_user_addr_valid(struct task_struct *child,
158 unsigned long start, unsigned long len)
159{
160 struct vm_list_struct *vml;
161 struct sram_list_struct *sraml;
162
163 for (vml = child->mm->context.vmlist; vml; vml = vml->next)
164 if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end)
165 return 0;
166
167 for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
168 if (start >= (unsigned long)sraml->addr
169 && start + len <= (unsigned long)sraml->addr + sraml->length)
170 return 0;
171
172 return -EIO;
173}
174
175/*
176 * Called by kernel/ptrace.c when detaching..
177 *
178 * Make sure the single step bit is not set.
179 */
180void ptrace_disable(struct task_struct *child)
181{
182 unsigned long tmp;
183 /* make sure the single step bit is not set. */
184 tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
185 put_reg(child, PT_SR, tmp);
186}
187
188long arch_ptrace(struct task_struct *child, long request, long addr, long data)
189{
190 int ret;
191 int add = 0;
192
193 switch (request) {
194 /* when I and D space are separate, these will need to be fixed. */
195 case PTRACE_PEEKDATA:
196 pr_debug("ptrace: PEEKDATA\n");
197 add = MAX_SHARED_LIBS * 4; /* space between text and data */
198 /* fall through */
199 case PTRACE_PEEKTEXT: /* read word at location addr. */
200 {
201 unsigned long tmp = 0;
202 int copied;
203
204 ret = -EIO;
205 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add,
206 sizeof(data));
207 if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0)
208 break;
209 pr_debug("ptrace: user address is valid\n");
210
211#if L1_CODE_LENGTH != 0
212 if (addr + add >= L1_CODE_START
213 && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
214 safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp));
215 copied = sizeof(tmp);
216 } else
217#endif
218 copied =
219 access_process_vm(child, addr + add, &tmp,
220 sizeof(tmp), 0);
221 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
222 if (copied != sizeof(tmp))
223 break;
224 ret = put_user(tmp, (unsigned long *)data);
225 break;
226 }
227
228 /* read the word at location addr in the USER area. */
229 case PTRACE_PEEKUSR:
230 {
231 unsigned long tmp;
232 ret = -EIO;
233 tmp = 0;
234 if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
235 printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning "
236 "0 - %x sizeof(pt_regs) is %lx\n",
237 (int)addr, sizeof(struct pt_regs));
238 break;
239 }
240 if (addr == sizeof(struct pt_regs)) {
241 /* PT_TEXT_ADDR */
242 tmp = child->mm->start_code + TEXT_OFFSET;
243 } else if (addr == (sizeof(struct pt_regs) + 4)) {
244 /* PT_TEXT_END_ADDR */
245 tmp = child->mm->end_code;
246 } else if (addr == (sizeof(struct pt_regs) + 8)) {
247 /* PT_DATA_ADDR */
248 tmp = child->mm->start_data;
249#ifdef CONFIG_BINFMT_ELF_FDPIC
250 } else if (addr == (sizeof(struct pt_regs) + 12)) {
251 tmp = child->mm->context.exec_fdpic_loadmap;
252 } else if (addr == (sizeof(struct pt_regs) + 16)) {
253 tmp = child->mm->context.interp_fdpic_loadmap;
254#endif
255 } else {
256 tmp = get_reg(child, addr);
257 }
258 ret = put_user(tmp, (unsigned long *)data);
259 break;
260 }
261
262 /* when I and D space are separate, this will have to be fixed. */
263 case PTRACE_POKEDATA:
264 printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n");
265 /* fall through */
266 case PTRACE_POKETEXT: /* write the word at location addr. */
267 {
268 int copied;
269
270 ret = -EIO;
271 pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n",
272 addr, add, sizeof(data), data);
273 if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0)
274 break;
275 pr_debug("ptrace: user address is valid\n");
276
277#if L1_CODE_LENGTH != 0
278 if (addr + add >= L1_CODE_START
279 && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
280 safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data));
281 copied = sizeof(data);
282 } else
283#endif
284 copied =
285 access_process_vm(child, addr + add, &data,
286 sizeof(data), 1);
287 pr_debug("ptrace: copied size %d\n", copied);
288 if (copied != sizeof(data))
289 break;
290 ret = 0;
291 break;
292 }
293
294 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
295 ret = -EIO;
296 if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
297 printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n");
298 break;
299 }
300
301 if (addr >= (sizeof(struct pt_regs))) {
302 ret = 0;
303 break;
304 }
305 if (addr == PT_SYSCFG) {
306 data &= SYSCFG_MASK;
307 data |= get_reg(child, PT_SYSCFG);
308 }
309 ret = put_reg(child, addr, data);
310 break;
311
312 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
313 case PTRACE_CONT:
314 { /* restart after signal. */
315 long tmp;
316
317 pr_debug("ptrace_cont\n");
318
319 ret = -EIO;
320 if (!valid_signal(data))
321 break;
322 if (request == PTRACE_SYSCALL)
323 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
324 else
325 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
326
327 child->exit_code = data;
328 /* make sure the single step bit is not set. */
329 tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
330 put_reg(child, PT_SYSCFG, tmp);
331 pr_debug("before wake_up_process\n");
332 wake_up_process(child);
333 ret = 0;
334 break;
335 }
336
337 /*
338 * make the child exit. Best I can do is send it a sigkill.
339 * perhaps it should be put in the status that it wants to
340 * exit.
341 */
342 case PTRACE_KILL:
343 {
344 long tmp;
345 ret = 0;
346 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
347 break;
348 child->exit_code = SIGKILL;
349 /* make sure the single step bit is not set. */
350 tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
351 put_reg(child, PT_SYSCFG, tmp);
352 wake_up_process(child);
353 break;
354 }
355
356 case PTRACE_SINGLESTEP:
357 { /* set the trap flag. */
358 long tmp;
359
360 pr_debug("single step\n");
361 ret = -EIO;
362 if (!valid_signal(data))
363 break;
364 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
365
366 tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
367 put_reg(child, PT_SYSCFG, tmp);
368
369 child->exit_code = data;
370 /* give it a chance to run. */
371 wake_up_process(child);
372 ret = 0;
373 break;
374 }
375
376 case PTRACE_DETACH:
377 { /* detach a process that was attached. */
378 ret = ptrace_detach(child, data);
379 break;
380 }
381
382 case PTRACE_GETREGS:
383 {
384
385 /* Get all gp regs from the child. */
386 ret = ptrace_getregs(child, (void __user *)data);
387 break;
388 }
389
390 case PTRACE_SETREGS:
391 {
392 printk(KERN_NOTICE
393 "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
394 /* Set all gp regs in the child. */
395 ret = 0;
396 break;
397 }
398 default:
399 ret = ptrace_request(child, request, addr, data);
400 break;
401 }
402
403 return ret;
404}
405
406asmlinkage void syscall_trace(void)
407{
408
409 if (!test_thread_flag(TIF_SYSCALL_TRACE))
410 return;
411
412 if (!(current->ptrace & PT_PTRACED))
413 return;
414
415 /* the 0x80 provides a way for the tracing parent to distinguish
416 * between a syscall stop and SIGTRAP delivery
417 */
418 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
419 ? 0x80 : 0));
420
421 /*
422 * this isn't the same as continuing with a signal, but it will do
423 * for normal use. strace only continues with a signal if the
424 * stopping signal is not SIGTRAP. -brl
425 */
426 if (current->exit_code) {
427 send_sig(current->exit_code, current, 1);
428 current->exit_code = 0;
429 }
430}
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
new file mode 100644
index 000000000000..342bb8dd56ac
--- /dev/null
+++ b/arch/blackfin/kernel/setup.c
@@ -0,0 +1,902 @@
1/*
2 * File: arch/blackfin/kernel/setup.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/delay.h>
31#include <linux/console.h>
32#include <linux/bootmem.h>
33#include <linux/seq_file.h>
34#include <linux/cpu.h>
35#include <linux/module.h>
36#include <linux/console.h>
37#include <linux/tty.h>
38
39#include <linux/ext2_fs.h>
40#include <linux/cramfs_fs.h>
41#include <linux/romfs_fs.h>
42
43#include <asm/cacheflush.h>
44#include <asm/blackfin.h>
45#include <asm/cplbinit.h>
46
47unsigned long memory_start, memory_end, physical_mem_end;
48unsigned long reserved_mem_dcache_on;
49unsigned long reserved_mem_icache_on;
50EXPORT_SYMBOL(memory_start);
51EXPORT_SYMBOL(memory_end);
52EXPORT_SYMBOL(physical_mem_end);
53EXPORT_SYMBOL(_ramend);
54
55#ifdef CONFIG_MTD_UCLINUX
56unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
57unsigned long _ebss;
58EXPORT_SYMBOL(memory_mtd_end);
59EXPORT_SYMBOL(memory_mtd_start);
60EXPORT_SYMBOL(mtd_size);
61#endif
62
63char command_line[COMMAND_LINE_SIZE];
64
65#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
66static void generate_cpl_tables(void);
67#endif
68
69void __init bf53x_cache_init(void)
70{
71#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
72 generate_cpl_tables();
73#endif
74
75#ifdef CONFIG_BLKFIN_CACHE
76 bfin_icache_init();
77 printk(KERN_INFO "Instruction Cache Enabled\n");
78#endif
79
80#ifdef CONFIG_BLKFIN_DCACHE
81 bfin_dcache_init();
82 printk(KERN_INFO "Data Cache Enabled"
83# if defined CONFIG_BLKFIN_WB
84 " (write-back)"
85# elif defined CONFIG_BLKFIN_WT
86 " (write-through)"
87# endif
88 "\n");
89#endif
90}
91
92void bf53x_relocate_l1_mem(void)
93{
94 unsigned long l1_code_length;
95 unsigned long l1_data_a_length;
96 unsigned long l1_data_b_length;
97
98 l1_code_length = _etext_l1 - _stext_l1;
99 if (l1_code_length > L1_CODE_LENGTH)
100 l1_code_length = L1_CODE_LENGTH;
101 /* cannot complain as printk is not available as yet.
102 * But we can continue booting and complain later!
103 */
104
105 /* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
106 dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
107
108 l1_data_a_length = _ebss_l1 - _sdata_l1;
109 if (l1_data_a_length > L1_DATA_A_LENGTH)
110 l1_data_a_length = L1_DATA_A_LENGTH;
111
112 /* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */
113 dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
114
115 l1_data_b_length = _ebss_b_l1 - _sdata_b_l1;
116 if (l1_data_b_length > L1_DATA_B_LENGTH)
117 l1_data_b_length = L1_DATA_B_LENGTH;
118
119 /* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */
120 dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
121 l1_data_a_length, l1_data_b_length);
122
123}
124
125/*
126 * Initial parsing of the command line. Currently, we support:
127 * - Controlling the linux memory size: mem=xxx[KMG]
128 * - Controlling the physical memory size: max_mem=xxx[KMG][$][#]
129 * $ -> reserved memory is dcacheable
130 * # -> reserved memory is icacheable
131 */
132static __init void parse_cmdline_early(char *cmdline_p)
133{
134 char c = ' ', *to = cmdline_p;
135 unsigned int memsize;
136 for (;;) {
137 if (c == ' ') {
138
139 if (!memcmp(to, "mem=", 4)) {
140 to += 4;
141 memsize = memparse(to, &to);
142 if (memsize)
143 _ramend = memsize;
144
145 } else if (!memcmp(to, "max_mem=", 8)) {
146 to += 8;
147 memsize = memparse(to, &to);
148 if (memsize) {
149 physical_mem_end = memsize;
150 if (*to != ' ') {
151 if (*to == '$'
152 || *(to + 1) == '$')
153 reserved_mem_dcache_on =
154 1;
155 if (*to == '#'
156 || *(to + 1) == '#')
157 reserved_mem_icache_on =
158 1;
159 }
160 }
161 }
162
163 }
164 c = *(to++);
165 if (!c)
166 break;
167 }
168}
169
170void __init setup_arch(char **cmdline_p)
171{
172 int bootmap_size;
173 unsigned long l1_length, sclk, cclk;
174#ifdef CONFIG_MTD_UCLINUX
175 unsigned long mtd_phys = 0;
176#endif
177
178 cclk = get_cclk();
179 sclk = get_sclk();
180
181#if !defined(CONFIG_BFIN_KERNEL_CLOCK) && defined(ANOMALY_05000273)
182 if (cclk == sclk)
183 panic("ANOMALY 05000273, SCLK can not be same as CCLK");
184#endif
185
186#if defined(ANOMALY_05000266)
187 bfin_read_IMDMA_D0_IRQ_STATUS();
188 bfin_read_IMDMA_D1_IRQ_STATUS();
189#endif
190
191#ifdef DEBUG_SERIAL_EARLY_INIT
192 bfin_console_init(); /* early console registration */
193 /* this give a chance to get printk() working before crash. */
194#endif
195
196#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
197 /* we need to initialize the Flashrom device here since we might
198 * do things with flash early on in the boot
199 */
200 flash_probe();
201#endif
202
203#if defined(CONFIG_CMDLINE_BOOL)
204 memset(command_line, 0, sizeof(command_line));
205 strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line));
206 command_line[sizeof(command_line) - 1] = 0;
207#endif
208
209 /* Keep a copy of command line */
210 *cmdline_p = &command_line[0];
211 memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
212 boot_command_line[COMMAND_LINE_SIZE - 1] = 0;
213
214 /* setup memory defaults from the user config */
215 physical_mem_end = 0;
216 _ramend = CONFIG_MEM_SIZE * 1024 * 1024;
217
218 parse_cmdline_early(&command_line[0]);
219
220 if (physical_mem_end == 0)
221 physical_mem_end = _ramend;
222
223 /* by now the stack is part of the init task */
224 memory_end = _ramend - DMA_UNCACHED_REGION;
225
226 _ramstart = (unsigned long)__bss_stop;
227 memory_start = PAGE_ALIGN(_ramstart);
228
229#if defined(CONFIG_MTD_UCLINUX)
230 /* generic memory mapped MTD driver */
231 memory_mtd_end = memory_end;
232
233 mtd_phys = _ramstart;
234 mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 8)));
235
236# if defined(CONFIG_EXT2_FS) || defined(CONFIG_EXT3_FS)
237 if (*((unsigned short *)(mtd_phys + 0x438)) == EXT2_SUPER_MAGIC)
238 mtd_size =
239 PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x404)) << 10);
240# endif
241
242# if defined(CONFIG_CRAMFS)
243 if (*((unsigned long *)(mtd_phys)) == CRAMFS_MAGIC)
244 mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x4)));
245# endif
246
247# if defined(CONFIG_ROMFS_FS)
248 if (((unsigned long *)mtd_phys)[0] == ROMSB_WORD0
249 && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1)
250 mtd_size =
251 PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2]));
252# if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
253 /* Due to a Hardware Anomaly we need to limit the size of usable
254 * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
255 * 05000263 - Hardware loop corrupted when taking an ICPLB exception
256 */
257# if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
258 if (memory_end >= 56 * 1024 * 1024)
259 memory_end = 56 * 1024 * 1024;
260# else
261 if (memory_end >= 60 * 1024 * 1024)
262 memory_end = 60 * 1024 * 1024;
263# endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
264# endif /* ANOMALY_05000263 */
265# endif /* CONFIG_ROMFS_FS */
266
267 memory_end -= mtd_size;
268
269 if (mtd_size == 0) {
270 console_init();
271 panic("Don't boot kernel without rootfs attached.\n");
272 }
273
274 /* Relocate MTD image to the top of memory after the uncached memory area */
275 dma_memcpy((char *)memory_end, __bss_stop, mtd_size);
276
277 memory_mtd_start = memory_end;
278 _ebss = memory_mtd_start; /* define _ebss for compatible */
279#endif /* CONFIG_MTD_UCLINUX */
280
281#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
282 /* Due to a Hardware Anomaly we need to limit the size of usable
283 * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
284 * 05000263 - Hardware loop corrupted when taking an ICPLB exception
285 */
286#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
287 if (memory_end >= 56 * 1024 * 1024)
288 memory_end = 56 * 1024 * 1024;
289#else
290 if (memory_end >= 60 * 1024 * 1024)
291 memory_end = 60 * 1024 * 1024;
292#endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
293 printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
294#endif /* ANOMALY_05000263 */
295
296#if !defined(CONFIG_MTD_UCLINUX)
297 memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
298#endif
299 init_mm.start_code = (unsigned long)_stext;
300 init_mm.end_code = (unsigned long)_etext;
301 init_mm.end_data = (unsigned long)_edata;
302 init_mm.brk = (unsigned long)0;
303
304 init_leds();
305
306 printk(KERN_INFO "Blackfin support (C) 2004-2007 Analog Devices, Inc.\n");
307 printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid());
308 if (bfin_revid() != bfin_compiled_revid())
309 printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
310 bfin_compiled_revid(), bfin_revid());
311 if (bfin_revid() < SUPPORTED_REVID)
312 printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
313 CPU, bfin_revid());
314 printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
315
316 printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n",
317 cclk / 1000000, sclk / 1000000);
318
319#if defined(ANOMALY_05000273)
320 if ((cclk >> 1) <= sclk)
321 printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
322#endif
323
324 printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20);
325 printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20);
326
327 printk(KERN_INFO "Memory map:\n"
328 KERN_INFO " text = 0x%p-0x%p\n"
329 KERN_INFO " init = 0x%p-0x%p\n"
330 KERN_INFO " data = 0x%p-0x%p\n"
331 KERN_INFO " stack = 0x%p-0x%p\n"
332 KERN_INFO " bss = 0x%p-0x%p\n"
333 KERN_INFO " available = 0x%p-0x%p\n"
334#ifdef CONFIG_MTD_UCLINUX
335 KERN_INFO " rootfs = 0x%p-0x%p\n"
336#endif
337#if DMA_UNCACHED_REGION > 0
338 KERN_INFO " DMA Zone = 0x%p-0x%p\n"
339#endif
340 , _stext, _etext,
341 __init_begin, __init_end,
342 _sdata, _edata,
343 (void*)&init_thread_union, (void*)((int)(&init_thread_union) + 0x2000),
344 __bss_start, __bss_stop,
345 (void*)_ramstart, (void*)memory_end
346#ifdef CONFIG_MTD_UCLINUX
347 , (void*)memory_mtd_start, (void*)(memory_mtd_start + mtd_size)
348#endif
349#if DMA_UNCACHED_REGION > 0
350 , (void*)(_ramend - DMA_UNCACHED_REGION), (void*)(_ramend)
351#endif
352 );
353
354 /*
355 * give all the memory to the bootmap allocator, tell it to put the
356 * boot mem_map at the start of memory
357 */
358 bootmap_size = init_bootmem_node(NODE_DATA(0), memory_start >> PAGE_SHIFT, /* map goes here */
359 PAGE_OFFSET >> PAGE_SHIFT,
360 memory_end >> PAGE_SHIFT);
361 /*
362 * free the usable memory, we have to make sure we do not free
363 * the bootmem bitmap so we then reserve it after freeing it :-)
364 */
365 free_bootmem(memory_start, memory_end - memory_start);
366
367 reserve_bootmem(memory_start, bootmap_size);
368 /*
369 * get kmalloc into gear
370 */
371 paging_init();
372
373 /* check the size of the l1 area */
374 l1_length = _etext_l1 - _stext_l1;
375 if (l1_length > L1_CODE_LENGTH)
376 panic("L1 memory overflow\n");
377
378 l1_length = _ebss_l1 - _sdata_l1;
379 if (l1_length > L1_DATA_A_LENGTH)
380 panic("L1 memory overflow\n");
381
382 bf53x_cache_init();
383
384#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
385# if defined(CONFIG_BFIN_SHARED_FLASH_ENET) && defined(CONFIG_BFIN533_STAMP)
386 /* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */
387 bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN));
388 bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN);
389 SSYNC();
390# endif
391# if defined (CONFIG_BFIN561_EZKIT)
392 bfin_write_FIO0_DIR(bfin_read_FIO0_DIR() | (1 << 12));
393 SSYNC();
394# endif /* defined (CONFIG_BFIN561_EZKIT) */
395#endif
396
397 printk(KERN_INFO "Hardware Trace Enabled\n");
398 bfin_write_TBUFCTL(0x03);
399}
400
401#if defined(CONFIG_BF561)
402static struct cpu cpu[2];
403#else
404static struct cpu cpu[1];
405#endif
406static int __init topology_init(void)
407{
408#if defined (CONFIG_BF561)
409 register_cpu(&cpu[0], 0);
410 register_cpu(&cpu[1], 1);
411 return 0;
412#else
413 return register_cpu(cpu, 0);
414#endif
415}
416
417subsys_initcall(topology_init);
418
419#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
420u16 lock_kernel_check(u32 start, u32 end)
421{
422 if ((start <= (u32) _stext && end >= (u32) _end)
423 || (start >= (u32) _stext && end <= (u32) _end))
424 return IN_KERNEL;
425 return 0;
426}
427
428static unsigned short __init
429fill_cplbtab(struct cplb_tab *table,
430 unsigned long start, unsigned long end,
431 unsigned long block_size, unsigned long cplb_data)
432{
433 int i;
434
435 switch (block_size) {
436 case SIZE_4M:
437 i = 3;
438 break;
439 case SIZE_1M:
440 i = 2;
441 break;
442 case SIZE_4K:
443 i = 1;
444 break;
445 case SIZE_1K:
446 default:
447 i = 0;
448 break;
449 }
450
451 cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
452
453 while ((start < end) && (table->pos < table->size)) {
454
455 table->tab[table->pos++] = start;
456
457 if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
458 table->tab[table->pos++] =
459 cplb_data | CPLB_LOCK | CPLB_DIRTY;
460 else
461 table->tab[table->pos++] = cplb_data;
462
463 start += block_size;
464 }
465 return 0;
466}
467
468static unsigned short __init
469close_cplbtab(struct cplb_tab *table)
470{
471
472 while (table->pos < table->size) {
473
474 table->tab[table->pos++] = 0;
475 table->tab[table->pos++] = 0; /* !CPLB_VALID */
476 }
477 return 0;
478}
479
480static void __init generate_cpl_tables(void)
481{
482
483 u16 i, j, process;
484 u32 a_start, a_end, as, ae, as_1m;
485
486 struct cplb_tab *t_i = NULL;
487 struct cplb_tab *t_d = NULL;
488 struct s_cplb cplb;
489
490 cplb.init_i.size = MAX_CPLBS;
491 cplb.init_d.size = MAX_CPLBS;
492 cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
493 cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
494
495 cplb.init_i.pos = 0;
496 cplb.init_d.pos = 0;
497 cplb.switch_i.pos = 0;
498 cplb.switch_d.pos = 0;
499
500 cplb.init_i.tab = icplb_table;
501 cplb.init_d.tab = dcplb_table;
502 cplb.switch_i.tab = ipdt_table;
503 cplb.switch_d.tab = dpdt_table;
504
505 cplb_data[SDRAM_KERN].end = memory_end;
506
507#ifdef CONFIG_MTD_UCLINUX
508 cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
509 cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
510 cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
511# if defined(CONFIG_ROMFS_FS)
512 cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
513
514 /*
515 * The ROMFS_FS size is often not multiple of 1MB.
516 * This can cause multiple CPLB sets covering the same memory area.
517 * This will then cause multiple CPLB hit exceptions.
518 * Workaround: We ensure a contiguous memory area by extending the kernel
519 * memory section over the mtd section.
520 * For ROMFS_FS memory must be covered with ICPLBs anyways.
521 * So there is no difference between kernel and mtd memory setup.
522 */
523
524 cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
525 cplb_data[SDRAM_RAM_MTD].valid = 0;
526
527# endif
528#else
529 cplb_data[SDRAM_RAM_MTD].valid = 0;
530#endif
531
532 cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
533 cplb_data[SDRAM_DMAZ].end = _ramend;
534
535 cplb_data[RES_MEM].start = _ramend;
536 cplb_data[RES_MEM].end = physical_mem_end;
537
538 if (reserved_mem_dcache_on)
539 cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
540 else
541 cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
542
543 if (reserved_mem_icache_on)
544 cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
545 else
546 cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
547
548 for (i = ZERO_P; i <= L2_MEM; i++) {
549
550 if (cplb_data[i].valid) {
551
552 as_1m = cplb_data[i].start % SIZE_1M;
553
554 /* We need to make sure all sections are properly 1M aligned
555 * However between Kernel Memory and the Kernel mtd section, depending on the
556 * rootfs size, there can be overlapping memory areas.
557 */
558
559 if (as_1m && i!=L1I_MEM && i!=L1D_MEM) {
560#ifdef CONFIG_MTD_UCLINUX
561 if (i == SDRAM_RAM_MTD) {
562 if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
563 cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
564 else
565 cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
566 } else
567#endif
568 printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
569 cplb_data[i].name, cplb_data[i].start);
570 }
571
572 as = cplb_data[i].start % SIZE_4M;
573 ae = cplb_data[i].end % SIZE_4M;
574
575 if (as)
576 a_start = cplb_data[i].start + (SIZE_4M - (as));
577 else
578 a_start = cplb_data[i].start;
579
580 a_end = cplb_data[i].end - ae;
581
582 for (j = INITIAL_T; j <= SWITCH_T; j++) {
583
584 switch (j) {
585 case INITIAL_T:
586 if (cplb_data[i].attr & INITIAL_T) {
587 t_i = &cplb.init_i;
588 t_d = &cplb.init_d;
589 process = 1;
590 } else
591 process = 0;
592 break;
593 case SWITCH_T:
594 if (cplb_data[i].attr & SWITCH_T) {
595 t_i = &cplb.switch_i;
596 t_d = &cplb.switch_d;
597 process = 1;
598 } else
599 process = 0;
600 break;
601 default:
602 process = 0;
603 break;
604 }
605
606 if (process) {
607 if (cplb_data[i].attr & I_CPLB) {
608
609 if (cplb_data[i].psize) {
610 fill_cplbtab(t_i,
611 cplb_data[i].start,
612 cplb_data[i].end,
613 cplb_data[i].psize,
614 cplb_data[i].i_conf);
615 } else {
616 /*icplb_table */
617#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
618 if (i == SDRAM_KERN) {
619 fill_cplbtab(t_i,
620 cplb_data[i].start,
621 cplb_data[i].end,
622 SIZE_4M,
623 cplb_data[i].i_conf);
624 } else
625#endif
626 {
627 fill_cplbtab(t_i,
628 cplb_data[i].start,
629 a_start,
630 SIZE_1M,
631 cplb_data[i].i_conf);
632 fill_cplbtab(t_i,
633 a_start,
634 a_end,
635 SIZE_4M,
636 cplb_data[i].i_conf);
637 fill_cplbtab(t_i, a_end,
638 cplb_data[i].end,
639 SIZE_1M,
640 cplb_data[i].i_conf);
641 }
642 }
643
644 }
645 if (cplb_data[i].attr & D_CPLB) {
646
647 if (cplb_data[i].psize) {
648 fill_cplbtab(t_d,
649 cplb_data[i].start,
650 cplb_data[i].end,
651 cplb_data[i].psize,
652 cplb_data[i].d_conf);
653 } else {
654/*dcplb_table*/
655 fill_cplbtab(t_d,
656 cplb_data[i].start,
657 a_start, SIZE_1M,
658 cplb_data[i].d_conf);
659 fill_cplbtab(t_d, a_start,
660 a_end, SIZE_4M,
661 cplb_data[i].d_conf);
662 fill_cplbtab(t_d, a_end,
663 cplb_data[i].end,
664 SIZE_1M,
665 cplb_data[i].d_conf);
666
667 }
668
669 }
670 }
671 }
672
673 }
674 }
675
676/* close tables */
677
678 close_cplbtab(&cplb.init_i);
679 close_cplbtab(&cplb.init_d);
680
681 cplb.init_i.tab[cplb.init_i.pos] = -1;
682 cplb.init_d.tab[cplb.init_d.pos] = -1;
683 cplb.switch_i.tab[cplb.switch_i.pos] = -1;
684 cplb.switch_d.tab[cplb.switch_d.pos] = -1;
685
686}
687
688#endif
689
690static inline u_long get_vco(void)
691{
692 u_long msel;
693 u_long vco;
694
695 msel = (bfin_read_PLL_CTL() >> 9) & 0x3F;
696 if (0 == msel)
697 msel = 64;
698
699 vco = CONFIG_CLKIN_HZ;
700 vco >>= (1 & bfin_read_PLL_CTL()); /* DF bit */
701 vco = msel * vco;
702 return vco;
703}
704
705/*Get the Core clock*/
706u_long get_cclk(void)
707{
708 u_long csel, ssel;
709 if (bfin_read_PLL_STAT() & 0x1)
710 return CONFIG_CLKIN_HZ;
711
712 ssel = bfin_read_PLL_DIV();
713 csel = ((ssel >> 4) & 0x03);
714 ssel &= 0xf;
715 if (ssel && ssel < (1 << csel)) /* SCLK > CCLK */
716 return get_vco() / ssel;
717 return get_vco() >> csel;
718}
719
720EXPORT_SYMBOL(get_cclk);
721
722/* Get the System clock */
723u_long get_sclk(void)
724{
725 u_long ssel;
726
727 if (bfin_read_PLL_STAT() & 0x1)
728 return CONFIG_CLKIN_HZ;
729
730 ssel = (bfin_read_PLL_DIV() & 0xf);
731 if (0 == ssel) {
732 printk(KERN_WARNING "Invalid System Clock\n");
733 ssel = 1;
734 }
735
736 return get_vco() / ssel;
737}
738
739EXPORT_SYMBOL(get_sclk);
740
741/*
742 * Get CPU information for use by the procfs.
743 */
744static int show_cpuinfo(struct seq_file *m, void *v)
745{
746 char *cpu, *mmu, *fpu, *name;
747 uint32_t revid;
748
749 u_long cclk = 0, sclk = 0;
750 u_int dcache_size = 0, dsup_banks = 0;
751
752 cpu = CPU;
753 mmu = "none";
754 fpu = "none";
755 revid = bfin_revid();
756 name = bfin_board_name;
757
758 cclk = get_cclk();
759 sclk = get_sclk();
760
761 seq_printf(m, "CPU:\t\tADSP-%s Rev. 0.%d\n"
762 "MMU:\t\t%s\n"
763 "FPU:\t\t%s\n"
764 "Core Clock:\t%9lu Hz\n"
765 "System Clock:\t%9lu Hz\n"
766 "BogoMips:\t%lu.%02lu\n"
767 "Calibration:\t%lu loops\n",
768 cpu, revid, mmu, fpu,
769 cclk,
770 sclk,
771 (loops_per_jiffy * HZ) / 500000,
772 ((loops_per_jiffy * HZ) / 5000) % 100,
773 (loops_per_jiffy * HZ));
774 seq_printf(m, "Board Name:\t%s\n", name);
775 seq_printf(m, "Board Memory:\t%ld MB\n", physical_mem_end >> 20);
776 seq_printf(m, "Kernel Memory:\t%ld MB\n", (unsigned long)_ramend >> 20);
777 if (bfin_read_IMEM_CONTROL() & (ENICPLB | IMC))
778 seq_printf(m, "I-CACHE:\tON\n");
779 else
780 seq_printf(m, "I-CACHE:\tOFF\n");
781 if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE))
782 seq_printf(m, "D-CACHE:\tON"
783#if defined CONFIG_BLKFIN_WB
784 " (write-back)"
785#elif defined CONFIG_BLKFIN_WT
786 " (write-through)"
787#endif
788 "\n");
789 else
790 seq_printf(m, "D-CACHE:\tOFF\n");
791
792
793 switch(bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) {
794 case ACACHE_BSRAM:
795 seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n");
796 dcache_size = 16;
797 dsup_banks = 1;
798 break;
799 case ACACHE_BCACHE:
800 seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n");
801 dcache_size = 32;
802 dsup_banks = 2;
803 break;
804 case ASRAM_BSRAM:
805 seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n");
806 dcache_size = 0;
807 dsup_banks = 0;
808 break;
809 default:
810 break;
811 }
812
813
814 seq_printf(m, "I-CACHE Size:\t%dKB\n", BLKFIN_ICACHESIZE / 1024);
815 seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size);
816 seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n",
817 BLKFIN_ISUBBANKS, BLKFIN_IWAYS, BLKFIN_ILINES);
818 seq_printf(m,
819 "D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n",
820 dsup_banks, BLKFIN_DSUBBANKS, BLKFIN_DWAYS,
821 BLKFIN_DLINES);
822#ifdef CONFIG_BLKFIN_CACHE_LOCK
823 switch (read_iloc()) {
824 case WAY0_L:
825 seq_printf(m, "Way0 Locked-Down\n");
826 break;
827 case WAY1_L:
828 seq_printf(m, "Way1 Locked-Down\n");
829 break;
830 case WAY01_L:
831 seq_printf(m, "Way0,Way1 Locked-Down\n");
832 break;
833 case WAY2_L:
834 seq_printf(m, "Way2 Locked-Down\n");
835 break;
836 case WAY02_L:
837 seq_printf(m, "Way0,Way2 Locked-Down\n");
838 break;
839 case WAY12_L:
840 seq_printf(m, "Way1,Way2 Locked-Down\n");
841 break;
842 case WAY012_L:
843 seq_printf(m, "Way0,Way1 & Way2 Locked-Down\n");
844 break;
845 case WAY3_L:
846 seq_printf(m, "Way3 Locked-Down\n");
847 break;
848 case WAY03_L:
849 seq_printf(m, "Way0,Way3 Locked-Down\n");
850 break;
851 case WAY13_L:
852 seq_printf(m, "Way1,Way3 Locked-Down\n");
853 break;
854 case WAY013_L:
855 seq_printf(m, "Way 0,Way1,Way3 Locked-Down\n");
856 break;
857 case WAY32_L:
858 seq_printf(m, "Way3,Way2 Locked-Down\n");
859 break;
860 case WAY320_L:
861 seq_printf(m, "Way3,Way2,Way0 Locked-Down\n");
862 break;
863 case WAY321_L:
864 seq_printf(m, "Way3,Way2,Way1 Locked-Down\n");
865 break;
866 case WAYALL_L:
867 seq_printf(m, "All Ways are locked\n");
868 break;
869 default:
870 seq_printf(m, "No Ways are locked\n");
871 }
872#endif
873 return 0;
874}
875
876static void *c_start(struct seq_file *m, loff_t *pos)
877{
878 return *pos < NR_CPUS ? ((void *)0x12345678) : NULL;
879}
880
881static void *c_next(struct seq_file *m, void *v, loff_t *pos)
882{
883 ++*pos;
884 return c_start(m, pos);
885}
886
887static void c_stop(struct seq_file *m, void *v)
888{
889}
890
891struct seq_operations cpuinfo_op = {
892 .start = c_start,
893 .next = c_next,
894 .stop = c_stop,
895 .show = show_cpuinfo,
896};
897
898void cmdline_init(unsigned long r0)
899{
900 if (r0)
901 strncpy(command_line, (char *)r0, COMMAND_LINE_SIZE);
902}
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
new file mode 100644
index 000000000000..316e65c3439d
--- /dev/null
+++ b/arch/blackfin/kernel/signal.c
@@ -0,0 +1,356 @@
1/*
2 * File: arch/blackfin/kernel/signal.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <linux/signal.h>
31#include <linux/syscalls.h>
32#include <linux/ptrace.h>
33#include <linux/tty.h>
34#include <linux/personality.h>
35#include <linux/binfmts.h>
36#include <linux/freezer.h>
37
38#include <asm/uaccess.h>
39#include <asm/cacheflush.h>
40#include <asm/ucontext.h>
41
42#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
43
44struct fdpic_func_descriptor {
45 unsigned long text;
46 unsigned long GOT;
47};
48
49struct rt_sigframe {
50 int sig;
51 struct siginfo *pinfo;
52 void *puc;
53 char retcode[8];
54 struct siginfo info;
55 struct ucontext uc;
56};
57
58asmlinkage int sys_sigaltstack(const stack_t * uss, stack_t * uoss)
59{
60 return do_sigaltstack(uss, uoss, rdusp());
61}
62
63static inline int
64rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *pr0)
65{
66 unsigned long usp = 0;
67 int err = 0;
68
69#define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x)
70
71 /* restore passed registers */
72 RESTORE(r0); RESTORE(r1); RESTORE(r2); RESTORE(r3);
73 RESTORE(r4); RESTORE(r5); RESTORE(r6); RESTORE(r7);
74 RESTORE(p0); RESTORE(p1); RESTORE(p2); RESTORE(p3);
75 RESTORE(p4); RESTORE(p5);
76 err |= __get_user(usp, &sc->sc_usp);
77 wrusp(usp);
78 RESTORE(a0w); RESTORE(a1w);
79 RESTORE(a0x); RESTORE(a1x);
80 RESTORE(astat);
81 RESTORE(rets);
82 RESTORE(pc);
83 RESTORE(retx);
84 RESTORE(fp);
85 RESTORE(i0); RESTORE(i1); RESTORE(i2); RESTORE(i3);
86 RESTORE(m0); RESTORE(m1); RESTORE(m2); RESTORE(m3);
87 RESTORE(l0); RESTORE(l1); RESTORE(l2); RESTORE(l3);
88 RESTORE(b0); RESTORE(b1); RESTORE(b2); RESTORE(b3);
89 RESTORE(lc0); RESTORE(lc1);
90 RESTORE(lt0); RESTORE(lt1);
91 RESTORE(lb0); RESTORE(lb1);
92 RESTORE(seqstat);
93
94 regs->orig_p0 = -1; /* disable syscall checks */
95
96 *pr0 = regs->r0;
97 return err;
98}
99
100asmlinkage int do_rt_sigreturn(unsigned long __unused)
101{
102 struct pt_regs *regs = (struct pt_regs *)__unused;
103 unsigned long usp = rdusp();
104 struct rt_sigframe *frame = (struct rt_sigframe *)(usp);
105 sigset_t set;
106 int r0;
107
108 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
109 goto badframe;
110 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
111 goto badframe;
112
113 sigdelsetmask(&set, ~_BLOCKABLE);
114 spin_lock_irq(&current->sighand->siglock);
115 current->blocked = set;
116 recalc_sigpending();
117 spin_unlock_irq(&current->sighand->siglock);
118
119 if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
120 goto badframe;
121
122 if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->usp) == -EFAULT)
123 goto badframe;
124
125 return r0;
126
127 badframe:
128 force_sig(SIGSEGV, current);
129 return 0;
130}
131
132static inline int rt_setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
133{
134 int err = 0;
135
136#define SETUP(x) err |= __put_user(regs->x, &sc->sc_##x)
137
138 SETUP(r0); SETUP(r1); SETUP(r2); SETUP(r3);
139 SETUP(r4); SETUP(r5); SETUP(r6); SETUP(r7);
140 SETUP(p0); SETUP(p1); SETUP(p2); SETUP(p3);
141 SETUP(p4); SETUP(p5);
142 err |= __put_user(rdusp(), &sc->sc_usp);
143 SETUP(a0w); SETUP(a1w);
144 SETUP(a0x); SETUP(a1x);
145 SETUP(astat);
146 SETUP(rets);
147 SETUP(pc);
148 SETUP(retx);
149 SETUP(fp);
150 SETUP(i0); SETUP(i1); SETUP(i2); SETUP(i3);
151 SETUP(m0); SETUP(m1); SETUP(m2); SETUP(m3);
152 SETUP(l0); SETUP(l1); SETUP(l2); SETUP(l3);
153 SETUP(b0); SETUP(b1); SETUP(b2); SETUP(b3);
154 SETUP(lc0); SETUP(lc1);
155 SETUP(lt0); SETUP(lt1);
156 SETUP(lb0); SETUP(lb1);
157 SETUP(seqstat);
158
159 return err;
160}
161
162static inline void push_cache(unsigned long vaddr, unsigned int len)
163{
164 flush_icache_range(vaddr, vaddr + len);
165}
166
167static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
168 size_t frame_size)
169{
170 unsigned long usp;
171
172 /* Default to using normal stack. */
173 usp = rdusp();
174
175 /* This is the X/Open sanctioned signal stack switching. */
176 if (ka->sa.sa_flags & SA_ONSTACK) {
177 if (!on_sig_stack(usp))
178 usp = current->sas_ss_sp + current->sas_ss_size;
179 }
180 return (void *)((usp - frame_size) & -8UL);
181}
182
183static int
184setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
185 sigset_t * set, struct pt_regs *regs)
186{
187 struct rt_sigframe *frame;
188 int err = 0;
189
190 frame = get_sigframe(ka, regs, sizeof(*frame));
191
192 err |= __put_user((current_thread_info()->exec_domain
193 && current_thread_info()->exec_domain->signal_invmap
194 && sig < 32
195 ? current_thread_info()->exec_domain->
196 signal_invmap[sig] : sig), &frame->sig);
197
198 err |= __put_user(&frame->info, &frame->pinfo);
199 err |= __put_user(&frame->uc, &frame->puc);
200 err |= copy_siginfo_to_user(&frame->info, info);
201
202 /* Create the ucontext. */
203 err |= __put_user(0, &frame->uc.uc_flags);
204 err |= __put_user(0, &frame->uc.uc_link);
205 err |=
206 __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
207 err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags);
208 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
209 err |= rt_setup_sigcontext(&frame->uc.uc_mcontext, regs);
210 err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
211
212 /* Set up to return from userspace. */
213 err |= __put_user(0x28, &(frame->retcode[0]));
214 err |= __put_user(0xe1, &(frame->retcode[1]));
215 err |= __put_user(0xad, &(frame->retcode[2]));
216 err |= __put_user(0x00, &(frame->retcode[3]));
217 err |= __put_user(0xa0, &(frame->retcode[4]));
218 err |= __put_user(0x00, &(frame->retcode[5]));
219
220 if (err)
221 goto give_sigsegv;
222
223 push_cache((unsigned long)&frame->retcode, sizeof(frame->retcode));
224
225 /* Set up registers for signal handler */
226 wrusp((unsigned long)frame);
227 if (get_personality & FDPIC_FUNCPTRS) {
228 struct fdpic_func_descriptor __user *funcptr =
229 (struct fdpic_func_descriptor *) ka->sa.sa_handler;
230 __get_user(regs->pc, &funcptr->text);
231 __get_user(regs->p3, &funcptr->GOT);
232 } else
233 regs->pc = (unsigned long)ka->sa.sa_handler;
234 regs->rets = (unsigned long)(frame->retcode);
235
236 regs->r0 = frame->sig;
237 regs->r1 = (unsigned long)(&frame->info);
238 regs->r2 = (unsigned long)(&frame->uc);
239
240 return 0;
241
242 give_sigsegv:
243 if (sig == SIGSEGV)
244 ka->sa.sa_handler = SIG_DFL;
245 force_sig(SIGSEGV, current);
246 return -EFAULT;
247}
248
249static inline void
250handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
251{
252 switch (regs->r0) {
253 case -ERESTARTNOHAND:
254 if (!has_handler)
255 goto do_restart;
256 regs->r0 = -EINTR;
257 break;
258
259 case -ERESTARTSYS:
260 if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
261 regs->r0 = -EINTR;
262 break;
263 }
264 /* fallthrough */
265 case -ERESTARTNOINTR:
266 do_restart:
267 regs->p0 = regs->orig_p0;
268 regs->r0 = regs->orig_r0;
269 regs->pc -= 2;
270 break;
271 }
272}
273
274/*
275 * OK, we're invoking a handler
276 */
277static int
278handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
279 sigset_t *oldset, struct pt_regs *regs)
280{
281 int ret;
282
283 /* are we from a system call? to see pt_regs->orig_p0 */
284 if (regs->orig_p0 >= 0)
285 /* If so, check system call restarting.. */
286 handle_restart(regs, ka, 1);
287
288 /* set up the stack frame */
289 ret = setup_rt_frame(sig, ka, info, oldset, regs);
290
291 if (ret == 0) {
292 spin_lock_irq(&current->sighand->siglock);
293 sigorsets(&current->blocked, &current->blocked,
294 &ka->sa.sa_mask);
295 if (!(ka->sa.sa_flags & SA_NODEFER))
296 sigaddset(&current->blocked, sig);
297 recalc_sigpending();
298 spin_unlock_irq(&current->sighand->siglock);
299 }
300 return ret;
301}
302
303/*
304 * Note that 'init' is a special process: it doesn't get signals it doesn't
305 * want to handle. Thus you cannot kill init even with a SIGKILL even by
306 * mistake.
307 *
308 * Note that we go through the signals twice: once to check the signals
309 * that the kernel can handle, and then we build all the user-level signal
310 * handling stack-frames in one go after that.
311 */
312asmlinkage void do_signal(struct pt_regs *regs)
313{
314 siginfo_t info;
315 int signr;
316 struct k_sigaction ka;
317 sigset_t *oldset;
318
319 current->thread.esp0 = (unsigned long)regs;
320
321 if (try_to_freeze())
322 goto no_signal;
323
324 if (test_thread_flag(TIF_RESTORE_SIGMASK))
325 oldset = &current->saved_sigmask;
326 else
327 oldset = &current->blocked;
328
329 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
330 if (signr > 0) {
331 /* Whee! Actually deliver the signal. */
332 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
333 /* a signal was successfully delivered; the saved
334 * sigmask will have been stored in the signal frame,
335 * and will be restored by sigreturn, so we can simply
336 * clear the TIF_RESTORE_SIGMASK flag */
337 if (test_thread_flag(TIF_RESTORE_SIGMASK))
338 clear_thread_flag(TIF_RESTORE_SIGMASK);
339 }
340
341 return;
342 }
343
344no_signal:
345 /* Did we come from a system call? */
346 if (regs->orig_p0 >= 0)
347 /* Restart the system call - no handlers present */
348 handle_restart(regs, NULL, 0);
349
350 /* if there's no signal to deliver, we just put the saved sigmask
351 * back */
352 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
353 clear_thread_flag(TIF_RESTORE_SIGMASK);
354 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
355 }
356}
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c
new file mode 100644
index 000000000000..f436e6743f5a
--- /dev/null
+++ b/arch/blackfin/kernel/sys_bfin.c
@@ -0,0 +1,115 @@
1/*
2 * File: arch/blackfin/kernel/sys_bfin.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: This file contains various random system calls that
8 * have a non-standard calling sequence on the Linux/bfin
9 * platform.
10 *
11 * Modified:
12 * Copyright 2004-2006 Analog Devices Inc.
13 *
14 * Bugs: Enter bugs at http://blackfin.uclinux.org/
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see the file COPYING, or write
28 * to the Free Software Foundation, Inc.,
29 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
31
32#include <linux/smp_lock.h>
33#include <linux/spinlock.h>
34#include <linux/sem.h>
35#include <linux/msg.h>
36#include <linux/shm.h>
37#include <linux/syscalls.h>
38#include <linux/mman.h>
39#include <linux/file.h>
40
41#include <asm/cacheflush.h>
42#include <asm/uaccess.h>
43#include <asm/ipc.h>
44#include <asm/dma.h>
45#include <asm/unistd.h>
46
47/*
48 * sys_pipe() is the normal C calling standard for creating
49 * a pipe. It's not the way unix traditionally does this, though.
50 */
51asmlinkage int sys_pipe(unsigned long *fildes)
52{
53 int fd[2];
54 int error;
55
56 error = do_pipe(fd);
57 if (!error) {
58 if (copy_to_user(fildes, fd, 2 * sizeof(int)))
59 error = -EFAULT;
60 }
61 return error;
62}
63
64/* common code for old and new mmaps */
65static inline long
66do_mmap2(unsigned long addr, unsigned long len,
67 unsigned long prot, unsigned long flags,
68 unsigned long fd, unsigned long pgoff)
69{
70 int error = -EBADF;
71 struct file *file = NULL;
72
73 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
74 if (!(flags & MAP_ANONYMOUS)) {
75 file = fget(fd);
76 if (!file)
77 goto out;
78 }
79
80 down_write(&current->mm->mmap_sem);
81 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
82 up_write(&current->mm->mmap_sem);
83
84 if (file)
85 fput(file);
86 out:
87 return error;
88}
89
90asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
91 unsigned long prot, unsigned long flags,
92 unsigned long fd, unsigned long pgoff)
93{
94 return do_mmap2(addr, len, prot, flags, fd, pgoff);
95}
96
97asmlinkage int sys_getpagesize(void)
98{
99 return PAGE_SIZE;
100}
101
102asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
103{
104 return sram_alloc_with_lsl(size, flags);
105}
106
107asmlinkage int sys_sram_free(const void *addr)
108{
109 return sram_free_with_lsl(addr);
110}
111
112asmlinkage void *sys_dma_memcpy(void *dest, const void *src, size_t len)
113{
114 return safe_dma_memcpy(dest, src, len);
115}
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
new file mode 100644
index 000000000000..f578176b6d92
--- /dev/null
+++ b/arch/blackfin/kernel/time.c
@@ -0,0 +1,326 @@
1/*
2 * File: arch/blackfin/kernel/time.c
3 * Based on: none - original work
4 * Author:
5 *
6 * Created:
7 * Description: This file contains the bfin-specific time handling details.
8 * Most of the stuff is located in the machine specific files.
9 *
10 * Modified:
11 * Copyright 2004-2006 Analog Devices Inc.
12 *
13 * Bugs: Enter bugs at http://blackfin.uclinux.org/
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see the file COPYING, or write
27 * to the Free Software Foundation, Inc.,
28 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 */
30
31#include <linux/module.h>
32#include <linux/profile.h>
33#include <linux/interrupt.h>
34#include <linux/time.h>
35#include <linux/irq.h>
36
37#include <asm/blackfin.h>
38
39/* This is an NTP setting */
40#define TICK_SIZE (tick_nsec / 1000)
41
42static void time_sched_init(irqreturn_t(*timer_routine)
43 (int, void *));
44static unsigned long gettimeoffset(void);
45static inline void do_leds(void);
46
47#if (defined(CONFIG_BFIN_ALIVE_LED) || defined(CONFIG_BFIN_IDLE_LED))
48void __init init_leds(void)
49{
50 unsigned int tmp = 0;
51
52#if defined(CONFIG_BFIN_ALIVE_LED)
53 /* config pins as output. */
54 tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_DPORT();
55 SSYNC();
56 bfin_write_CONFIG_BFIN_ALIVE_LED_DPORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);
57 SSYNC();
58
59 /* First set led be off */
60 tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
61 SSYNC();
62 bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN); /* light off */
63 SSYNC();
64#endif
65
66#if defined(CONFIG_BFIN_IDLE_LED)
67 /* config pins as output. */
68 tmp = bfin_read_CONFIG_BFIN_IDLE_LED_DPORT();
69 SSYNC();
70 bfin_write_CONFIG_BFIN_IDLE_LED_DPORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);
71 SSYNC();
72
73 /* First set led be off */
74 tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
75 SSYNC();
76 bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp | CONFIG_BFIN_IDLE_LED_PIN); /* light off */
77 SSYNC();
78#endif
79}
80#else
81void __init init_leds(void)
82{
83}
84#endif
85
86#if defined(CONFIG_BFIN_ALIVE_LED)
87static inline void do_leds(void)
88{
89 static unsigned int count = 50;
90 static int flag = 0;
91 unsigned short tmp = 0;
92
93 if (--count == 0) {
94 count = 50;
95 flag = ~flag;
96 }
97 tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
98 SSYNC();
99
100 if (flag)
101 tmp &= ~CONFIG_BFIN_ALIVE_LED_PIN; /* light on */
102 else
103 tmp |= CONFIG_BFIN_ALIVE_LED_PIN; /* light off */
104
105 bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp);
106 SSYNC();
107
108}
109#else
110static inline void do_leds(void)
111{
112}
113#endif
114
115static struct irqaction bfin_timer_irq = {
116 .name = "BFIN Timer Tick",
117 .flags = IRQF_DISABLED
118};
119
120/*
121 * The way that the Blackfin core timer works is:
122 * - CCLK is divided by a programmable 8-bit pre-scaler (TSCALE)
123 * - Every time TSCALE ticks, a 32bit is counted down (TCOUNT)
124 *
125 * If you take the fastest clock (1ns, or 1GHz to make the math work easier)
126 * 10ms is 10,000,000 clock ticks, which fits easy into a 32-bit counter
127 * (32 bit counter is 4,294,967,296ns or 4.2 seconds) so, we don't need
128 * to use TSCALE, and program it to zero (which is pass CCLK through).
129 * If you feel like using it, try to keep HZ * TIMESCALE to some
130 * value that divides easy (like power of 2).
131 */
132
133#define TIME_SCALE 1
134
135static void
136time_sched_init(irqreturn_t(*timer_routine) (int, void *))
137{
138 u32 tcount;
139
140 /* power up the timer, but don't enable it just yet */
141 bfin_write_TCNTL(1);
142 CSYNC();
143
144 /*
145 * the TSCALE prescaler counter.
146 */
147 bfin_write_TSCALE((TIME_SCALE - 1));
148
149 tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
150 bfin_write_TPERIOD(tcount);
151 bfin_write_TCOUNT(tcount);
152
153 /* now enable the timer */
154 CSYNC();
155
156 bfin_write_TCNTL(7);
157
158 bfin_timer_irq.handler = (irq_handler_t)timer_routine;
159 /* call setup_irq instead of request_irq because request_irq calls
160 * kmalloc which has not been initialized yet
161 */
162 setup_irq(IRQ_CORETMR, &bfin_timer_irq);
163}
164
165/*
166 * Should return useconds since last timer tick
167 */
168static unsigned long gettimeoffset(void)
169{
170 unsigned long offset;
171 unsigned long clocks_per_jiffy;
172
173 clocks_per_jiffy = bfin_read_TPERIOD();
174 offset =
175 (clocks_per_jiffy -
176 bfin_read_TCOUNT()) / (((clocks_per_jiffy + 1) * HZ) /
177 USEC_PER_SEC);
178
179 /* Check if we just wrapped the counters and maybe missed a tick */
180 if ((bfin_read_ILAT() & (1 << IRQ_CORETMR))
181 && (offset < (100000 / HZ / 2)))
182 offset += (USEC_PER_SEC / HZ);
183
184 return offset;
185}
186
187static inline int set_rtc_mmss(unsigned long nowtime)
188{
189 return 0;
190}
191
192/*
193 * timer_interrupt() needs to keep up the real-time clock,
194 * as well as call the "do_timer()" routine every clocktick
195 */
196#ifdef CONFIG_CORE_TIMER_IRQ_L1
197irqreturn_t timer_interrupt(int irq, void *dummy)__attribute__((l1_text));
198#endif
199
200irqreturn_t timer_interrupt(int irq, void *dummy)
201{
202 /* last time the cmos clock got updated */
203 static long last_rtc_update = 0;
204
205 write_seqlock(&xtime_lock);
206
207 do_timer(1);
208 do_leds();
209
210#ifndef CONFIG_SMP
211 update_process_times(user_mode(get_irq_regs()));
212#endif
213 profile_tick(CPU_PROFILING);
214
215 /*
216 * If we have an externally synchronized Linux clock, then update
217 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
218 * called as close as possible to 500 ms before the new second starts.
219 */
220
221 if (ntp_synced() &&
222 xtime.tv_sec > last_rtc_update + 660 &&
223 (xtime.tv_nsec / NSEC_PER_USEC) >=
224 500000 - ((unsigned)TICK_SIZE) / 2
225 && (xtime.tv_nsec / NSEC_PER_USEC) <=
226 500000 + ((unsigned)TICK_SIZE) / 2) {
227 if (set_rtc_mmss(xtime.tv_sec) == 0)
228 last_rtc_update = xtime.tv_sec;
229 else
230 /* Do it again in 60s. */
231 last_rtc_update = xtime.tv_sec - 600;
232 }
233 write_sequnlock(&xtime_lock);
234 return IRQ_HANDLED;
235}
236
237void __init time_init(void)
238{
239 time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60; /* 1 Jan 2007 */
240
241#ifdef CONFIG_RTC_DRV_BFIN
242 /* [#2663] hack to filter junk RTC values that would cause
243 * userspace to have to deal with time values greater than
244 * 2^31 seconds (which uClibc cannot cope with yet)
245 */
246 if ((bfin_read_RTC_STAT() & 0xC0000000) == 0xC0000000) {
247 printk(KERN_NOTICE "bfin-rtc: invalid date; resetting\n");
248 bfin_write_RTC_STAT(0);
249 }
250#endif
251
252 /* Initialize xtime. From now on, xtime is updated with timer interrupts */
253 xtime.tv_sec = secs_since_1970;
254 xtime.tv_nsec = 0;
255
256 wall_to_monotonic.tv_sec = -xtime.tv_sec;
257
258 time_sched_init(timer_interrupt);
259}
260
261#ifndef CONFIG_GENERIC_TIME
262void do_gettimeofday(struct timeval *tv)
263{
264 unsigned long flags;
265 unsigned long seq;
266 unsigned long usec, sec;
267
268 do {
269 seq = read_seqbegin_irqsave(&xtime_lock, flags);
270 usec = gettimeoffset();
271 sec = xtime.tv_sec;
272 usec += (xtime.tv_nsec / NSEC_PER_USEC);
273 }
274 while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
275
276 while (usec >= USEC_PER_SEC) {
277 usec -= USEC_PER_SEC;
278 sec++;
279 }
280
281 tv->tv_sec = sec;
282 tv->tv_usec = usec;
283}
284EXPORT_SYMBOL(do_gettimeofday);
285
286int do_settimeofday(struct timespec *tv)
287{
288 time_t wtm_sec, sec = tv->tv_sec;
289 long wtm_nsec, nsec = tv->tv_nsec;
290
291 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
292 return -EINVAL;
293
294 write_seqlock_irq(&xtime_lock);
295 /*
296 * This is revolting. We need to set the xtime.tv_usec
297 * correctly. However, the value in this location is
298 * is value at the last tick.
299 * Discover what correction gettimeofday
300 * would have done, and then undo it!
301 */
302 nsec -= (gettimeoffset() * NSEC_PER_USEC);
303
304 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
305 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
306
307 set_normalized_timespec(&xtime, sec, nsec);
308 set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
309
310 ntp_clear();
311
312 write_sequnlock_irq(&xtime_lock);
313 clock_was_set();
314
315 return 0;
316}
317EXPORT_SYMBOL(do_settimeofday);
318#endif /* !CONFIG_GENERIC_TIME */
319
320/*
321 * Scheduler clock - returns current time in nanosec units.
322 */
323unsigned long long sched_clock(void)
324{
325 return (unsigned long long)jiffies *(NSEC_PER_SEC / HZ);
326}
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
new file mode 100644
index 000000000000..9556b73de808
--- /dev/null
+++ b/arch/blackfin/kernel/traps.c
@@ -0,0 +1,649 @@
1/*
2 * File: arch/blackfin/kernel/traps.c
3 * Based on:
4 * Author: Hamish Macdonald
5 *
6 * Created:
7 * Description: uses S/W interrupt 15 for the system calls
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#include <asm/uaccess.h>
31#include <asm/traps.h>
32#include <asm/cacheflush.h>
33#include <asm/blackfin.h>
34#include <asm/uaccess.h>
35#include <asm/irq_handler.h>
36#include <linux/interrupt.h>
37#include <linux/module.h>
38#include <linux/kallsyms.h>
39
40#ifdef CONFIG_KGDB
41# include <linux/debugger.h>
42# include <linux/kgdb.h>
43#endif
44
45/* Initiate the event table handler */
46void __init trap_init(void)
47{
48 CSYNC();
49 bfin_write_EVT3(trap);
50 CSYNC();
51}
52
53asmlinkage void trap_c(struct pt_regs *fp);
54
55int kstack_depth_to_print = 48;
56
57static int printk_address(unsigned long address)
58{
59 struct vm_list_struct *vml;
60 struct task_struct *p;
61 struct mm_struct *mm;
62
63#ifdef CONFIG_KALLSYMS
64 unsigned long offset = 0, symsize;
65 const char *symname;
66 char *modname;
67 char *delim = ":";
68 char namebuf[128];
69
70 /* look up the address and see if we are in kernel space */
71 symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);
72
73 if (symname) {
74 /* yeah! kernel space! */
75 if (!modname)
76 modname = delim = "";
77 return printk("<0x%p> { %s%s%s%s + 0x%lx }",
78 (void*)address, delim, modname, delim, symname,
79 (unsigned long)offset);
80
81 }
82#endif
83
84 /* looks like we're off in user-land, so let's walk all the
85 * mappings of all our processes and see if we can't be a whee
86 * bit more specific
87 */
88 write_lock_irq(&tasklist_lock);
89 for_each_process(p) {
90 mm = get_task_mm(p);
91 if (!mm)
92 continue;
93
94 vml = mm->context.vmlist;
95 while (vml) {
96 struct vm_area_struct *vma = vml->vma;
97
98 if (address >= vma->vm_start && address < vma->vm_end) {
99 char *name = p->comm;
100 struct file *file = vma->vm_file;
101 if (file) {
102 char _tmpbuf[256];
103 name = d_path(file->f_dentry,
104 file->f_vfsmnt,
105 _tmpbuf,
106 sizeof(_tmpbuf));
107 }
108
109 write_unlock_irq(&tasklist_lock);
110 return printk("<0x%p> [ %s + 0x%lx ]",
111 (void*)address, name,
112 (unsigned long)
113 ((address - vma->vm_start) +
114 (vma->vm_pgoff << PAGE_SHIFT)));
115 }
116
117 vml = vml->next;
118 }
119 }
120 write_unlock_irq(&tasklist_lock);
121
122 /* we were unable to find this address anywhere */
123 return printk("[<0x%p>]", (void*)address);
124}
125
126#define trace_buffer_save(x) \
127 do { \
128 (x) = bfin_read_TBUFCTL(); \
129 bfin_write_TBUFCTL((x) & ~TBUFEN); \
130 } while (0)
131#define trace_buffer_restore(x) \
132 do { \
133 bfin_write_TBUFCTL((x)); \
134 } while (0)
135
136asmlinkage void trap_c(struct pt_regs *fp)
137{
138 int j, sig = 0;
139 siginfo_t info;
140 unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
141
142#ifdef CONFIG_KGDB
143# define CHK_DEBUGGER_TRAP() do { CHK_DEBUGGER(trapnr, sig, info.si_code, fp,); } while (0)
144# define CHK_DEBUGGER_TRAP_MAYBE() do { if (kgdb_connected) CHK_DEBUGGER_TRAP(); } while (0)
145#else
146# define CHK_DEBUGGER_TRAP() do { } while (0)
147# define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
148#endif
149
150 trace_buffer_save(j);
151
152 /* trap_c() will be called for exceptions. During exceptions
153 * processing, the pc value should be set with retx value.
154 * With this change we can cleanup some code in signal.c- TODO
155 */
156 fp->orig_pc = fp->retx;
157 /* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n",
158 trapnr, fp->ipend, fp->pc, fp->retx); */
159
160 /* send the appropriate signal to the user program */
161 switch (trapnr) {
162
163 /* This table works in conjuction with the one in ./mach-common/entry.S
164 * Some exceptions are handled there (in assembly, in exception space)
165 * Some are handled here, (in C, in interrupt space)
166 * Some, like CPLB, are handled in both, where the normal path is
167 * handled in assembly/exception space, and the error path is handled
168 * here
169 */
170
171 /* 0x00 - Linux Syscall, getting here is an error */
172 /* 0x01 - userspace gdb breakpoint, handled here */
173 case VEC_EXCPT01:
174 info.si_code = TRAP_ILLTRAP;
175 sig = SIGTRAP;
176 CHK_DEBUGGER_TRAP_MAYBE();
177 /* Check if this is a breakpoint in kernel space */
178 if (fp->ipend & 0xffc0)
179 return;
180 else
181 break;
182#ifdef CONFIG_KGDB
183 case VEC_EXCPT02 : /* gdb connection */
184 info.si_code = TRAP_ILLTRAP;
185 sig = SIGTRAP;
186 CHK_DEBUGGER_TRAP();
187 return;
188#else
189 /* 0x02 - User Defined, Caught by default */
190#endif
191 /* 0x03 - Atomic test and set */
192 case VEC_EXCPT03:
193 info.si_code = SEGV_STACKFLOW;
194 sig = SIGSEGV;
195 printk(KERN_EMERG EXC_0x03);
196 CHK_DEBUGGER_TRAP();
197 break;
198 /* 0x04 - spinlock - handled by _ex_spinlock,
199 getting here is an error */
200 /* 0x05 - User Defined, Caught by default */
201 /* 0x06 - User Defined, Caught by default */
202 /* 0x07 - User Defined, Caught by default */
203 /* 0x08 - User Defined, Caught by default */
204 /* 0x09 - User Defined, Caught by default */
205 /* 0x0A - User Defined, Caught by default */
206 /* 0x0B - User Defined, Caught by default */
207 /* 0x0C - User Defined, Caught by default */
208 /* 0x0D - User Defined, Caught by default */
209 /* 0x0E - User Defined, Caught by default */
210 /* 0x0F - User Defined, Caught by default */
211 /* 0x10 HW Single step, handled here */
212 case VEC_STEP:
213 info.si_code = TRAP_STEP;
214 sig = SIGTRAP;
215 CHK_DEBUGGER_TRAP_MAYBE();
216 /* Check if this is a single step in kernel space */
217 if (fp->ipend & 0xffc0)
218 return;
219 else
220 break;
221 /* 0x11 - Trace Buffer Full, handled here */
222 case VEC_OVFLOW:
223 info.si_code = TRAP_TRACEFLOW;
224 sig = SIGTRAP;
225 printk(KERN_EMERG EXC_0x11);
226 CHK_DEBUGGER_TRAP();
227 break;
228 /* 0x12 - Reserved, Caught by default */
229 /* 0x13 - Reserved, Caught by default */
230 /* 0x14 - Reserved, Caught by default */
231 /* 0x15 - Reserved, Caught by default */
232 /* 0x16 - Reserved, Caught by default */
233 /* 0x17 - Reserved, Caught by default */
234 /* 0x18 - Reserved, Caught by default */
235 /* 0x19 - Reserved, Caught by default */
236 /* 0x1A - Reserved, Caught by default */
237 /* 0x1B - Reserved, Caught by default */
238 /* 0x1C - Reserved, Caught by default */
239 /* 0x1D - Reserved, Caught by default */
240 /* 0x1E - Reserved, Caught by default */
241 /* 0x1F - Reserved, Caught by default */
242 /* 0x20 - Reserved, Caught by default */
243 /* 0x21 - Undefined Instruction, handled here */
244 case VEC_UNDEF_I:
245 info.si_code = ILL_ILLOPC;
246 sig = SIGILL;
247 printk(KERN_EMERG EXC_0x21);
248 CHK_DEBUGGER_TRAP();
249 break;
250 /* 0x22 - Illegal Instruction Combination, handled here */
251 case VEC_ILGAL_I:
252 info.si_code = ILL_ILLPARAOP;
253 sig = SIGILL;
254 printk(KERN_EMERG EXC_0x22);
255 CHK_DEBUGGER_TRAP();
256 break;
257 /* 0x23 - Data CPLB Protection Violation,
258 normal case is handled in _cplb_hdr */
259 case VEC_CPLB_VL:
260 info.si_code = ILL_CPLB_VI;
261 sig = SIGILL;
262 printk(KERN_EMERG EXC_0x23);
263 CHK_DEBUGGER_TRAP();
264 break;
265 /* 0x24 - Data access misaligned, handled here */
266 case VEC_MISALI_D:
267 info.si_code = BUS_ADRALN;
268 sig = SIGBUS;
269 printk(KERN_EMERG EXC_0x24);
270 CHK_DEBUGGER_TRAP();
271 break;
272 /* 0x25 - Unrecoverable Event, handled here */
273 case VEC_UNCOV:
274 info.si_code = ILL_ILLEXCPT;
275 sig = SIGILL;
276 printk(KERN_EMERG EXC_0x25);
277 CHK_DEBUGGER_TRAP();
278 break;
279 /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
280 error case is handled here */
281 case VEC_CPLB_M:
282 info.si_code = BUS_ADRALN;
283 sig = SIGBUS;
284 printk(KERN_EMERG EXC_0x26);
285 CHK_DEBUGGER_TRAP();
286 break;
287 /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
288 case VEC_CPLB_MHIT:
289 info.si_code = ILL_CPLB_MULHIT;
290#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
291 sig = SIGSEGV;
292 printk(KERN_EMERG "\n\nNULL pointer access (probably)\n");
293#else
294 sig = SIGILL;
295 printk(KERN_EMERG EXC_0x27);
296#endif
297 CHK_DEBUGGER_TRAP();
298 break;
299 /* 0x28 - Emulation Watchpoint, handled here */
300 case VEC_WATCH:
301 info.si_code = TRAP_WATCHPT;
302 sig = SIGTRAP;
303 pr_debug(EXC_0x28);
304 CHK_DEBUGGER_TRAP_MAYBE();
305 /* Check if this is a watchpoint in kernel space */
306 if (fp->ipend & 0xffc0)
307 return;
308 else
309 break;
310#ifdef CONFIG_BF535
311 /* 0x29 - Instruction fetch access error (535 only) */
312 case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */
313 info.si_code = BUS_OPFETCH;
314 sig = SIGBUS;
315 printk(KERN_EMERG "BF535: VEC_ISTRU_VL\n");
316 CHK_DEBUGGER_TRAP();
317 break;
318#else
319 /* 0x29 - Reserved, Caught by default */
320#endif
321 /* 0x2A - Instruction fetch misaligned, handled here */
322 case VEC_MISALI_I:
323 info.si_code = BUS_ADRALN;
324 sig = SIGBUS;
325 printk(KERN_EMERG EXC_0x2A);
326 CHK_DEBUGGER_TRAP();
327 break;
328 /* 0x2B - Instruction CPLB protection Violation,
329 handled in _cplb_hdr */
330 case VEC_CPLB_I_VL:
331 info.si_code = ILL_CPLB_VI;
332 sig = SIGILL;
333 printk(KERN_EMERG EXC_0x2B);
334 CHK_DEBUGGER_TRAP();
335 break;
336 /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
337 case VEC_CPLB_I_M:
338 info.si_code = ILL_CPLB_MISS;
339 sig = SIGBUS;
340 printk(KERN_EMERG EXC_0x2C);
341 CHK_DEBUGGER_TRAP();
342 break;
343 /* 0x2D - Instruction CPLB Multiple Hits, handled here */
344 case VEC_CPLB_I_MHIT:
345 info.si_code = ILL_CPLB_MULHIT;
346#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
347 sig = SIGSEGV;
348 printk(KERN_EMERG "\n\nJump to address 0 - 0x0fff\n");
349#else
350 sig = SIGILL;
351 printk(KERN_EMERG EXC_0x2D);
352#endif
353 CHK_DEBUGGER_TRAP();
354 break;
355 /* 0x2E - Illegal use of Supervisor Resource, handled here */
356 case VEC_ILL_RES:
357 info.si_code = ILL_PRVOPC;
358 sig = SIGILL;
359 printk(KERN_EMERG EXC_0x2E);
360 CHK_DEBUGGER_TRAP();
361 break;
362 /* 0x2F - Reserved, Caught by default */
363 /* 0x30 - Reserved, Caught by default */
364 /* 0x31 - Reserved, Caught by default */
365 /* 0x32 - Reserved, Caught by default */
366 /* 0x33 - Reserved, Caught by default */
367 /* 0x34 - Reserved, Caught by default */
368 /* 0x35 - Reserved, Caught by default */
369 /* 0x36 - Reserved, Caught by default */
370 /* 0x37 - Reserved, Caught by default */
371 /* 0x38 - Reserved, Caught by default */
372 /* 0x39 - Reserved, Caught by default */
373 /* 0x3A - Reserved, Caught by default */
374 /* 0x3B - Reserved, Caught by default */
375 /* 0x3C - Reserved, Caught by default */
376 /* 0x3D - Reserved, Caught by default */
377 /* 0x3E - Reserved, Caught by default */
378 /* 0x3F - Reserved, Caught by default */
379 default:
380 info.si_code = TRAP_ILLTRAP;
381 sig = SIGTRAP;
382 printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
383 (fp->seqstat & SEQSTAT_EXCAUSE));
384 CHK_DEBUGGER_TRAP();
385 break;
386 }
387
388 info.si_signo = sig;
389 info.si_errno = 0;
390 info.si_addr = (void *)fp->pc;
391 force_sig_info(sig, &info, current);
392 if (sig != 0 && sig != SIGTRAP) {
393 unsigned long stack;
394 dump_bfin_regs(fp, (void *)fp->retx);
395 dump_bfin_trace_buffer();
396 show_stack(current, &stack);
397 if (current->mm == NULL)
398 panic("Kernel exception");
399 }
400
401 /* if the address that we are about to return to is not valid, set it
402 * to a valid address, if we have a current application or panic
403 */
404 if (!(fp->pc <= physical_mem_end
405#if L1_CODE_LENGTH != 0
406 || (fp->pc >= L1_CODE_START &&
407 fp->pc <= (L1_CODE_START + L1_CODE_LENGTH))
408#endif
409 )) {
410 if (current->mm) {
411 fp->pc = current->mm->start_code;
412 } else {
413 printk(KERN_EMERG "I can't return to memory that doesn't exist - bad things happen\n");
414 panic("Help - I've fallen and can't get up\n");
415 }
416 }
417
418 trace_buffer_restore(j);
419 return;
420}
421
422/* Typical exception handling routines */
423
424void dump_bfin_trace_buffer(void)
425{
426 int tflags;
427 trace_buffer_save(tflags);
428
429 if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
430 int i;
431 printk(KERN_EMERG "Hardware Trace:\n");
432 for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
433 printk(KERN_EMERG "%2i Target : ", i);
434 printk_address((unsigned long)bfin_read_TBUF());
435 printk("\n" KERN_EMERG " Source : ");
436 printk_address((unsigned long)bfin_read_TBUF());
437 printk("\n");
438 }
439 }
440
441 trace_buffer_restore(tflags);
442}
443EXPORT_SYMBOL(dump_bfin_trace_buffer);
444
445static void show_trace(struct task_struct *tsk, unsigned long *sp)
446{
447 unsigned long addr;
448
449 printk("\nCall Trace:");
450#ifdef CONFIG_KALLSYMS
451 printk("\n");
452#endif
453
454 while (!kstack_end(sp)) {
455 addr = *sp++;
456 /*
457 * If the address is either in the text segment of the
458 * kernel, or in the region which contains vmalloc'ed
459 * memory, it *may* be the address of a calling
460 * routine; if so, print it so that someone tracing
461 * down the cause of the crash will be able to figure
462 * out the call path that was taken.
463 */
464 if (kernel_text_address(addr))
465 print_ip_sym(addr);
466 }
467
468 printk("\n");
469}
470
471void show_stack(struct task_struct *task, unsigned long *stack)
472{
473 unsigned long *endstack, addr;
474 int i;
475
476 /* Cannot call dump_bfin_trace_buffer() here as show_stack() is
477 * called externally in some places in the kernel.
478 */
479
480 if (!stack) {
481 if (task)
482 stack = (unsigned long *)task->thread.ksp;
483 else
484 stack = (unsigned long *)&stack;
485 }
486
487 addr = (unsigned long)stack;
488 endstack = (unsigned long *)PAGE_ALIGN(addr);
489
490 printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
491 for (i = 0; i < kstack_depth_to_print; i++) {
492 if (stack + 1 > endstack)
493 break;
494 if (i % 8 == 0)
495 printk("\n" KERN_EMERG " ");
496 printk(" %08lx", *stack++);
497 }
498
499 show_trace(task, stack);
500}
501
502void dump_stack(void)
503{
504 unsigned long stack;
505 int tflags;
506 trace_buffer_save(tflags);
507 dump_bfin_trace_buffer();
508 show_stack(current, &stack);
509 trace_buffer_restore(tflags);
510}
511
512EXPORT_SYMBOL(dump_stack);
513
514void dump_bfin_regs(struct pt_regs *fp, void *retaddr)
515{
516 if (current->pid) {
517 printk("\nCURRENT PROCESS:\n\n");
518 printk("COMM=%s PID=%d\n", current->comm, current->pid);
519 } else {
520 printk
521 ("\nNo Valid pid - Either things are really messed up, or you are in the kernel\n");
522 }
523
524 if (current->mm) {
525 printk("TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n"
526 "BSS = 0x%p-0x%p USER-STACK = 0x%p\n\n",
527 (void*)current->mm->start_code,
528 (void*)current->mm->end_code,
529 (void*)current->mm->start_data,
530 (void*)current->mm->end_data,
531 (void*)current->mm->end_data,
532 (void*)current->mm->brk,
533 (void*)current->mm->start_stack);
534 }
535
536 printk("return address: 0x%p; contents of [PC-16...PC+8]:\n", retaddr);
537 if (retaddr != 0 && retaddr <= (void*)physical_mem_end
538#if L1_CODE_LENGTH != 0
539 /* FIXME: Copy the code out of L1 Instruction SRAM through dma
540 memcpy. */
541 && !(retaddr >= (void*)L1_CODE_START
542 && retaddr < (void*)(L1_CODE_START + L1_CODE_LENGTH))
543#endif
544 ) {
545 int i = 0;
546 unsigned short x = 0;
547 for (i = -16; i < 8; i++) {
548 if (get_user(x, (unsigned short *)retaddr + i))
549 break;
550#ifndef CONFIG_DEBUG_HWERR
551 /* If one of the last few instructions was a STI
552 * it is likily that the error occured awhile ago
553 * and we just noticed
554 */
555 if (x >= 0x0040 && x <= 0x0047 && i <= 0)
556 panic("\n\nWARNING : You should reconfigure the kernel to turn on\n"
557 " 'Hardware error interrupt debugging'\n"
558 " The rest of this error is meanless\n");
559#endif
560
561 if (i == -8)
562 printk("\n");
563 if (i == 0)
564 printk("X\n");
565 printk("%04x ", x);
566 }
567 } else
568 printk("Cannot look at the [PC] for it is in unreadable L1 SRAM - sorry\n");
569
570 printk("\n\n");
571
572 printk("RETE: %08lx RETN: %08lx RETX: %08lx RETS: %08lx\n",
573 fp->rete, fp->retn, fp->retx, fp->rets);
574 printk("IPEND: %04lx SYSCFG: %04lx\n", fp->ipend, fp->syscfg);
575 printk("SEQSTAT: %08lx SP: %08lx\n", (long)fp->seqstat, (long)fp);
576 printk("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n",
577 fp->r0, fp->r1, fp->r2, fp->r3);
578 printk("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n",
579 fp->r4, fp->r5, fp->r6, fp->r7);
580 printk("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n",
581 fp->p0, fp->p1, fp->p2, fp->p3);
582 printk("P4: %08lx P5: %08lx FP: %08lx\n", fp->p4, fp->p5, fp->fp);
583 printk("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n",
584 fp->a0w, fp->a0x, fp->a1w, fp->a1x);
585
586 printk("LB0: %08lx LT0: %08lx LC0: %08lx\n", fp->lb0, fp->lt0,
587 fp->lc0);
588 printk("LB1: %08lx LT1: %08lx LC1: %08lx\n", fp->lb1, fp->lt1,
589 fp->lc1);
590 printk("B0: %08lx L0: %08lx M0: %08lx I0: %08lx\n", fp->b0, fp->l0,
591 fp->m0, fp->i0);
592 printk("B1: %08lx L1: %08lx M1: %08lx I1: %08lx\n", fp->b1, fp->l1,
593 fp->m1, fp->i1);
594 printk("B2: %08lx L2: %08lx M2: %08lx I2: %08lx\n", fp->b2, fp->l2,
595 fp->m2, fp->i2);
596 printk("B3: %08lx L3: %08lx M3: %08lx I3: %08lx\n", fp->b3, fp->l3,
597 fp->m3, fp->i3);
598
599 printk("\nUSP: %08lx ASTAT: %08lx\n", rdusp(), fp->astat);
600 if ((long)fp->seqstat & SEQSTAT_EXCAUSE) {
601 printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
602 printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
603 }
604
605 printk("\n\n");
606}
607
608#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
609asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text));
610#endif
611
612asmlinkage int sys_bfin_spinlock(int *spinlock)
613{
614 int ret = 0;
615 int tmp = 0;
616
617 local_irq_disable();
618 ret = get_user(tmp, spinlock);
619 if (ret == 0) {
620 if (tmp)
621 ret = 1;
622 tmp = 1;
623 put_user(tmp, spinlock);
624 }
625 local_irq_enable();
626 return ret;
627}
628
629void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
630{
631 switch (cplb_panic) {
632 case CPLB_NO_UNLOCKED:
633 printk(KERN_EMERG "All CPLBs are locked\n");
634 break;
635 case CPLB_PROT_VIOL:
636 return;
637 case CPLB_NO_ADDR_MATCH:
638 return;
639 case CPLB_UNKNOWN_ERR:
640 printk(KERN_EMERG "Unknown CPLB Exception\n");
641 break;
642 }
643
644 printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
645 printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
646 dump_bfin_regs(fp, (void *)fp->retx);
647 dump_stack();
648 panic("Unrecoverable event\n");
649}
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..6ae9ebbd8e58
--- /dev/null
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -0,0 +1,228 @@
1/*
2 * File: arch/blackfin/kernel/vmlinux.lds.S
3 * Based on: none - original work
4 * Author:
5 *
6 * Created: Tue Sep 21 2004
7 * Description: Master linker script for blackfin architecture
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#define VMLINUX_SYMBOL(_sym_) _##_sym_
31
32#include <asm-generic/vmlinux.lds.h>
33#include <asm/mem_map.h>
34
35
36OUTPUT_FORMAT("elf32-bfin")
37ENTRY(__start)
38_jiffies = _jiffies_64;
39
40MEMORY
41{
42 ram : ORIGIN = CONFIG_BOOT_LOAD, LENGTH = (CONFIG_MEM_SIZE * 1024 * 1024) - (CONFIG_BOOT_LOAD)
43 l1_data_a : ORIGIN = L1_DATA_A_START, LENGTH = L1_DATA_A_LENGTH
44 l1_data_b : ORIGIN = L1_DATA_B_START, LENGTH = L1_DATA_B_LENGTH
45 l1_code : ORIGIN = L1_CODE_START, LENGTH = L1_CODE_LENGTH
46 l1_scratch : ORIGIN = L1_SCRATCH_START, LENGTH = L1_SCRATCH_LENGTH
47}
48
49SECTIONS
50{
51 . = CONFIG_BOOT_LOAD;
52
53 .text :
54 {
55 _text = .;
56 __stext = .;
57 *(.text)
58 SCHED_TEXT
59 *(.text.lock)
60 . = ALIGN(16);
61 ___start___ex_table = .;
62 *(__ex_table)
63 ___stop___ex_table = .;
64
65 *($code)
66 *(.rodata)
67 *(.rodata.*)
68 *(__vermagic) /* Kernel version magic */
69 *(.rodata1)
70 *(.fixup)
71 *(.spinlock.text)
72
73 /* Kernel symbol table: Normal symbols */
74 . = ALIGN(4);
75 ___start___ksymtab = .;
76 *(__ksymtab)
77 ___stop___ksymtab = .;
78
79 /* Kernel symbol table: GPL-only symbols */
80 ___start___ksymtab_gpl = .;
81 *(__ksymtab_gpl)
82 ___stop___ksymtab_gpl = .;
83
84 /* Kernel symbol table: Normal unused symbols */ \
85 ___start___ksymtab_unused = .;
86 *(__ksymtab_unused)
87 ___stop___ksymtab_unused = .;
88
89 /* Kernel symbol table: GPL-only unused symbols */
90 ___start___ksymtab_unused_gpl = .;
91 *(__ksymtab_unused_gpl)
92 ___stop___ksymtab_unused_gpl = .;
93
94
95 /* Kernel symbol table: GPL-future symbols */
96 ___start___ksymtab_gpl_future = .;
97 *(__ksymtab_gpl_future)
98 ___stop___ksymtab_gpl_future = .;
99
100 /* Kernel symbol table: Normal symbols */
101 ___start___kcrctab = .;
102 *(__kcrctab)
103 ___stop___kcrctab = .;
104
105 /* Kernel symbol table: GPL-only symbols */
106 ___start___kcrctab_gpl = .;
107 *(__kcrctab_gpl)
108 ___stop___kcrctab_gpl = .;
109
110 /* Kernel symbol table: GPL-future symbols */
111 ___start___kcrctab_gpl_future = .;
112 *(__kcrctab_gpl_future)
113 ___stop___kcrctab_gpl_future = .;
114
115 /* Kernel symbol table: strings */
116 *(__ksymtab_strings)
117
118 . = ALIGN(4);
119 __etext = .;
120 } > ram
121
122 .init :
123 {
124 . = ALIGN(4096);
125 ___init_begin = .;
126 __sinittext = .;
127 *(.init.text)
128 __einittext = .;
129 *(.init.data)
130 . = ALIGN(16);
131 ___setup_start = .;
132 *(.init.setup)
133 ___setup_end = .;
134 ___start___param = .;
135 *(__param)
136 ___stop___param = .;
137 ___initcall_start = .;
138 INITCALLS
139 ___initcall_end = .;
140 ___con_initcall_start = .;
141 *(.con_initcall.init)
142 ___con_initcall_end = .;
143 ___security_initcall_start = .;
144 *(.security_initcall.init)
145 ___security_initcall_end = .;
146 . = ALIGN(4);
147 ___initramfs_start = .;
148 *(.init.ramfs)
149 ___initramfs_end = .;
150 . = ALIGN(4);
151 ___init_end = .;
152 } > ram
153
154 __l1_lma_start = .;
155
156 .text_l1 :
157 {
158 . = ALIGN(4);
159 __stext_l1 = .;
160 *(.l1.text)
161
162 . = ALIGN(4);
163 __etext_l1 = .;
164 } > l1_code AT > ram
165
166 .data_l1 :
167 {
168 . = ALIGN(4);
169 __sdata_l1 = .;
170 *(.l1.data)
171 __edata_l1 = .;
172
173 . = ALIGN(4);
174 __sbss_l1 = .;
175 *(.l1.bss)
176
177 . = ALIGN(32);
178 *(.data_l1.cacheline_aligned)
179
180 . = ALIGN(4);
181 __ebss_l1 = .;
182 } > l1_data_a AT > ram
183 .data_b_l1 :
184 {
185 . = ALIGN(4);
186 __sdata_b_l1 = .;
187 *(.l1.data.B)
188 __edata_b_l1 = .;
189
190 . = ALIGN(4);
191 __sbss_b_l1 = .;
192 *(.l1.bss.B)
193
194 . = ALIGN(4);
195 __ebss_b_l1 = .;
196 } > l1_data_b AT > ram
197
198 .data :
199 {
200 __sdata = .;
201 . = ALIGN(0x2000);
202 *(.data.init_task)
203 *(.data)
204
205 . = ALIGN(32);
206 *(.data.cacheline_aligned)
207
208 . = ALIGN(0x2000);
209 __edata = .;
210 } > ram
211
212 /DISCARD/ : { /* Exit code and data*/
213 *(.exit.text)
214 *(.exit.data)
215 *(.exitcall.exit)
216 } > ram
217
218 .bss :
219 {
220 . = ALIGN(4);
221 ___bss_start = .;
222 *(.bss)
223 *(COMMON)
224 . = ALIGN(4);
225 ___bss_stop = .;
226 __end = . ;
227 } > ram
228}