coreb.c 10 KB

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