aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2009-05-14 10:55:50 -0400
committerMike Frysinger <vapier@gentoo.org>2009-06-12 06:11:24 -0400
commitc8f36dc3c11c3e9e879ded82cdf5d748d4ab2fb2 (patch)
tree27ebc3fbb08a15f1561d20ed8f90c12c230db6a2 /arch/blackfin
parentb9ccf14bc5352b86e7e254e6cf55d9b917b1b1cc (diff)
Blackfin: simplify BF561 coreb driver greatly
Since 90% of this driver can be handled in user space, move it to the corebld user space application. Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/mach-bf561/Kconfig15
-rw-r--r--arch/blackfin/mach-bf561/coreb.c396
2 files changed, 33 insertions, 378 deletions
diff --git a/arch/blackfin/mach-bf561/Kconfig b/arch/blackfin/mach-bf561/Kconfig
index 638ec38ca470..6965dd59af4c 100644
--- a/arch/blackfin/mach-bf561/Kconfig
+++ b/arch/blackfin/mach-bf561/Kconfig
@@ -9,22 +9,9 @@ if (!SMP)
9comment "Core B Support" 9comment "Core B Support"
10 10
11config BF561_COREB 11config BF561_COREB
12 bool "Enable Core B support" 12 bool "Enable Core B loader"
13 default y 13 default y
14 14
15config BF561_COREB_RESET
16 bool "Enable Core B reset support"
17 default n
18 help
19 This requires code in the application that is loaded
20 into Core B. In order to reset, the application needs
21 to install an interrupt handler for Supplemental
22 Interrupt 0, that sets RETI to 0xff600000 and writes
23 bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0.
24 This causes Core B to stall when Supplemental Interrupt
25 0 is set, and will reset PC to 0xff600000 when
26 COREB_SRAM_INIT is cleared.
27
28endif 15endif
29 16
30comment "Interrupt Priority Assignment" 17comment "Interrupt Priority Assignment"
diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c
index 8598098c0840..93635a766f9c 100644
--- a/arch/blackfin/mach-bf561/coreb.c
+++ b/arch/blackfin/mach-bf561/coreb.c
@@ -1,406 +1,74 @@
1/* 1/* Load firmware into Core B on a BF561
2 * File: arch/blackfin/mach-bf561/coreb.c
3 * Based on:
4 * Author:
5 * 2 *
6 * Created: 3 * Copyright 2004-2009 Analog Devices Inc.
7 * Description: Handle CoreB on a BF561 4 * Licensed under the GPL-2 or later.
8 * 5 */
9 * Modified: 6
10 * Copyright 2004-2006 Analog Devices Inc. 7/* The Core B reset func requires code in the application that is loaded into
11 * 8 * Core B. In order to reset, the application needs to install an interrupt
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/ 9 * handler for Supplemental Interrupt 0, that sets RETI to 0xff600000 and
13 * 10 * writes bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0. This causes Core
14 * This program is free software; you can redistribute it and/or modify 11 * B to stall when Supplemental Interrupt 0 is set, and will reset PC to
15 * it under the terms of the GNU General Public License as published by 12 * 0xff600000 when COREB_SRAM_INIT is cleared.
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 */ 13 */
29 14
30#include <linux/mm.h>
31#include <linux/miscdevice.h>
32#include <linux/device.h> 15#include <linux/device.h>
33#include <linux/ioport.h>
34#include <linux/module.h>
35#include <linux/uaccess.h>
36#include <linux/fs.h> 16#include <linux/fs.h>
37#include <asm/dma.h> 17#include <linux/kernel.h>
38#include <asm/cacheflush.h> 18#include <linux/miscdevice.h>
39 19#include <linux/module.h>
40#define MODULE_VER "v0.1"
41
42static spinlock_t coreb_lock;
43static wait_queue_head_t coreb_dma_wait;
44
45#define COREB_IS_OPEN 0x00000001
46#define COREB_IS_RUNNING 0x00000010
47 20
48#define CMD_COREB_INDEX 1
49#define CMD_COREB_START 2 21#define CMD_COREB_START 2
50#define CMD_COREB_STOP 3 22#define CMD_COREB_STOP 3
51#define CMD_COREB_RESET 4 23#define CMD_COREB_RESET 4
52 24
53#define COREB_MINOR 229 25static int
54 26coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
55static unsigned long coreb_status = 0;
56static unsigned long coreb_base = 0xff600000;
57static unsigned long coreb_size = 0x4000;
58int coreb_dma_done;
59
60static loff_t coreb_lseek(struct file *file, loff_t offset, int origin);
61static ssize_t coreb_read(struct file *file, char *buf, size_t count,
62 loff_t * ppos);
63static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
64 loff_t * ppos);
65static int coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
66 unsigned long arg);
67static int coreb_open(struct inode *inode, struct file *file);
68static int coreb_release(struct inode *inode, struct file *file);
69
70static irqreturn_t coreb_dma_interrupt(int irq, void *dev_id)
71{
72 clear_dma_irqstat(CH_MEM_STREAM2_DEST);
73 coreb_dma_done = 1;
74 wake_up_interruptible(&coreb_dma_wait);
75 return IRQ_HANDLED;
76}
77
78static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
79 loff_t * ppos)
80{
81 unsigned long p = *ppos;
82 ssize_t wrote = 0;
83
84 if (p + count > coreb_size)
85 return -EFAULT;
86
87 while (count > 0) {
88 int len = count;
89
90 if (len > PAGE_SIZE)
91 len = PAGE_SIZE;
92
93 coreb_dma_done = 0;
94
95 flush_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
96 /* Source Channel */
97 set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
98 set_dma_x_count(CH_MEM_STREAM2_SRC, len);
99 set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
100 set_dma_config(CH_MEM_STREAM2_SRC, 0);
101 /* Destination Channel */
102 set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
103 set_dma_x_count(CH_MEM_STREAM2_DEST, len);
104 set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
105 set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
106
107 enable_dma(CH_MEM_STREAM2_SRC);
108 enable_dma(CH_MEM_STREAM2_DEST);
109
110 wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
111
112 disable_dma(CH_MEM_STREAM2_SRC);
113 disable_dma(CH_MEM_STREAM2_DEST);
114
115 count -= len;
116 wrote += len;
117 buf += len;
118 p += len;
119 }
120 *ppos = p;
121 return wrote;
122}
123
124static ssize_t coreb_read(struct file *file, char *buf, size_t count,
125 loff_t * ppos)
126{
127 unsigned long p = *ppos;
128 ssize_t read = 0;
129
130 if ((p + count) > coreb_size)
131 return -EFAULT;
132
133 while (count > 0) {
134 int len = count;
135
136 if (len > PAGE_SIZE)
137 len = PAGE_SIZE;
138
139 coreb_dma_done = 0;
140
141 invalidate_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
142 /* Source Channel */
143 set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
144 set_dma_x_count(CH_MEM_STREAM2_SRC, len);
145 set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
146 set_dma_config(CH_MEM_STREAM2_SRC, 0);
147 /* Destination Channel */
148 set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
149 set_dma_x_count(CH_MEM_STREAM2_DEST, len);
150 set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
151 set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
152
153 enable_dma(CH_MEM_STREAM2_SRC);
154 enable_dma(CH_MEM_STREAM2_DEST);
155
156 wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
157
158 disable_dma(CH_MEM_STREAM2_SRC);
159 disable_dma(CH_MEM_STREAM2_DEST);
160
161 count -= len;
162 read += len;
163 buf += len;
164 p += len;
165 }
166
167 return read;
168}
169
170static loff_t coreb_lseek(struct file *file, loff_t offset, int origin)
171{ 27{
172 loff_t ret; 28 int ret = 0;
173
174 mutex_lock(&file->f_dentry->d_inode->i_mutex);
175
176 switch (origin) {
177 case 0 /* SEEK_SET */ :
178 if (offset < coreb_size) {
179 file->f_pos = offset;
180 ret = file->f_pos;
181 } else
182 ret = -EINVAL;
183 break;
184 case 1 /* SEEK_CUR */ :
185 if ((offset + file->f_pos) < coreb_size) {
186 file->f_pos += offset;
187 ret = file->f_pos;
188 } else
189 ret = -EINVAL;
190 default:
191 ret = -EINVAL;
192 }
193 mutex_unlock(&file->f_dentry->d_inode->i_mutex);
194 return ret;
195}
196
197/* No BKL needed here */
198static int coreb_open(struct inode *inode, struct file *file)
199{
200 spin_lock_irq(&coreb_lock);
201
202 if (coreb_status & COREB_IS_OPEN)
203 goto out_busy;
204
205 coreb_status |= COREB_IS_OPEN;
206
207 spin_unlock_irq(&coreb_lock);
208 return 0;
209
210 out_busy:
211 spin_unlock_irq(&coreb_lock);
212 return -EBUSY;
213}
214
215static int coreb_release(struct inode *inode, struct file *file)
216{
217 spin_lock_irq(&coreb_lock);
218 coreb_status &= ~COREB_IS_OPEN;
219 spin_unlock_irq(&coreb_lock);
220 return 0;
221}
222
223static int coreb_ioctl(struct inode *inode, struct file *file,
224 unsigned int cmd, unsigned long arg)
225{
226 int retval = 0;
227 int coreb_index = 0;
228 29
229 switch (cmd) { 30 switch (cmd) {
230 case CMD_COREB_INDEX:
231 if (copy_from_user(&coreb_index, (int *)arg, sizeof(int))) {
232 retval = -EFAULT;
233 break;
234 }
235
236 spin_lock_irq(&coreb_lock);
237 switch (coreb_index) {
238 case 0:
239 coreb_base = 0xff600000;
240 coreb_size = 0x4000;
241 break;
242 case 1:
243 coreb_base = 0xff610000;
244 coreb_size = 0x4000;
245 break;
246 case 2:
247 coreb_base = 0xff500000;
248 coreb_size = 0x8000;
249 break;
250 case 3:
251 coreb_base = 0xff400000;
252 coreb_size = 0x8000;
253 break;
254 default:
255 retval = -EINVAL;
256 break;
257 }
258 spin_unlock_irq(&coreb_lock);
259
260 mutex_lock(&file->f_dentry->d_inode->i_mutex);
261 file->f_pos = 0;
262 mutex_unlock(&file->f_dentry->d_inode->i_mutex);
263 break;
264 case CMD_COREB_START: 31 case CMD_COREB_START:
265 spin_lock_irq(&coreb_lock);
266 if (coreb_status & COREB_IS_RUNNING) {
267 retval = -EBUSY;
268 break;
269 }
270 printk(KERN_INFO "Starting Core B\n");
271 coreb_status |= COREB_IS_RUNNING;
272 bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020); 32 bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
273 SSYNC();
274 spin_unlock_irq(&coreb_lock);
275 break; 33 break;
276#if defined(CONFIG_BF561_COREB_RESET)
277 case CMD_COREB_STOP: 34 case CMD_COREB_STOP:
278 spin_lock_irq(&coreb_lock);
279 printk(KERN_INFO "Stopping Core B\n");
280 bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020); 35 bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
281 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080); 36 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
282 coreb_status &= ~COREB_IS_RUNNING;
283 spin_unlock_irq(&coreb_lock);
284 break; 37 break;
285 case CMD_COREB_RESET: 38 case CMD_COREB_RESET:
286 printk(KERN_INFO "Resetting Core B\n");
287 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080); 39 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
288 break; 40 break;
289#endif 41 default:
42 ret = -EINVAL;
43 break;
290 } 44 }
291 45
292 return retval; 46 CSYNC();
47
48 return ret;
293} 49}
294 50
295static struct file_operations coreb_fops = { 51static struct file_operations coreb_fops = {
296 .owner = THIS_MODULE, 52 .owner = THIS_MODULE,
297 .llseek = coreb_lseek, 53 .ioctl = coreb_ioctl,
298 .read = coreb_read,
299 .write = coreb_write,
300 .ioctl = coreb_ioctl,
301 .open = coreb_open,
302 .release = coreb_release
303}; 54};
304 55
305static struct miscdevice coreb_dev = { 56static struct miscdevice coreb_dev = {
306 COREB_MINOR, 57 .minor = MISC_DYNAMIC_MINOR,
307 "coreb", 58 .name = "coreb",
308 &coreb_fops 59 .fops = &coreb_fops,
309}; 60};
310 61
311static ssize_t coreb_show_status(struct device *dev, struct device_attribute *attr, char *buf) 62static int __init bf561_coreb_init(void)
312{ 63{
313 return sprintf(buf, 64 return misc_register(&coreb_dev);
314 "Base Address:\t0x%08lx\n"
315 "Core B is %s\n"
316 "SICA_SYSCR:\t%04x\n"
317 "SICB_SYSCR:\t%04x\n"
318 "\n"
319 "IRQ Status:\tCore A\t\tCore B\n"
320 "ISR0:\t\t%08x\t\t%08x\n"
321 "ISR1:\t\t%08x\t\t%08x\n"
322 "IMASK0:\t\t%08x\t\t%08x\n"
323 "IMASK1:\t\t%08x\t\t%08x\n",
324 coreb_base,
325 coreb_status & COREB_IS_RUNNING ? "running" : "stalled",
326 bfin_read_SICA_SYSCR(), bfin_read_SICB_SYSCR(),
327 bfin_read_SICA_ISR0(), bfin_read_SICB_ISR0(),
328 bfin_read_SICA_ISR1(), bfin_read_SICB_ISR0(),
329 bfin_read_SICA_IMASK0(), bfin_read_SICB_IMASK0(),
330 bfin_read_SICA_IMASK1(), bfin_read_SICB_IMASK1());
331}
332
333static DEVICE_ATTR(coreb_status, S_IRUGO, coreb_show_status, NULL);
334
335int __init bf561_coreb_init(void)
336{
337 init_waitqueue_head(&coreb_dma_wait);
338
339 spin_lock_init(&coreb_lock);
340 /* Request the core memory regions for Core B */
341 if (request_mem_region(0xff600000, 0x4000,
342 "Core B - Instruction SRAM") == NULL)
343 goto exit;
344
345 if (request_mem_region(0xFF610000, 0x4000,
346 "Core B - Instruction SRAM") == NULL)
347 goto release_instruction_a_sram;
348
349 if (request_mem_region(0xFF500000, 0x8000,
350 "Core B - Data Bank B SRAM") == NULL)
351 goto release_instruction_b_sram;
352
353 if (request_mem_region(0xff400000, 0x8000,
354 "Core B - Data Bank A SRAM") == NULL)
355 goto release_data_b_sram;
356
357 if (request_dma(CH_MEM_STREAM2_DEST, "Core B - DMA Destination") < 0)
358 goto release_data_a_sram;
359
360 if (request_dma(CH_MEM_STREAM2_SRC, "Core B - DMA Source") < 0)
361 goto release_dma_dest;
362
363 set_dma_callback(CH_MEM_STREAM2_DEST, coreb_dma_interrupt, NULL);
364
365 misc_register(&coreb_dev);
366
367 if (device_create_file(coreb_dev.this_device, &dev_attr_coreb_status))
368 goto release_dma_src;
369
370 printk(KERN_INFO "BF561 Core B driver %s initialized.\n", MODULE_VER);
371 return 0;
372
373 release_dma_src:
374 free_dma(CH_MEM_STREAM2_SRC);
375 release_dma_dest:
376 free_dma(CH_MEM_STREAM2_DEST);
377 release_data_a_sram:
378 release_mem_region(0xff400000, 0x8000);
379 release_data_b_sram:
380 release_mem_region(0xff500000, 0x8000);
381 release_instruction_b_sram:
382 release_mem_region(0xff610000, 0x4000);
383 release_instruction_a_sram:
384 release_mem_region(0xff600000, 0x4000);
385 exit:
386 return -ENOMEM;
387} 65}
66module_init(bf561_coreb_init);
388 67
389void __exit bf561_coreb_exit(void) 68static void __exit bf561_coreb_exit(void)
390{ 69{
391 device_remove_file(coreb_dev.this_device, &dev_attr_coreb_status);
392 misc_deregister(&coreb_dev); 70 misc_deregister(&coreb_dev);
393
394 release_mem_region(0xff610000, 0x4000);
395 release_mem_region(0xff600000, 0x4000);
396 release_mem_region(0xff500000, 0x8000);
397 release_mem_region(0xff400000, 0x8000);
398
399 free_dma(CH_MEM_STREAM2_DEST);
400 free_dma(CH_MEM_STREAM2_SRC);
401} 71}
402
403module_init(bf561_coreb_init);
404module_exit(bf561_coreb_exit); 72module_exit(bf561_coreb_exit);
405 73
406MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>"); 74MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");