isp_venc_shake_driver.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. * Copyright (C) 2021 - 2022 Alibaba Group. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. */
  18. #include <linux/kernel.h>
  19. #include <linux/module.h>
  20. #include <linux/init.h>
  21. #include <linux/mm.h>
  22. #include <linux/slab.h>
  23. #include <linux/fs.h>
  24. #include <linux/errno.h>
  25. #include <linux/ioctl.h>
  26. #include <linux/kernel.h>
  27. #include <linux/module.h>
  28. #include <linux/moduleparam.h>
  29. #include <linux/interrupt.h>
  30. #include <linux/sched.h>
  31. #include <linux/semaphore.h>
  32. #include <linux/spinlock.h>
  33. #include <asm/io.h>
  34. #include <linux/cdev.h>
  35. #include <linux/pci.h>
  36. #include <linux/uaccess.h>
  37. #include <linux/ioport.h>
  38. #include <asm/irq.h>
  39. #include <linux/version.h>
  40. #include <linux/vmalloc.h>
  41. #include <linux/timer.h>
  42. #include <linux/delay.h>
  43. #include <linux/platform_device.h>
  44. #include <linux/of.h>
  45. #include "isp_venc_shake_driver.h"
  46. #define IVS_SWREG_AMOUNT 27
  47. typedef struct _theadivs_dev
  48. {
  49. struct cdev cdev;
  50. dev_t devt;
  51. struct class *class;
  52. unsigned long base_addr;
  53. u32 iosize;
  54. volatile u8 *hwregs;
  55. int irq;
  56. int state;
  57. } theadivs_dev;
  58. static int theadivs_major = 0; /* dynamic */
  59. static int theadivs_minor = 0;
  60. static theadivs_dev* theadivs_data = NULL;
  61. static unsigned int device_register_index = 0;
  62. struct class *theadivs_class;
  63. static irqreturn_t theadivs_isr(int irq, void *dev_id);
  64. static void print_registers(void)
  65. {
  66. printk("pic_width = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x00)));
  67. printk("pic_height = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x04)));
  68. printk("encode_width = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x08)));
  69. printk("encode_height = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x0c)));
  70. printk("wid_y = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x10)));
  71. printk("wid_uv = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x14)));
  72. printk("sram_size = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x18)));
  73. printk("encode_n = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x1c)));
  74. printk("stride_y = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x20)));
  75. printk("stride_uv = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x24)));
  76. printk("encode_x = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x2c)));
  77. printk("encode_y = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x30)));
  78. printk("int_state = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x38)));
  79. printk("int_mask = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x40)));
  80. }
  81. static int config_ivs(struct file *filp, struct ivs_parameter *params)
  82. {
  83. iowrite32(params->pic_width, (void*)(theadivs_data->hwregs + 0x00));
  84. iowrite32(params->pic_height, (void*)(theadivs_data->hwregs + 0x04));
  85. iowrite32(params->encode_width, (void*)(theadivs_data->hwregs + 0x08));
  86. iowrite32(params->encode_height, (void*)(theadivs_data->hwregs + 0x0c));
  87. iowrite32(params->wid_y, (void*)(theadivs_data->hwregs + 0x10));
  88. iowrite32(params->wid_uv, (void*)(theadivs_data->hwregs + 0x14));
  89. iowrite32(params->sram_size, (void*)(theadivs_data->hwregs + 0x18));
  90. iowrite32(params->encode_n, (void*)(theadivs_data->hwregs + 0x1c));
  91. iowrite32(params->stride_y, (void*)(theadivs_data->hwregs + 0x20));
  92. iowrite32(params->stride_uv, (void*)(theadivs_data->hwregs + 0x24));
  93. iowrite32(1, (void*)(theadivs_data->hwregs + 0x28)); // CLEAR
  94. iowrite32(params->encode_x, (void*)(theadivs_data->hwregs + 0x2c));
  95. iowrite32(params->encode_y, (void*)(theadivs_data->hwregs + 0x30));
  96. iowrite32(0, (void*)(theadivs_data->hwregs + 0x34)); // START
  97. iowrite32(0, (void*)(theadivs_data->hwregs + 0x3c)); // INT_CLEAN
  98. iowrite32(params->int_mask, (void*)(theadivs_data->hwregs + 0x40));
  99. return 0;
  100. }
  101. static long theadivs_ioctl(struct file *filp,
  102. unsigned int cmd, unsigned long arg)
  103. {
  104. int err = 0;
  105. if (_IOC_TYPE(cmd) != THEAD_IOC_MAGIC)
  106. return -ENOTTY;
  107. else if (_IOC_NR(cmd) > THEAD_IOC_MAXNR)
  108. return -ENOTTY;
  109. if (_IOC_DIR(cmd) & _IOC_READ)
  110. err = !access_ok((void *) arg, _IOC_SIZE(cmd));
  111. else if (_IOC_DIR(cmd) & _IOC_WRITE)
  112. err = !access_ok((void *) arg, _IOC_SIZE(cmd));
  113. if (err)
  114. return -EFAULT;
  115. switch (cmd)
  116. {
  117. case THEAD_IOCH_CONFIG_IVS:
  118. {
  119. struct ivs_parameter params;
  120. printk("%s: THEAD_IOCH_CONFIG_IVS\n", __func__);
  121. err = copy_from_user(&params, (struct ivs_parameter*)arg, sizeof(struct ivs_parameter));
  122. config_ivs(filp, &params);
  123. print_registers();
  124. theadivs_data->state = THEADIVS_READY;
  125. break;
  126. }
  127. case THEAD_IOCH_START_IVS:
  128. {
  129. printk("%s: THEAD_IOCH_START_IVS\n", __func__);
  130. iowrite32(1, theadivs_data->hwregs + 0x34); // START
  131. print_registers();
  132. theadivs_data->state = THEADIVS_RUNNING;
  133. break;
  134. }
  135. case THEAD_IOCH_RESET_IVS:
  136. {
  137. printk("%s: THEAD_IOCH_RESET_IVS\n", __func__);
  138. iowrite32(1, theadivs_data->hwregs + 0x40); // INT_MASK
  139. iowrite32(1, theadivs_data->hwregs + 0x28); // CLEAR
  140. iowrite32(0, theadivs_data->hwregs + 0x40); // INT_MASK
  141. print_registers();
  142. theadivs_data->state = THEADIVS_IDLE;
  143. break;
  144. }
  145. case THEAD_IOCH_GET_STATE:
  146. {
  147. printk("%s: THEAD_IOCH_GET_STATE: %d\n", __func__, theadivs_data->state);
  148. err = copy_to_user((int *)arg, &theadivs_data->state, sizeof(int));
  149. break;
  150. }
  151. default:
  152. {
  153. printk("%s: undefined command: 0x%x\n", __func__, cmd);
  154. }
  155. }
  156. return 0;
  157. }
  158. static int theadivs_open(struct inode *inode, struct file *filp)
  159. {
  160. int result = 0;
  161. //theadivs_dev *dev = theadivs_data;
  162. //filp->private_data = (void *) dev;
  163. return result;
  164. }
  165. static int theadivs_release(struct inode *inode, struct file *filp)
  166. {
  167. //theadivs_dev *dev = (theadivs_dev *) filp->private_data;
  168. return 0;
  169. }
  170. static struct file_operations theadivs_fops = {
  171. .owner= THIS_MODULE,
  172. .open = theadivs_open,
  173. .release = theadivs_release,
  174. .unlocked_ioctl = theadivs_ioctl,
  175. .fasync = NULL,
  176. };
  177. static const struct of_device_id thead_of_match[] = {
  178. { .compatible = "thead,light-ivs", },
  179. { /* sentinel */ },
  180. };
  181. static int theadivs_reserve_IO(void)
  182. {
  183. if(!request_mem_region
  184. (theadivs_data->base_addr, theadivs_data->iosize, "shake"))
  185. {
  186. printk(KERN_INFO "theadivs: failed to reserve HW regs\n");
  187. printk(KERN_INFO "theadivs: base_addr = 0x%08lx, iosize = %d\n",
  188. theadivs_data->base_addr,
  189. theadivs_data->iosize);
  190. return -1;
  191. }
  192. #if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
  193. theadivs_data->hwregs =
  194. (volatile u8 *) ioremap_nocache(theadivs_data->base_addr,
  195. theadivs_data->iosize);
  196. #else
  197. theadivs_data->hwregs =
  198. (volatile u8 *) ioremap(theadivs_data->base_addr,
  199. theadivs_data->iosize);
  200. #endif
  201. if (theadivs_data->hwregs == NULL)
  202. {
  203. printk(KERN_INFO "theadivs: failed to ioremap HW regs\n");
  204. release_mem_region(theadivs_data->base_addr, theadivs_data->iosize);
  205. return -1;
  206. }
  207. printk("theadivs: mapped from 0x%lx to %p with size %d\n",
  208. theadivs_data->base_addr, theadivs_data->hwregs, theadivs_data->iosize);
  209. return 0;
  210. }
  211. static void theadivs_release_IO(void)
  212. {
  213. if(theadivs_data->hwregs)
  214. {
  215. iounmap((void *) theadivs_data->hwregs);
  216. release_mem_region(theadivs_data->base_addr, theadivs_data->iosize);
  217. theadivs_data->hwregs = NULL;
  218. }
  219. }
  220. int __init theadivs_probe(struct platform_device *pdev)
  221. {
  222. int result = -1;
  223. struct resource *mem;
  224. printk("enter %s\n",__func__);
  225. theadivs_data = (theadivs_dev *)vmalloc(sizeof(theadivs_dev));
  226. if (theadivs_data == NULL)
  227. return result;
  228. memset(theadivs_data, 0, sizeof(theadivs_dev));
  229. mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  230. if(mem->start)
  231. theadivs_data->base_addr = mem->start;
  232. theadivs_data->irq = platform_get_irq(pdev, 0);
  233. printk("%s:get irq %d\n", __func__, theadivs_data->irq);
  234. theadivs_data->iosize = IVS_SWREG_AMOUNT * 4;
  235. #if 1
  236. if (device_register_index == 0)
  237. {
  238. if (theadivs_major == 0)
  239. {
  240. result = alloc_chrdev_region(&theadivs_data->devt, 0, 1, "shake");
  241. if (result != 0)
  242. {
  243. printk("%s:alloc_chrdev_region error\n", __func__);
  244. goto err1;
  245. }
  246. theadivs_major = MAJOR(theadivs_data->devt);
  247. theadivs_minor = MINOR(theadivs_data->devt);
  248. }
  249. else
  250. {
  251. theadivs_data->devt = MKDEV(theadivs_major, theadivs_minor);
  252. result = register_chrdev_region(theadivs_data->devt, 1, "shake");
  253. if (result)
  254. {
  255. printk("%s:register_chrdev_region error\n", __func__);
  256. goto err1;
  257. }
  258. }
  259. theadivs_class = class_create(THIS_MODULE, "shake");
  260. if (IS_ERR(theadivs_class))
  261. {
  262. printk("%s[%d]:class_create error!\n", __func__, __LINE__);
  263. goto err;
  264. }
  265. }
  266. theadivs_data->devt = MKDEV(theadivs_major, theadivs_minor + pdev->id);
  267. cdev_init(&theadivs_data->cdev, &theadivs_fops);
  268. result = cdev_add(&theadivs_data->cdev, theadivs_data->devt, 1);
  269. if ( result )
  270. {
  271. printk("%s[%d]:cdev_add error!\n", __func__, __LINE__);
  272. goto err;
  273. }
  274. theadivs_data->class = theadivs_class;
  275. device_create(theadivs_data->class, NULL, theadivs_data->devt,
  276. theadivs_data, "shake");
  277. device_register_index++;
  278. #else
  279. result = register_chrdev(theadivs_major, "shake", &theadivs_fops);
  280. if (result < 0)
  281. {
  282. printk(KERN_INFO "theadivs_driver: unable to get major <%d>\n",
  283. theadivs_major);
  284. goto err1;
  285. }
  286. else if (result != 0) /* this is for dynamic major */
  287. {
  288. theadivs_major = result;
  289. }
  290. #endif
  291. theadivs_reserve_IO();
  292. /* get the IRQ line */
  293. if (theadivs_data->irq!= -1)
  294. {
  295. result = request_irq(theadivs_data->irq, theadivs_isr,
  296. IRQF_SHARED,
  297. "shake", (void *)theadivs_data);
  298. if (result == -EINVAL)
  299. {
  300. printk(KERN_ERR "theadivs_driver: Bad irq number or handler.\n");
  301. theadivs_release_IO();
  302. goto err;
  303. }
  304. else if (result == -EBUSY)
  305. {
  306. printk(KERN_ERR "theadivs_driver: IRQ <%d> busy, change your config.\n",
  307. theadivs_data->irq);
  308. theadivs_release_IO();
  309. goto err;
  310. }
  311. }
  312. else
  313. {
  314. printk(KERN_INFO "theadivs_driver: IRQ not in use!\n");
  315. }
  316. printk(KERN_INFO "theadivs_driver: module inserted. Major <%d>\n", theadivs_major);
  317. return 0;
  318. err:
  319. //unregister_chrdev(theadivs_major, "shake");
  320. unregister_chrdev_region(theadivs_data->devt, 1);
  321. err1:
  322. if (theadivs_data != NULL)
  323. vfree(theadivs_data);
  324. printk(KERN_INFO "theadivs_driver: module not inserted\n");
  325. return result;
  326. }
  327. static int theadivs_remove(struct platform_device *pdev)
  328. {
  329. free_irq(theadivs_data->irq, theadivs_data);
  330. theadivs_release_IO();
  331. //unregister_chrdev(theadivs_major, "shake");
  332. device_register_index--;
  333. cdev_del(&theadivs_data->cdev);
  334. device_destroy(theadivs_data->class, theadivs_data->devt);
  335. unregister_chrdev_region(theadivs_data->devt, 1);
  336. if (device_register_index == 0)
  337. {
  338. class_destroy(theadivs_data->class);
  339. }
  340. if (theadivs_data != NULL)
  341. vfree(theadivs_data);
  342. printk(KERN_INFO "theadivs_driver: module removed\n");
  343. return 0;
  344. }
  345. static struct platform_driver theadivs_driver = {
  346. .probe = theadivs_probe,
  347. .remove = theadivs_remove,
  348. .driver = {
  349. .name = "shake",
  350. .owner = THIS_MODULE,
  351. .of_match_table = of_match_ptr(thead_of_match),
  352. }
  353. };
  354. int __init theadivs_init(void)
  355. {
  356. int ret = 0;
  357. printk("enter %s\n",__func__);
  358. #if 1
  359. ret = platform_driver_register(&theadivs_driver);
  360. if (ret)
  361. {
  362. pr_err("register platform driver failed!\n");
  363. }
  364. #endif
  365. return ret;
  366. }
  367. void __exit theadivs_cleanup(void)
  368. {
  369. printk("enter %s\n",__func__);
  370. platform_driver_unregister(&theadivs_driver);
  371. return;
  372. }
  373. static irqreturn_t theadivs_isr(int irq, void *dev_id)
  374. {
  375. theadivs_dev *dev = (theadivs_dev *) dev_id;
  376. u32 irq_status = 0;
  377. printk( "theadivs_isr: received IRQ!\n");
  378. irq_status = (u32)ioread32((void*)dev->hwregs + 0x38); // INT_STATE
  379. printk( "INT_STATE of is: 0x%x\n", irq_status);
  380. theadivs_data->state = THEADIVS_ERROR;
  381. iowrite32(1, theadivs_data->hwregs + 0x40); // INT_MASK
  382. iowrite32(1, theadivs_data->hwregs + 0x3c); // INT_CLEAN
  383. iowrite32(1, theadivs_data->hwregs + 0x28); // CLEAR
  384. iowrite32(0, theadivs_data->hwregs + 0x40); // INT_MASK
  385. return IRQ_HANDLED;
  386. }
  387. module_init(theadivs_init);
  388. module_exit(theadivs_cleanup);
  389. MODULE_LICENSE("GPL");
  390. MODULE_AUTHOR("T-HEAD");
  391. MODULE_DESCRIPTION("T-HEAD ISP-VENC-SHAKE driver");