aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/mach-bf561/coreb.c
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/mach-bf561/coreb.c
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/mach-bf561/coreb.c')
-rw-r--r--arch/blackfin/mach-bf561/coreb.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c
new file mode 100644
index 00000000000..b28582fe083
--- /dev/null
+++ b/arch/blackfin/mach-bf561/coreb.c
@@ -0,0 +1,402 @@
1/*
2 * File: arch/blackfin/mach-bf561/coreb.c
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: Handle 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/mm.h>
31#include <linux/miscdevice.h>
32#include <linux/device.h>
33#include <linux/ioport.h>
34#include <linux/module.h>
35#include <asm/dma.h>
36#include <asm/uaccess.h>
37
38#define MODULE_VER "v0.1"
39
40static spinlock_t coreb_lock;
41static wait_queue_head_t coreb_dma_wait;
42
43#define COREB_IS_OPEN 0x00000001
44#define COREB_IS_RUNNING 0x00000010
45
46#define CMD_COREB_INDEX 1
47#define CMD_COREB_START 2
48#define CMD_COREB_STOP 3
49#define CMD_COREB_RESET 4
50
51#define COREB_MINOR 229
52
53static unsigned long coreb_status = 0;
54static unsigned long coreb_base = 0xff600000;
55static unsigned long coreb_size = 0x4000;
56int coreb_dma_done;
57
58static loff_t coreb_lseek(struct file *file, loff_t offset, int origin);
59static ssize_t coreb_read(struct file *file, char *buf, size_t count,
60 loff_t * ppos);
61static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
62 loff_t * ppos);
63static int coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
64 unsigned long arg);
65static int coreb_open(struct inode *inode, struct file *file);
66static int coreb_release(struct inode *inode, struct file *file);
67
68static irqreturn_t coreb_dma_interrupt(int irq, void *dev_id)
69{
70 clear_dma_irqstat(CH_MEM_STREAM2_DEST);
71 coreb_dma_done = 1;
72 wake_up_interruptible(&coreb_dma_wait);
73 return IRQ_HANDLED;
74}
75
76static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
77 loff_t * ppos)
78{
79 unsigned long p = *ppos;
80 ssize_t wrote = 0;
81
82 if (p + count > coreb_size)
83 return -EFAULT;
84
85 while (count > 0) {
86 int len = count;
87
88 if (len > PAGE_SIZE)
89 len = PAGE_SIZE;
90
91 coreb_dma_done = 0;
92
93 /* Source Channel */
94 set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
95 set_dma_x_count(CH_MEM_STREAM2_SRC, len);
96 set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
97 set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
98 /* Destination Channel */
99 set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
100 set_dma_x_count(CH_MEM_STREAM2_DEST, len);
101 set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
102 set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
103
104 enable_dma(CH_MEM_STREAM2_SRC);
105 enable_dma(CH_MEM_STREAM2_DEST);
106
107 wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
108
109 disable_dma(CH_MEM_STREAM2_SRC);
110 disable_dma(CH_MEM_STREAM2_DEST);
111
112 count -= len;
113 wrote += len;
114 buf += len;
115 p += len;
116 }
117 *ppos = p;
118 return wrote;
119}
120
121static ssize_t coreb_read(struct file *file, char *buf, size_t count,
122 loff_t * ppos)
123{
124 unsigned long p = *ppos;
125 ssize_t read = 0;
126
127 if ((p + count) > coreb_size)
128 return -EFAULT;
129
130 while (count > 0) {
131 int len = count;
132
133 if (len > PAGE_SIZE)
134 len = PAGE_SIZE;
135
136 coreb_dma_done = 0;
137
138 /* Source Channel */
139 set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
140 set_dma_x_count(CH_MEM_STREAM2_SRC, len);
141 set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
142 set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
143 /* Destination Channel */
144 set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
145 set_dma_x_count(CH_MEM_STREAM2_DEST, len);
146 set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
147 set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
148
149 enable_dma(CH_MEM_STREAM2_SRC);
150 enable_dma(CH_MEM_STREAM2_DEST);
151
152 wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
153
154 disable_dma(CH_MEM_STREAM2_SRC);
155 disable_dma(CH_MEM_STREAM2_DEST);
156
157 count -= len;
158 read += len;
159 buf += len;
160 p += len;
161 }
162
163 return read;
164}
165
166static loff_t coreb_lseek(struct file *file, loff_t offset, int origin)
167{
168 loff_t ret;
169
170 mutex_lock(&file->f_dentry->d_inode->i_mutex);
171
172 switch (origin) {
173 case 0 /* SEEK_SET */ :
174 if (offset < coreb_size) {
175 file->f_pos = offset;
176 ret = file->f_pos;
177 } else
178 ret = -EINVAL;
179 break;
180 case 1 /* SEEK_CUR */ :
181 if ((offset + file->f_pos) < coreb_size) {
182 file->f_pos += offset;
183 ret = file->f_pos;
184 } else
185 ret = -EINVAL;
186 default:
187 ret = -EINVAL;
188 }
189 mutex_unlock(&file->f_dentry->d_inode->i_mutex);
190 return ret;
191}
192
193static int coreb_open(struct inode *inode, struct file *file)
194{
195 spin_lock_irq(&coreb_lock);
196
197 if (coreb_status & COREB_IS_OPEN)
198 goto out_busy;
199
200 coreb_status |= COREB_IS_OPEN;
201
202 spin_unlock_irq(&coreb_lock);
203 return 0;
204
205 out_busy:
206 spin_unlock_irq(&coreb_lock);
207 return -EBUSY;
208}
209
210static int coreb_release(struct inode *inode, struct file *file)
211{
212 spin_lock_irq(&coreb_lock);
213 coreb_status &= ~COREB_IS_OPEN;
214 spin_unlock_irq(&coreb_lock);
215 return 0;
216}
217
218static int coreb_ioctl(struct inode *inode, struct file *file,
219 unsigned int cmd, unsigned long arg)
220{
221 int retval = 0;
222 int coreb_index = 0;
223
224 switch (cmd) {
225 case CMD_COREB_INDEX:
226 if (copy_from_user(&coreb_index, (int *)arg, sizeof(int))) {
227 retval = -EFAULT;
228 break;
229 }
230
231 spin_lock_irq(&coreb_lock);
232 switch (coreb_index) {
233 case 0:
234 coreb_base = 0xff600000;
235 coreb_size = 0x4000;
236 break;
237 case 1:
238 coreb_base = 0xff610000;
239 coreb_size = 0x4000;
240 break;
241 case 2:
242 coreb_base = 0xff500000;
243 coreb_size = 0x8000;
244 break;
245 case 3:
246 coreb_base = 0xff400000;
247 coreb_size = 0x8000;
248 break;
249 default:
250 retval = -EINVAL;
251 break;
252 }
253 spin_unlock_irq(&coreb_lock);
254
255 mutex_lock(&file->f_dentry->d_inode->i_mutex);
256 file->f_pos = 0;
257 mutex_unlock(&file->f_dentry->d_inode->i_mutex);
258 break;
259 case CMD_COREB_START:
260 spin_lock_irq(&coreb_lock);
261 if (coreb_status & COREB_IS_RUNNING) {
262 retval = -EBUSY;
263 break;
264 }
265 printk(KERN_INFO "Starting Core B\n");
266 coreb_status |= COREB_IS_RUNNING;
267 bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
268 SSYNC();
269 spin_lock_irq(&coreb_lock);
270 break;
271#if defined(CONFIG_BF561_COREB_RESET)
272 case CMD_COREB_STOP:
273 spin_lock_irq(&coreb_lock);
274 printk(KERN_INFO "Stopping Core B\n");
275 bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
276 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
277 coreb_status &= ~COREB_IS_RUNNING;
278 spin_lock_irq(&coreb_lock);
279 break;
280 case CMD_COREB_RESET:
281 printk(KERN_INFO "Resetting Core B\n");
282 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
283 break;
284#endif
285 }
286
287 return retval;
288}
289
290static struct file_operations coreb_fops = {
291 .owner = THIS_MODULE,
292 .llseek = coreb_lseek,
293 .read = coreb_read,
294 .write = coreb_write,
295 .ioctl = coreb_ioctl,
296 .open = coreb_open,
297 .release = coreb_release
298};
299
300static struct miscdevice coreb_dev = {
301 COREB_MINOR,
302 "coreb",
303 &coreb_fops
304};
305
306static ssize_t coreb_show_status(struct device *dev, struct device_attribute *attr, char *buf)
307{
308 return sprintf(buf,
309 "Base Address:\t0x%08lx\n"
310 "Core B is %s\n"
311 "SICA_SYSCR:\t%04x\n"
312 "SICB_SYSCR:\t%04x\n"
313 "\n"
314 "IRQ Status:\tCore A\t\tCore B\n"
315 "ISR0:\t\t%08x\t\t%08x\n"
316 "ISR1:\t\t%08x\t\t%08x\n"
317 "IMASK0:\t\t%08x\t\t%08x\n"
318 "IMASK1:\t\t%08x\t\t%08x\n",
319 coreb_base,
320 coreb_status & COREB_IS_RUNNING ? "running" : "stalled",
321 bfin_read_SICA_SYSCR(), bfin_read_SICB_SYSCR(),
322 bfin_read_SICA_ISR0(), bfin_read_SICB_ISR0(),
323 bfin_read_SICA_ISR1(), bfin_read_SICB_ISR0(),
324 bfin_read_SICA_IMASK0(), bfin_read_SICB_IMASK0(),
325 bfin_read_SICA_IMASK1(), bfin_read_SICB_IMASK1());
326}
327
328static DEVICE_ATTR(coreb_status, S_IRUGO, coreb_show_status, NULL);
329
330int __init bf561_coreb_init(void)
331{
332 init_waitqueue_head(&coreb_dma_wait);
333
334 spin_lock_init(&coreb_lock);
335 /* Request the core memory regions for Core B */
336 if (request_mem_region(0xff600000, 0x4000,
337 "Core B - Instruction SRAM") == NULL)
338 goto exit;
339
340 if (request_mem_region(0xFF610000, 0x4000,
341 "Core B - Instruction SRAM") == NULL)
342 goto release_instruction_a_sram;
343
344 if (request_mem_region(0xFF500000, 0x8000,
345 "Core B - Data Bank B SRAM") == NULL)
346 goto release_instruction_b_sram;
347
348 if (request_mem_region(0xff400000, 0x8000,
349 "Core B - Data Bank A SRAM") == NULL)
350 goto release_data_b_sram;
351
352 if (request_dma(CH_MEM_STREAM2_DEST, "Core B - DMA Destination") < 0)
353 goto release_data_a_sram;
354
355 if (request_dma(CH_MEM_STREAM2_SRC, "Core B - DMA Source") < 0)
356 goto release_dma_dest;
357
358 set_dma_callback(CH_MEM_STREAM2_DEST, coreb_dma_interrupt, NULL);
359
360 misc_register(&coreb_dev);
361
362 if (device_create_file(coreb_dev.this_device, &dev_attr_coreb_status))
363 goto release_dma_src;
364
365 printk(KERN_INFO "BF561 Core B driver %s initialized.\n", MODULE_VER);
366 return 0;
367
368 release_dma_src:
369 free_dma(CH_MEM_STREAM2_SRC);
370 release_dma_dest:
371 free_dma(CH_MEM_STREAM2_DEST);
372 release_data_a_sram:
373 release_mem_region(0xff400000, 0x8000);
374 release_data_b_sram:
375 release_mem_region(0xff500000, 0x8000);
376 release_instruction_b_sram:
377 release_mem_region(0xff610000, 0x4000);
378 release_instruction_a_sram:
379 release_mem_region(0xff600000, 0x4000);
380 exit:
381 return -ENOMEM;
382}
383
384void __exit bf561_coreb_exit(void)
385{
386 device_remove_file(coreb_dev.this_device, &dev_attr_coreb_status);
387 misc_deregister(&coreb_dev);
388
389 release_mem_region(0xff610000, 0x4000);
390 release_mem_region(0xff600000, 0x4000);
391 release_mem_region(0xff500000, 0x8000);
392 release_mem_region(0xff400000, 0x8000);
393
394 free_dma(CH_MEM_STREAM2_DEST);
395 free_dma(CH_MEM_STREAM2_SRC);
396}
397
398module_init(bf561_coreb_init);
399module_exit(bf561_coreb_exit);
400
401MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
402MODULE_DESCRIPTION("BF561 Core B Support");