hx280enc.c 14 KB

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