hx280enc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /*------------------------------------------------------------------------------
  2. -- --
  3. -- This software is confidential and proprietary and may be used --
  4. -- only as expressly authorized by a licensing agreement from --
  5. -- --
  6. -- Hantro Products Oy. --
  7. -- --
  8. -- (C) COPYRIGHT 2006 HANTRO PRODUCTS OY --
  9. -- ALL RIGHTS RESERVED --
  10. -- --
  11. -- The entire notice above must be reproduced --
  12. -- on all copies and should not be removed. --
  13. -- --
  14. --------------------------------------------------------------------------------
  15. --
  16. -- Abstract : 6280/7280/8270/8290 Encoder device driver (kernel module)
  17. --
  18. ------------------------------------------------------------------------------*/
  19. #include <linux/kernel.h>
  20. #include <linux/module.h>
  21. /* needed for __init,__exit directives */
  22. #include <linux/init.h>
  23. /* needed for remap_page_range
  24. SetPageReserved
  25. ClearPageReserved
  26. */
  27. #include <linux/mm.h>
  28. /* obviously, for kmalloc */
  29. #include <linux/slab.h>
  30. /* for struct file_operations, register_chrdev() */
  31. #include <linux/fs.h>
  32. /* standard error codes */
  33. #include <linux/errno.h>
  34. #include <linux/moduleparam.h>
  35. /* request_irq(), free_irq() */
  36. #include <linux/interrupt.h>
  37. /* needed for virt_to_phys() */
  38. #include <asm/io.h>
  39. #include <linux/pci.h>
  40. #include <asm/uaccess.h>
  41. #include <linux/ioport.h>
  42. #include <asm/irq.h>
  43. #include <linux/version.h>
  44. /* our own stuff */
  45. #include "hx280enc.h"
  46. /* module description */
  47. MODULE_LICENSE("Proprietary");
  48. MODULE_AUTHOR("Hantro Products Oy");
  49. MODULE_DESCRIPTION("Hantro 6280/7280/8270/8290 Encoder driver");
  50. /* this is ARM Integrator specific stuff */
  51. #define INTEGRATOR_LOGIC_MODULE0_BASE 0xC0000000
  52. /*
  53. #define INTEGRATOR_LOGIC_MODULE1_BASE 0xD0000000
  54. #define INTEGRATOR_LOGIC_MODULE2_BASE 0xE0000000
  55. #define INTEGRATOR_LOGIC_MODULE3_BASE 0xF0000000
  56. */
  57. #define VP_PB_INT_LT 30
  58. /*
  59. #define INT_EXPINT1 10
  60. #define INT_EXPINT2 11
  61. #define INT_EXPINT3 12
  62. */
  63. /* these could be module params in the future */
  64. #define ENC_IO_BASE INTEGRATOR_LOGIC_MODULE0_BASE
  65. #define ENC_IO_SIZE (96 * 4) /* bytes */
  66. #define ENC_HW_ID1 0x62800000
  67. #define ENC_HW_ID2 0x72800000
  68. #define ENC_HW_ID3 0x82700000
  69. #define ENC_HW_ID4 0x82900000
  70. #define HX280ENC_BUF_SIZE 0
  71. unsigned long base_port = INTEGRATOR_LOGIC_MODULE0_BASE;
  72. int irq = VP_PB_INT_LT;
  73. /* module_param(name, type, perm) */
  74. module_param(base_port, ulong, 0);
  75. module_param(irq, int, 0);
  76. /* and this is our MAJOR; use 0 for dynamic allocation (recommended)*/
  77. static int hx280enc_major = 0;
  78. /* here's all the must remember stuff */
  79. typedef struct
  80. {
  81. char *buffer;
  82. unsigned int buffsize;
  83. unsigned long iobaseaddr;
  84. unsigned int iosize;
  85. volatile u8 *hwregs;
  86. unsigned int irq;
  87. struct fasync_struct *async_queue;
  88. } hx280enc_t;
  89. /* dynamic allocation? */
  90. static hx280enc_t hx280enc_data;
  91. static int ReserveIO(void);
  92. static void ReleaseIO(void);
  93. static void ResetAsic(hx280enc_t * dev);
  94. #ifdef HX280ENC_DEBUG
  95. static void dump_regs(unsigned long data);
  96. #endif
  97. /* IRQ handler */
  98. #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
  99. static irqreturn_t hx280enc_isr(int irq, void *dev_id, struct pt_regs *regs);
  100. #else
  101. static irqreturn_t hx280enc_isr(int irq, void *dev_id);
  102. #endif
  103. /* VM operations */
  104. #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28))
  105. static struct page *hx280enc_vm_nopage(struct vm_area_struct *vma,
  106. unsigned long address, int *type)
  107. {
  108. PDEBUG("hx280enc_vm_nopage: problem with mem access\n");
  109. return NOPAGE_SIGBUS; /* send a SIGBUS */
  110. }
  111. #else
  112. static int hx280enc_vm_fault(struct vm_area_struct *vma,
  113. struct vm_fault *vmf)
  114. {
  115. PDEBUG("hx280enc_vm_fault: problem with mem access\n");
  116. return VM_FAULT_SIGBUS; /* send a SIGBUS */
  117. }
  118. #endif
  119. static void hx280enc_vm_open(struct vm_area_struct *vma)
  120. {
  121. PDEBUG("hx280enc_vm_open:\n");
  122. }
  123. static void hx280enc_vm_close(struct vm_area_struct *vma)
  124. {
  125. PDEBUG("hx280enc_vm_close:\n");
  126. }
  127. static struct vm_operations_struct hx280enc_vm_ops = {
  128. open:hx280enc_vm_open,
  129. close:hx280enc_vm_close,
  130. #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28))
  131. nopage:hx280enc_vm_nopage,
  132. #else
  133. fault:hx280enc_vm_fault,
  134. #endif
  135. };
  136. /* the device's mmap method. The VFS has kindly prepared the process's
  137. * vm_area_struct for us, so we examine this to see what was requested.
  138. */
  139. static int hx280enc_mmap(struct file *filp, struct vm_area_struct *vma)
  140. {
  141. int result = -EINVAL;
  142. result = -EINVAL;
  143. vma->vm_ops = &hx280enc_vm_ops;
  144. return result;
  145. }
  146. static int hx280enc_ioctl(struct inode *inode, struct file *filp,
  147. unsigned int cmd, unsigned long arg)
  148. {
  149. int err = 0;
  150. PDEBUG("ioctl cmd 0x%08ux\n", cmd);
  151. /*
  152. * extract the type and number bitfields, and don't encode
  153. * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
  154. */
  155. if(_IOC_TYPE(cmd) != HX280ENC_IOC_MAGIC)
  156. return -ENOTTY;
  157. if(_IOC_NR(cmd) > HX280ENC_IOC_MAXNR)
  158. return -ENOTTY;
  159. /*
  160. * the direction is a bitmask, and VERIFY_WRITE catches R/W
  161. * transfers. `Type' is user-oriented, while
  162. * access_ok is kernel-oriented, so the concept of "read" and
  163. * "write" is reversed
  164. */
  165. if(_IOC_DIR(cmd) & _IOC_READ)
  166. err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd));
  167. else if(_IOC_DIR(cmd) & _IOC_WRITE)
  168. err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd));
  169. if(err)
  170. return -EFAULT;
  171. switch (cmd)
  172. {
  173. case HX280ENC_IOCGHWOFFSET:
  174. __put_user(hx280enc_data.iobaseaddr, (unsigned long *) arg);
  175. break;
  176. case HX280ENC_IOCGHWIOSIZE:
  177. __put_user(hx280enc_data.iosize, (unsigned int *) arg);
  178. break;
  179. }
  180. return 0;
  181. }
  182. static int hx280enc_open(struct inode *inode, struct file *filp)
  183. {
  184. int result = 0;
  185. hx280enc_t *dev = &hx280enc_data;
  186. filp->private_data = (void *) dev;
  187. PDEBUG("dev opened\n");
  188. return result;
  189. }
  190. static int hx280enc_fasync(int fd, struct file *filp, int mode)
  191. {
  192. hx280enc_t *dev = (hx280enc_t *) filp->private_data;
  193. PDEBUG("fasync called\n");
  194. return fasync_helper(fd, filp, mode, &dev->async_queue);
  195. }
  196. static int hx280enc_release(struct inode *inode, struct file *filp)
  197. {
  198. #ifdef HX280ENC_DEBUG
  199. hx280enc_t *dev = (hx280enc_t *) filp->private_data;
  200. dump_regs((unsigned long) dev); /* dump the regs */
  201. #endif
  202. /* remove this filp from the asynchronusly notified filp's */
  203. hx280enc_fasync(-1, filp, 0);
  204. PDEBUG("dev closed\n");
  205. return 0;
  206. }
  207. /* VFS methods */
  208. static struct file_operations hx280enc_fops = {
  209. mmap:hx280enc_mmap,
  210. open:hx280enc_open,
  211. release:hx280enc_release,
  212. ioctl:hx280enc_ioctl,
  213. fasync:hx280enc_fasync,
  214. };
  215. int __init hx280enc_init(void)
  216. {
  217. int result;
  218. printk(KERN_INFO "hx280enc: module init - base_port=0x%08lx irq=%i\n",
  219. base_port, irq);
  220. hx280enc_data.iobaseaddr = base_port;
  221. hx280enc_data.iosize = ENC_IO_SIZE;
  222. hx280enc_data.irq = irq;
  223. hx280enc_data.async_queue = NULL;
  224. hx280enc_data.hwregs = NULL;
  225. result = register_chrdev(hx280enc_major, "hx280enc", &hx280enc_fops);
  226. if(result < 0)
  227. {
  228. printk(KERN_INFO "hx280enc: unable to get major <%d>\n",
  229. hx280enc_major);
  230. return result;
  231. }
  232. else if(result != 0) /* this is for dynamic major */
  233. {
  234. hx280enc_major = result;
  235. }
  236. result = ReserveIO();
  237. if(result < 0)
  238. {
  239. goto err;
  240. }
  241. ResetAsic(&hx280enc_data); /* reset hardware */
  242. /* get the IRQ line */
  243. if(irq != -1)
  244. {
  245. result = request_irq(irq, hx280enc_isr,
  246. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
  247. SA_INTERRUPT | SA_SHIRQ,
  248. #else
  249. IRQF_DISABLED | IRQF_SHARED,
  250. #endif
  251. "hx280enc", (void *) &hx280enc_data);
  252. if(result == -EINVAL)
  253. {
  254. printk(KERN_ERR "hx280enc: Bad irq number or handler\n");
  255. ReleaseIO();
  256. goto err;
  257. }
  258. else if(result == -EBUSY)
  259. {
  260. printk(KERN_ERR "hx280enc: IRQ <%d> busy, change your config\n",
  261. hx280enc_data.irq);
  262. ReleaseIO();
  263. goto err;
  264. }
  265. }
  266. else
  267. {
  268. printk(KERN_INFO "hx280enc: IRQ not in use!\n");
  269. }
  270. printk(KERN_INFO "hx280enc: module inserted. Major <%d>\n", hx280enc_major);
  271. return 0;
  272. err:
  273. unregister_chrdev(hx280enc_major, "hx280enc");
  274. printk(KERN_INFO "hx280enc: module not inserted\n");
  275. return result;
  276. }
  277. void __exit hx280enc_cleanup(void)
  278. {
  279. writel(0, hx280enc_data.hwregs + 0x38); /* disable HW */
  280. writel(0, hx280enc_data.hwregs + 0x04); /* clear enc IRQ */
  281. /* free the encoder IRQ */
  282. if(hx280enc_data.irq != -1)
  283. {
  284. free_irq(hx280enc_data.irq, (void *) &hx280enc_data);
  285. }
  286. ReleaseIO();
  287. unregister_chrdev(hx280enc_major, "hx280enc");
  288. printk(KERN_INFO "hx280enc: module removed\n");
  289. return;
  290. }
  291. module_init(hx280enc_init);
  292. module_exit(hx280enc_cleanup);
  293. static int ReserveIO(void)
  294. {
  295. long int hwid;
  296. if(!request_mem_region
  297. (hx280enc_data.iobaseaddr, hx280enc_data.iosize, "hx280enc"))
  298. {
  299. printk(KERN_INFO "hx280enc: failed to reserve HW regs\n");
  300. return -EBUSY;
  301. }
  302. hx280enc_data.hwregs =
  303. (volatile u8 *) ioremap_nocache(hx280enc_data.iobaseaddr,
  304. hx280enc_data.iosize);
  305. if(hx280enc_data.hwregs == NULL)
  306. {
  307. printk(KERN_INFO "hx280enc: failed to ioremap HW regs\n");
  308. ReleaseIO();
  309. return -EBUSY;
  310. }
  311. hwid = readl(hx280enc_data.hwregs);
  312. #if 1
  313. /* check for encoder HW ID */
  314. if((((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID1 >> 16) & 0xFFFF)) &&
  315. (((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID2 >> 16) & 0xFFFF)) &&
  316. (((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID3 >> 16) & 0xFFFF)) &&
  317. (((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID4 >> 16) & 0xFFFF)))
  318. {
  319. printk(KERN_INFO "hx280enc: HW not found at 0x%08lx\n",
  320. hx280enc_data.iobaseaddr);
  321. #ifdef HX280ENC_DEBUG
  322. dump_regs((unsigned long) &hx280enc_data);
  323. #endif
  324. ReleaseIO();
  325. return -EBUSY;
  326. }
  327. #endif
  328. printk(KERN_INFO
  329. "hx280enc: HW at base <0x%08lx> with ID <0x%08lx>\n",
  330. hx280enc_data.iobaseaddr, hwid);
  331. return 0;
  332. }
  333. static void ReleaseIO(void)
  334. {
  335. if(hx280enc_data.hwregs)
  336. iounmap((void *) hx280enc_data.hwregs);
  337. release_mem_region(hx280enc_data.iobaseaddr, hx280enc_data.iosize);
  338. }
  339. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
  340. irqreturn_t hx280enc_isr(int irq, void *dev_id, struct pt_regs *regs)
  341. #else
  342. irqreturn_t hx280enc_isr(int irq, void *dev_id)
  343. #endif
  344. {
  345. hx280enc_t *dev = (hx280enc_t *) dev_id;
  346. u32 irq_status;
  347. irq_status = readl(dev->hwregs + 0x04);
  348. if(irq_status & 0x01)
  349. {
  350. /* clear enc IRQ and slice ready interrupt bit */
  351. writel(irq_status & (~0x101), dev->hwregs + 0x04);
  352. /* Handle slice ready interrupts. The reference implementation
  353. * doesn't signal slice ready interrupts to EWL.
  354. * The EWL will poll the slices ready register value. */
  355. if ((irq_status & 0x1FE) == 0x100)
  356. {
  357. PDEBUG("Slice ready IRQ handled!\n");
  358. return IRQ_HANDLED;
  359. }
  360. /* All other interrupts will be signaled to EWL. */
  361. if(dev->async_queue)
  362. kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
  363. else
  364. {
  365. printk(KERN_WARNING
  366. "hx280enc: IRQ received w/o anybody waiting for it!\n");
  367. }
  368. PDEBUG("IRQ handled!\n");
  369. return IRQ_HANDLED;
  370. }
  371. else
  372. {
  373. PDEBUG("IRQ received, but NOT handled!\n");
  374. return IRQ_NONE;
  375. }
  376. }
  377. void ResetAsic(hx280enc_t * dev)
  378. {
  379. int i;
  380. writel(0, dev->hwregs + 0x38);
  381. for(i = 4; i < dev->iosize; i += 4)
  382. {
  383. writel(0, dev->hwregs + i);
  384. }
  385. }
  386. #ifdef HX280ENC_DEBUG
  387. void dump_regs(unsigned long data)
  388. {
  389. hx280enc_t *dev = (hx280enc_t *) data;
  390. int i;
  391. PDEBUG("Reg Dump Start\n");
  392. for(i = 0; i < dev->iosize; i += 4)
  393. {
  394. PDEBUG("\toffset %02X = %08X\n", i, readl(dev->hwregs + i));
  395. }
  396. PDEBUG("Reg Dump End\n");
  397. }
  398. #endif