coreb.c 10 KB

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