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