isdbt_port_mtv222.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. /*
  2. *
  3. * drivers/media/tdmb/isdbt_port_mtv222.c
  4. *
  5. * isdbt driver
  6. *
  7. * Copyright (C) (2014, Samsung Electronics)
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation version 2.
  12. *
  13. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  14. * kind, whether express or implied; without even the implied warranty
  15. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. */
  19. #include <linux/kernel.h>
  20. #include <linux/errno.h>
  21. #include <linux/device.h>
  22. #include <linux/init.h>
  23. #include <linux/types.h>
  24. #include <linux/fcntl.h>
  25. #include <linux/workqueue.h>
  26. #include <linux/irq.h>
  27. #include <linux/interrupt.h>
  28. #include <linux/io.h>
  29. #include <linux/fs.h>
  30. #include <linux/uaccess.h>
  31. #include <linux/time.h>
  32. #include <linux/timer.h>
  33. #include <linux/vmalloc.h>
  34. #include "isdbt.h"
  35. #include "isdbt_port_mtv222.h"
  36. #ifndef VM_RESERVED /* for kernel 3.10 */
  37. #define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
  38. #endif
  39. extern void mtv222_set_port_if(unsigned long interface);
  40. static bool mtv222_on_air = false;
  41. struct MTV222_CB *mtv222_cb_ptr = NULL;
  42. #ifdef _MTV_KERNEL_FILE_DUMP_ENABLE
  43. struct file *mtv_ts_filp = NULL;
  44. #endif
  45. static void tsb_enqueue(unsigned char *ts_chunk)
  46. {
  47. #ifdef DEBUG_TSP_BUF
  48. int readi, writei, num_euqueued_tsp, num_euqueued_seg;
  49. #endif
  50. struct TSB_CB_INFO *tsb_cb = &mtv222_cb_ptr->tsb_cb;
  51. if (!tsb_cb->tsbd) {
  52. DMBERR("Not memory mapped\n");
  53. return;
  54. }
  55. if (tsb_cb->tsbd->op_enabled) {
  56. /* Check if the specified tspb is the allocated tspb? */
  57. if (ts_chunk == tsb_cb->seg_buf[tsb_cb->enqueue_seg_idx]) {
  58. /* Update the next index of write-tsp. */
  59. tsb_cb->tsbd->write_idx = tsb_cb->avail_write_tspb_idx;
  60. /* Update the next index of segment. */
  61. tsb_cb->enqueue_seg_idx = tsb_cb->avail_seg_idx;
  62. #ifdef DEBUG_TSP_BUF
  63. readi = tsb_cb->tsbd->read_idx;
  64. writei = tsb_cb->tsbd->write_idx;
  65. if (writei > readi)
  66. num_euqueued_tsp = writei - readi;
  67. else if (writei < readi)
  68. num_euqueued_tsp = tsb_cb->num_total_tsp - (readi - writei);
  69. else
  70. num_euqueued_tsp = 0;
  71. mtv222_cb_ptr->max_enqueued_tsp_cnt
  72. = MAX(mtv222_cb_ptr->max_enqueued_tsp_cnt, num_euqueued_tsp);
  73. num_euqueued_seg = num_euqueued_tsp / tsb_cb->num_tsp_per_seg;
  74. mtv222_cb_ptr->max_enqueued_seg_cnt
  75. = MAX(mtv222_cb_ptr->max_enqueued_seg_cnt, num_euqueued_seg);
  76. #endif
  77. } else
  78. DMBERR("Invalid the enqueuing chunk address!\n");
  79. }
  80. }
  81. /* Get a TS buffer */
  82. static U8 *tsb_get(void)
  83. {
  84. int readi;
  85. int nwi; /* Next index of tsp buffer to be write. */
  86. struct TSB_CB_INFO *tsb_cb = &mtv222_cb_ptr->tsb_cb;
  87. unsigned char *tspb = NULL;
  88. int num_tsp_per_seg = tsb_cb->num_tsp_per_seg;
  89. #ifdef DEBUG_TSP_BUF
  90. int num_used_segment; /* Should NOT zero. */
  91. int write_seg_idx, read_seg_idx;
  92. #endif
  93. if (!tsb_cb->tsbd) {
  94. DMBERR("Not memory mapped\n");
  95. return NULL;
  96. }
  97. if (tsb_cb->tsbd->op_enabled) {
  98. readi = tsb_cb->tsbd->read_idx;
  99. /* Get the next avaliable index of segment to be write in the next time. */
  100. nwi = tsb_cb->avail_write_tspb_idx + num_tsp_per_seg;
  101. if (nwi >= tsb_cb->num_total_tsp)
  102. nwi = 0;
  103. if ((readi < nwi) || (readi >= (nwi + num_tsp_per_seg))) {
  104. tspb = tsb_cb->seg_buf[tsb_cb->avail_seg_idx];
  105. /* Update the writting index of tsp buffer. */
  106. tsb_cb->avail_write_tspb_idx = nwi;
  107. /* Update the avaliable index of segment to be write in the next time. */
  108. if (++tsb_cb->avail_seg_idx >= tsb_cb->num_total_seg)
  109. tsb_cb->avail_seg_idx = 0;
  110. #ifdef DEBUG_TSP_BUF
  111. write_seg_idx = tsb_cb->avail_seg_idx;
  112. read_seg_idx = readi / num_tsp_per_seg;
  113. if (write_seg_idx > read_seg_idx)
  114. num_used_segment = write_seg_idx - read_seg_idx;
  115. else
  116. num_used_segment
  117. = tsb_cb->num_total_seg - (read_seg_idx - write_seg_idx);
  118. DMBMSG("wseg_idx(%d), rseg_idx(%d), num_used_segment(%d)\n",
  119. write_seg_idx, read_seg_idx, num_used_segment);
  120. mtv222_cb_ptr->max_alloc_seg_cnt
  121. = MAX(mtv222_cb_ptr->max_alloc_seg_cnt, num_used_segment);
  122. #endif
  123. //DMBMSG("@@ readi(%d), next_writei(%d), avail_seg_idx(%d), tspb(0x%08lX)\n",
  124. // readi, nwi, tsb_cb->avail_seg_idx, (unsigned long)tspb);
  125. } else
  126. DMBERR("Full tsp buffer.\n");
  127. }
  128. return tspb;
  129. }
  130. static inline void tsb_free_mapping_area(void)
  131. {
  132. int i;
  133. unsigned int order;
  134. struct TSB_CB_INFO *tsb_cb = &mtv222_cb_ptr->tsb_cb;
  135. order = get_order(tsb_cb->seg_size);
  136. for (i = 0; i < tsb_cb->num_total_seg; i++) {
  137. if (tsb_cb->seg_buf[i]) {
  138. //DMBMSG("SEG[%d]: seg_buf(0x%lX)\n", i, (unsigned long)tsb_cb->seg_buf[i]);
  139. free_pages((unsigned long)tsb_cb->seg_buf[i], order);
  140. tsb_cb->seg_buf[i] = NULL;
  141. }
  142. }
  143. tsb_cb->seg_bufs_allocated = false;
  144. tsb_cb->seg_size = 0;
  145. tsb_cb->num_total_seg = 0;
  146. if (tsb_cb->tsbd) {
  147. order = get_order(tsb_cb->desc_size);
  148. free_pages((unsigned long)tsb_cb->tsbd, order);
  149. tsb_cb->tsbd = NULL;
  150. tsb_cb->desc_size = 0;
  151. }
  152. }
  153. static inline int tsb_alloc_mapping_area(unsigned int desc_size,
  154. unsigned int seg_size, int num_seg)
  155. {
  156. int i, ret;
  157. unsigned int order;
  158. struct TSB_CB_INFO *tsb_cb = &mtv222_cb_ptr->tsb_cb;
  159. /* Allocate the TSB descriptor. */
  160. order = get_order(desc_size);
  161. tsb_cb->tsbd
  162. = (struct TSB_DESC_INFO *)__get_dma_pages(GFP_KERNEL, order);
  163. if (!tsb_cb->tsbd) {
  164. DMBMSG("DESC allocation error\n");
  165. return -ENOMEM;
  166. }
  167. /* Allocate the TSB segments. */
  168. order = get_order(seg_size);
  169. DMBMSG("SEG order(%u)\n", order);
  170. if (order > MAX_ORDER) {
  171. DMBMSG("Invalid page order value of segment (%u)\n", order);
  172. ret = -ENOMEM;
  173. goto free_tsb;
  174. }
  175. for (i = 0; i < num_seg; i++) {
  176. tsb_cb->seg_buf[i] = (U8 *)__get_dma_pages(GFP_KERNEL, order);
  177. if (!tsb_cb->seg_buf[i]) {
  178. DMBMSG("SEG[%u] allocation error\n", i);
  179. ret = -ENOMEM;
  180. goto free_tsb;
  181. }
  182. }
  183. tsb_cb->seg_bufs_allocated = true;
  184. DMBMSG("Success\n");
  185. return 0;
  186. free_tsb:
  187. tsb_free_mapping_area();
  188. return ret;
  189. }
  190. static void mtv222_mmap_close(struct vm_area_struct *vma)
  191. {
  192. DMBMSG("Entered. mmap_completed(%d)\n", mtv222_cb_ptr->tsb_cb.mmap_completed);
  193. mtv222_cb_ptr->tsb_cb.mmap_completed = false;
  194. DMBMSG("Leaved...\n");
  195. }
  196. static const struct vm_operations_struct mtv222_mmap_ops = {
  197. .close = mtv222_mmap_close,
  198. };
  199. static int mtv222_mmap(struct file *filp, struct vm_area_struct *vma)
  200. {
  201. int ret, num_total_seg;
  202. unsigned int i, mmap_size, desc_size, seg_size;
  203. unsigned long pfn;
  204. unsigned long start = vma->vm_start;
  205. struct TSB_CB_INFO *tsb_cb = &mtv222_cb_ptr->tsb_cb;
  206. vma->vm_flags |= VM_RESERVED;
  207. vma->vm_ops = &mtv222_mmap_ops;
  208. mmap_size = vma->vm_end - vma->vm_start;
  209. #if 0
  210. DMBMSG("mmap_size(0x%X), vm_start(0x%lX), vm_page_prot(0x%lX)\n",
  211. mmap_size, vma->vm_start, vma->vm_page_prot);
  212. #endif
  213. if (mmap_size & (~PAGE_MASK)) {
  214. DMBERR("Must align with PAGE size\n");
  215. return -EINVAL;
  216. }
  217. if (tsb_cb->mmap_completed == true) {
  218. DMBERR("Already mapped!\n");
  219. return 0;
  220. }
  221. seg_size = vma->vm_pgoff << PAGE_SHIFT;
  222. num_total_seg = (mmap_size - PAGE_SIZE) / seg_size;
  223. desc_size = mmap_size - (num_total_seg * seg_size);
  224. /* Save */
  225. tsb_cb->desc_size = desc_size;
  226. tsb_cb->seg_size = seg_size;
  227. tsb_cb->num_total_seg = num_total_seg;
  228. #if 1
  229. DMBMSG("mmap_size(%u), seg_size(%u) #seg(%d), desc_size(%u)\n",
  230. mmap_size, seg_size, num_total_seg, desc_size);
  231. #endif
  232. if (num_total_seg > MAX_NUM_TSB_SEG) {
  233. DMBERR("Too large request #seg! kernel(%u), req(%d)\n",
  234. MAX_NUM_TSB_SEG, num_total_seg);
  235. return -ENOMEM;
  236. }
  237. if (desc_size > MAX_TSB_DESC_SIZE) {
  238. DMBERR("Too large request desc size! kernel(%u), req(%u)\n",
  239. MAX_TSB_DESC_SIZE, desc_size);
  240. return -ENOMEM;
  241. }
  242. if (seg_size > MAX_TSB_SEG_SIZE) {
  243. DMBERR("Too large request seg size! kernel(%u), req(%u)\n",
  244. MAX_TSB_SEG_SIZE, seg_size);
  245. return -ENOMEM;
  246. }
  247. if (!tsb_cb->tsbd) {
  248. DMBERR("TSB DESC was NOT allocated!\n");
  249. return -ENOMEM;
  250. }
  251. if (tsb_cb->seg_bufs_allocated == false) {
  252. DMBERR("TSB SEG are NOT allocated!\n");
  253. return -ENOMEM;
  254. }
  255. /* Map the shared informations. */
  256. pfn = virt_to_phys(tsb_cb->tsbd) >> PAGE_SHIFT;
  257. if (remap_pfn_range(vma, vma->vm_start, pfn, desc_size, vma->vm_page_prot)) {
  258. DMBERR("HDR remap_pfn_range() error!\n");
  259. ret = -EAGAIN;
  260. goto out;
  261. }
  262. /* Init descriptor except the addres of segments */
  263. tsb_cb->tsbd->op_enabled = 0;
  264. tsb_cb->tsbd->read_idx = 0;
  265. tsb_cb->tsbd->write_idx = 0;
  266. #if 0
  267. DMBMSG("tsbd(0x%lX), pfn(0x%lX), start(0x%lX)\n",
  268. (unsigned long)tsb_cb->tsbd, pfn, start);
  269. #endif
  270. start += desc_size; /* Avdance VMA. */
  271. /* Allocate and map the TSP buffer segments. */
  272. for (i = 0; i < num_total_seg; i++) {
  273. pfn = virt_to_phys(tsb_cb->seg_buf[i]) >> PAGE_SHIFT;
  274. #if 0
  275. DMBMSG("SEG[%d]: seg_buf(0x%lX) pfn(0x%lX) start(0x%lX)\n",
  276. i, (unsigned long)tsb_cb->seg_buf[i], pfn, start);
  277. #endif
  278. if (remap_pfn_range(vma, start, pfn, seg_size, vma->vm_page_prot)) {
  279. DMBERR("SEG[%u] remap_pfn_range() error!\n", i);
  280. ret = -EAGAIN;
  281. goto out;
  282. }
  283. tsb_cb->tsbd->seg_base[i] = start;
  284. start += seg_size;
  285. }
  286. tsb_cb->mmap_completed = true;
  287. return 0;
  288. out:
  289. return ret;
  290. }
  291. static void mtv222_power_off(void)
  292. {
  293. DMBMSG("mtv222_power_off\n");
  294. if (mtv222_cb_ptr->is_power_on) {
  295. mtv222_on_air = false;
  296. // isdbt_control_irq(false);
  297. isdbt_control_gpio(false);
  298. mtv222_cb_ptr->is_power_on = false;
  299. mtv222_cb_ptr->tsout_enabled = false;
  300. RTV_GUARD_DEINIT;
  301. }
  302. }
  303. static INLINE int __mtv222_power_on(unsigned long arg)
  304. {
  305. int ret;
  306. IOCTL_ISDBT_POWER_ON_INFO __user *argp
  307. = (IOCTL_ISDBT_POWER_ON_INFO __user *)arg;
  308. #if defined(RTV_IF_SPI) || defined(RTV_IF_CSI656_RAW_8BIT_ENABLE)
  309. if (get_user(mtv222_cb_ptr->intr_size, &argp->spi_intr_size[0]))
  310. return -EFAULT;
  311. DMBMSG("intr_size: %u\n", mtv222_cb_ptr->intr_size);
  312. mtv222_cb_ptr->cfged_tsp_chunk_size = 0;
  313. #endif
  314. if (get_user(mtv222_cb_ptr->country_band_type, &argp->country_band_type))
  315. return -EFAULT;
  316. mtv222_cb_ptr->tsout_enabled = false;
  317. mtv222_cb_ptr->cfged_svc = RTV_SERVICE_INVALID;
  318. ret = rtvISDBT_Initialize(mtv222_cb_ptr->country_band_type,
  319. mtv222_cb_ptr->intr_size);
  320. if (ret != RTV_SUCCESS) {
  321. DMBERR("Tuner initialization failed: %d\n", ret);
  322. if (put_user(ret, &argp->tuner_err_code))
  323. return -EFAULT;
  324. return -EIO; /* error occurred during the open() */
  325. }
  326. return ret;
  327. }
  328. static int mtv222_power_on(unsigned long arg)
  329. {
  330. int ret;
  331. IOCTL_ISDBT_POWER_ON_INFO __user *argp
  332. = (IOCTL_ISDBT_POWER_ON_INFO __user *)arg;
  333. DMBMSG("mtv222_power_on\n");
  334. if (mtv222_cb_ptr->is_power_on) {
  335. return 0;
  336. } else {
  337. isdbt_control_gpio(true);
  338. RTV_GUARD_INIT;
  339. mtv222_set_port_if((unsigned long)isdbt_get_if_handle());
  340. ret = __mtv222_power_on(arg);
  341. if (ret) {
  342. DMBERR("Tuner initialization failed: %d\n", ret);
  343. isdbt_control_gpio(false);
  344. if (put_user(ret, &argp->tuner_err_code))
  345. return -EFAULT;
  346. return ret;
  347. } else {
  348. // isdbt_control_irq(true);
  349. mtv222_cb_ptr->is_power_on = true;
  350. return 0;
  351. }
  352. }
  353. }
  354. #if defined(RTV_IF_SPI) || defined(RTV_IF_SPI_TSIFx)
  355. static unsigned long diff_jiffies_1st, diff_jiffies0, hours_cnt;
  356. #endif
  357. #define ISDBT_VALID_SVC_MASK (1<<RTV_SERVICE_UHF_ISDBT_1seg)
  358. /*============================================================================
  359. * Test IO control commands(0 ~ 10)
  360. *==========================================================================*/
  361. static int test_register_io(unsigned long arg, unsigned int cmd)
  362. {
  363. int ret = 0;
  364. unsigned int page, addr, write_data, read_cnt, i;
  365. U8 value;
  366. #if defined(RTV_IF_SPI) || defined(RTV_IF_SPI_TSIFx)
  367. unsigned long diff_jiffies1;
  368. unsigned int elapsed_ms;
  369. unsigned long param1;
  370. #endif
  371. U8 *reg_read_buf;
  372. U8 *src_ptr, *dst_ptr;
  373. IOCTL_REG_ACCESS_INFO __user *argp
  374. = (IOCTL_REG_ACCESS_INFO __user *)arg;
  375. if (mtv222_cb_ptr->is_power_on == FALSE) {
  376. DMBMSG("[mtv] Power Down state!Must Power ON\n");
  377. return -EFAULT;
  378. }
  379. if (get_user(page, &argp->page))
  380. return -EFAULT;
  381. if (get_user(addr, &argp->addr))
  382. return -EFAULT;
  383. RTV_GUARD_LOCK;
  384. switch (cmd) {
  385. case IOCTL_TEST_REG_SINGLE_READ:
  386. RTV_REG_MAP_SEL(page);
  387. value = RTV_REG_GET(addr);
  388. if (put_user(value, &argp->read_data[0])) {
  389. ret = -EFAULT;
  390. goto regio_exit;
  391. }
  392. break;
  393. case IOCTL_TEST_REG_BURST_READ:
  394. if (get_user(read_cnt, &argp->read_cnt)) {
  395. ret = -EFAULT;
  396. goto regio_exit;
  397. }
  398. reg_read_buf = kmalloc(MAX_NUM_MTV_REG_READ_BUF, GFP_KERNEL);
  399. if (reg_read_buf == NULL) {
  400. DMBERR("Register buffer allocation error\n");
  401. ret = -ENOMEM;
  402. goto regio_exit;
  403. }
  404. RTV_REG_MAP_SEL(page);
  405. RTV_REG_BURST_GET(addr, reg_read_buf, read_cnt);
  406. src_ptr = &reg_read_buf[0];
  407. dst_ptr = argp->read_data;
  408. for (i = 0; i< read_cnt; i++, src_ptr++, dst_ptr++) {
  409. if(put_user(*src_ptr, dst_ptr)) {
  410. ret = -EFAULT;
  411. break;
  412. }
  413. }
  414. kfree(reg_read_buf);
  415. break;
  416. case IOCTL_TEST_REG_WRITE:
  417. if (get_user(write_data, &argp->write_data)) {
  418. ret = -EFAULT;
  419. goto regio_exit;
  420. }
  421. RTV_REG_MAP_SEL(page);
  422. RTV_REG_SET(addr, write_data);
  423. break;
  424. case IOCTL_TEST_REG_SPI_MEM_READ:
  425. #if defined(RTV_IF_SPI)
  426. if (get_user(write_data, &argp->write_data)) {
  427. ret = -EFAULT;
  428. goto regio_exit;
  429. }
  430. if (get_user(read_cnt, &argp->read_cnt)) {
  431. ret = -EFAULT;
  432. goto regio_exit;
  433. }
  434. if (get_user(param1, &argp->param1)) {
  435. ret = -EFAULT;
  436. goto regio_exit;
  437. }
  438. reg_read_buf = kmalloc(MAX_NUM_MTV_REG_READ_BUF, GFP_KERNEL);
  439. if (reg_read_buf == NULL) {
  440. DMBERR("Register buffer allocation error\n");
  441. ret = -ENOMEM;
  442. goto regio_exit;
  443. }
  444. if (param1 == 0) {
  445. diff_jiffies_1st = diff_jiffies0 = get_jiffies_64();
  446. hours_cnt = 0;
  447. DMBMSG("START [AGING SPI Memory Test with Single IO]\n");
  448. }
  449. RTV_REG_MAP_SEL(page);
  450. RTV_REG_SET(addr, write_data);
  451. RTV_REG_MAP_SEL(SPI_MEM_PAGE);
  452. RTV_REG_BURST_GET(0x10, reg_read_buf, read_cnt);
  453. RTV_REG_MAP_SEL(page);
  454. value = RTV_REG_GET(addr);
  455. diff_jiffies1 = get_jiffies_64();
  456. elapsed_ms = jiffies_to_msecs(diff_jiffies1-diff_jiffies0);
  457. if (elapsed_ms >= (1000 * 60 * 60)) {
  458. diff_jiffies0 = get_jiffies_64(); /* Re-start */
  459. hours_cnt++;
  460. DMBMSG("\t %lu hours elaspesed...\n", hours_cnt);
  461. }
  462. if (write_data != value) {
  463. unsigned int min, sec;
  464. elapsed_ms = jiffies_to_msecs(diff_jiffies1-diff_jiffies_1st);
  465. sec = elapsed_ms / 1000;
  466. min = sec / 60;
  467. DMBMSG("END [AGING SPI Memory Test with Single IO]\n");
  468. DMBMSG("Total minutes: %u\n", min);
  469. }
  470. if (put_user(value, &argp->read_data[0]))
  471. ret = -EFAULT;
  472. kfree(reg_read_buf);
  473. #else
  474. DMBERR("Not SPI interface\n");
  475. #endif
  476. break;
  477. case IOCTL_TEST_REG_ONLY_SPI_MEM_READ:
  478. #if defined(RTV_IF_SPI)
  479. if (get_user(read_cnt, &argp->read_cnt)) {
  480. ret = -EFAULT;
  481. goto regio_exit;
  482. }
  483. if (get_user(write_data, &argp->write_data)) {
  484. ret = -EFAULT;
  485. goto regio_exit;
  486. }
  487. reg_read_buf = kmalloc(MAX_NUM_MTV_REG_READ_BUF, GFP_KERNEL);
  488. if (reg_read_buf == NULL) {
  489. DMBERR("Register buffer allocation error\n");
  490. ret = -ENOMEM;
  491. goto regio_exit;
  492. }
  493. if (write_data == 0) /* only one-time page selection */
  494. RTV_REG_MAP_SEL(page);
  495. RTV_REG_BURST_GET(addr, reg_read_buf, read_cnt);
  496. src_ptr = reg_read_buf;
  497. dst_ptr = argp->read_data;
  498. for (i = 0; i< read_cnt; i++, src_ptr++, dst_ptr++) {
  499. if(put_user(*src_ptr, dst_ptr)) {
  500. ret = -EFAULT;
  501. break;
  502. }
  503. }
  504. kfree(reg_read_buf);
  505. #else
  506. DMBERR("Not SPI interface\n");
  507. #endif
  508. break;
  509. default:
  510. break;
  511. }
  512. regio_exit:
  513. RTV_GUARD_FREE;
  514. return 0;
  515. }
  516. static int test_gpio(unsigned long arg, unsigned int cmd)
  517. {
  518. unsigned int pin, value;
  519. IOCTL_GPIO_ACCESS_INFO __user *argp = (IOCTL_GPIO_ACCESS_INFO __user *)arg;
  520. if (get_user(pin, &argp->pin))
  521. return -EFAULT;
  522. switch (cmd) {
  523. case IOCTL_TEST_GPIO_SET:
  524. if(get_user(value, &argp->value))
  525. return -EFAULT;
  526. gpio_set_value(pin, value);
  527. break;
  528. case IOCTL_TEST_GPIO_GET:
  529. value = gpio_get_value(pin);
  530. if(put_user(value, &argp->value))
  531. return -EFAULT;
  532. }
  533. return 0;
  534. }
  535. static void test_power_on_off(unsigned int cmd)
  536. {
  537. switch (cmd) {
  538. case IOCTL_TEST_MTV_POWER_ON:
  539. DMBMSG("IOCTL_TEST_MTV_POWER_ON\n");
  540. if (mtv222_cb_ptr->is_power_on == FALSE) {
  541. isdbt_control_gpio(true);
  542. rtvISDBT_Initialize(RTV_COUNTRY_BAND_BRAZIL, 16*188);
  543. mtv222_cb_ptr->is_power_on = TRUE;
  544. }
  545. break;
  546. case IOCTL_TEST_MTV_POWER_OFF:
  547. if(mtv222_cb_ptr->is_power_on == TRUE) {
  548. isdbt_control_gpio(false);
  549. mtv222_cb_ptr->is_power_on = FALSE;
  550. }
  551. break;
  552. }
  553. }
  554. /*==============================================================================
  555. * TDMB IO control commands(30 ~ 49)
  556. *============================================================================*/
  557. static INLINE int mtv222_get_signal_qual_info(unsigned long arg)
  558. {
  559. IOCTL_ISDBT_SIGNAL_QUAL_INFO sig;
  560. void __user *argp = (void __user *)arg;
  561. sig.lock_mask = rtvISDBT_GetLockStatus();
  562. sig.rssi = rtvISDBT_GetRSSI();
  563. sig.ber_layer_A = rtvISDBT_GetBER();
  564. sig.ber_layer_B = 0;
  565. sig.per_layer_A = rtvISDBT_GetPER();
  566. sig.per_layer_B = 0;
  567. sig.cnr_layer_A = rtvISDBT_GetCNR();
  568. sig.ant_level_layer_A = rtvISDBT_GetAntennaLevel(sig.cnr_layer_A);
  569. sig.cnr_layer_B = 0;
  570. sig.ant_level_layer_B = 0;
  571. if (copy_to_user(argp, &sig, sizeof(IOCTL_ISDBT_SIGNAL_QUAL_INFO)))
  572. return -EFAULT;
  573. SHOW_ISDBT_DEBUG_STAT;
  574. return 0;
  575. }
  576. static INLINE int mtv222_get_cnr(unsigned long arg)
  577. {
  578. int cnr = (int)rtvISDBT_GetCNR();
  579. if (put_user(cnr, (int *)arg))
  580. return -EFAULT;
  581. SHOW_ISDBT_DEBUG_STAT;
  582. return 0;
  583. }
  584. static INLINE int mtv222_get_rssi(unsigned long arg)
  585. {
  586. int rssi = rtvISDBT_GetRSSI();
  587. if (put_user(rssi, (int *)arg))
  588. return -EFAULT;
  589. SHOW_ISDBT_DEBUG_STAT;
  590. return 0;
  591. }
  592. static INLINE int mtv222_get_ber_per_info(unsigned long arg)
  593. {
  594. IOCTL_ISDBT_BER_PER_INFO info;
  595. void __user *argp = (void __user *)arg;
  596. info.ber_layer_A = rtvISDBT_GetBER();
  597. info.ber_layer_B = 0;
  598. info.per_layer_A = rtvISDBT_GetPER();
  599. info.per_layer_B = 0;
  600. if (copy_to_user(argp, &info, sizeof(IOCTL_ISDBT_BER_PER_INFO)))
  601. return -EFAULT;
  602. SHOW_ISDBT_DEBUG_STAT;
  603. return 0;
  604. }
  605. static INLINE void mtv222_disable_standby_mode(unsigned long arg)
  606. {
  607. rtvISDBT_StandbyMode(0);
  608. }
  609. static INLINE void mtv222_enable_standby_mode(unsigned long arg)
  610. {
  611. rtvISDBT_StandbyMode(1);
  612. }
  613. static INLINE int mtv222_get_lock_status(unsigned long arg)
  614. {
  615. unsigned int lock_mask = rtvISDBT_GetLockStatus();
  616. if (put_user(lock_mask, (unsigned int *)arg))
  617. return -EFAULT;
  618. return 0;
  619. }
  620. static INLINE int mtv222_get_signal_info(unsigned long arg)
  621. {
  622. IOCTL_ISDBT_SIGNAL_INFO sig;
  623. void __user *argp = (void __user *)arg;
  624. sig.lock_mask = rtvISDBT_GetLockStatus();
  625. sig.ber = rtvISDBT_GetBER();
  626. sig.cnr = rtvISDBT_GetCNR();
  627. sig.per = rtvISDBT_GetPER();
  628. sig.rssi = rtvISDBT_GetRSSI();
  629. sig.ant_level = rtvISDBT_GetAntennaLevel(sig.cnr);
  630. if (copy_to_user(argp, &sig, sizeof(IOCTL_ISDBT_SIGNAL_INFO)))
  631. return -EFAULT;
  632. SHOW_ISDBT_DEBUG_STAT;
  633. return 0;
  634. }
  635. static INLINE int mtv222_set_channel(unsigned long arg)
  636. {
  637. int ch_no;
  638. int ret = 0;
  639. unsigned int freq_khz, subch_id, intr_size;
  640. enum E_RTV_SERVICE_TYPE svc_type;
  641. enum E_RTV_BANDWIDTH_TYPE bw;
  642. IOCTL_ISDBT_SET_CH_INFO __user *argp
  643. = (IOCTL_ISDBT_SET_CH_INFO __user *)arg;
  644. if (get_user(freq_khz, &argp->freq_khz))
  645. return -EFAULT;
  646. if (get_user(subch_id, &argp->subch_id))
  647. return -EFAULT;
  648. if (get_user(svc_type, &argp->svc_type))
  649. return -EFAULT;
  650. if (get_user(bw, &argp->bandwidth))
  651. return -EFAULT;
  652. if (!((1<<svc_type) & ISDBT_VALID_SVC_MASK)) {
  653. DMBERR("Invaild service type: %d\n", svc_type);
  654. mtv222_cb_ptr->cfged_svc = RTV_SERVICE_INVALID;
  655. return -EINVAL;
  656. }
  657. DMBMSG("freq_khz(%u), subch_id(%u), svc_type(%u), bandwidth(%d)\n",
  658. freq_khz, subch_id, svc_type, bw);
  659. #if defined(RTV_IF_SPI)
  660. intr_size = mtv222_cb_ptr->intr_size;
  661. #else
  662. intr_size = 0;
  663. #endif
  664. mtv222_cb_ptr->cfged_svc = svc_type;
  665. mtv222_cb_ptr->freq_khz = freq_khz;
  666. ch_no = RTV_ISDBT_FREQ2CHNUM(mtv222_cb_ptr->country_band_type, freq_khz);
  667. ret = rtvISDBT_SetFrequency(ch_no);
  668. if (ret != RTV_SUCCESS) {
  669. DMBERR("failed: %d\n", ret);
  670. if (put_user(ret, &argp->tuner_err_code))
  671. return -EFAULT;
  672. return -EIO;
  673. }
  674. DMBMSG("Leave...\n");
  675. return 0;
  676. }
  677. static INLINE int mtv222_scan_channel(unsigned long arg)
  678. {
  679. int ch_no;
  680. int ret;
  681. unsigned int freq_khz, subch_id, intr_size;
  682. enum E_RTV_SERVICE_TYPE svc_type;
  683. enum E_RTV_BANDWIDTH_TYPE bw;
  684. IOCTL_ISDBT_SCAN_INFO __user *argp
  685. = (IOCTL_ISDBT_SCAN_INFO __user *)arg;
  686. if (get_user(freq_khz, &argp->freq_khz))
  687. return -EFAULT;
  688. if (get_user(subch_id, &argp->subch_id))
  689. return -EFAULT;
  690. if (get_user(svc_type, &argp->svc_type))
  691. return -EFAULT;
  692. if (get_user(bw, &argp->bandwidth))
  693. return -EFAULT;
  694. if (!((1<<svc_type) & ISDBT_VALID_SVC_MASK)) {
  695. DMBERR("Invaild service type: %d\n", svc_type);
  696. mtv222_cb_ptr->cfged_svc = RTV_SERVICE_INVALID;
  697. return -EINVAL;
  698. }
  699. #if defined(RTV_IF_SPI)
  700. intr_size = mtv222_cb_ptr->intr_size;
  701. #else
  702. intr_size = 0;
  703. #endif
  704. mtv222_cb_ptr->cfged_svc = svc_type;
  705. mtv222_cb_ptr->freq_khz = freq_khz;
  706. ch_no = RTV_ISDBT_FREQ2CHNUM(mtv222_cb_ptr->country_band_type, freq_khz);
  707. ret = rtvISDBT_ScanFrequency(ch_no);
  708. if (ret == RTV_SUCCESS)
  709. return 0;
  710. else {
  711. if(ret != RTV_CHANNEL_NOT_DETECTED)
  712. DMBERR("Device error: %d\n", ret);
  713. /* Copy the tuner error-code to application */
  714. if (put_user(ret, &argp->tuner_err_code))
  715. return -EFAULT;
  716. return -EINVAL;
  717. }
  718. }
  719. static INLINE int mtv222_disable_ts_out(void)
  720. {
  721. int ret = 0;
  722. DMBMSG("Enter\n");
  723. if (!mtv222_cb_ptr->tsout_enabled) {
  724. DMBMSG("Already TS out Disabled\n");
  725. return 0;
  726. }
  727. mtv222_cb_ptr->tsout_enabled = false;
  728. rtvISDBT_DisableStreamOut();
  729. #ifdef _MTV_KERNEL_FILE_DUMP_ENABLE
  730. mtv_ts_dump_kfile_close();
  731. #endif
  732. DMBMSG("Leave\n");
  733. return ret;
  734. }
  735. static INLINE int mtv222_enable_ts_out(void)
  736. {
  737. int ret = 0;
  738. #if defined(RTV_IF_SPI) || defined(RTV_IF_CSI656_RAW_8BIT_ENABLE)
  739. struct TSB_CB_INFO *tsb_cb = &mtv222_cb_ptr->tsb_cb;
  740. #endif
  741. //DMBMSG("ENTER\n");
  742. if (mtv222_cb_ptr->tsout_enabled) {
  743. DMBMSG("Already TS out Enabled\n");
  744. return 0;
  745. }
  746. RESET_DEBUG_INTR_STAT;
  747. RESET_DEBUG_TSPB_STAT;
  748. if (!((1<<mtv222_cb_ptr->cfged_svc) & ISDBT_VALID_SVC_MASK)) {
  749. DMBERR("Invaild configured service type: %d\n",
  750. mtv222_cb_ptr->cfged_svc);
  751. mtv222_cb_ptr->cfged_svc = RTV_SERVICE_INVALID;
  752. return -EINVAL;
  753. }
  754. #if defined(RTV_IF_SPI) || defined(RTV_IF_CSI656_RAW_8BIT_ENABLE)
  755. /* Setup the tsb_cb stuff to process interrupt. */
  756. tsb_cb->avail_seg_idx = 0;
  757. tsb_cb->avail_write_tspb_idx = 0;
  758. tsb_cb->enqueue_seg_idx = 0;
  759. if (mtv222_cb_ptr->intr_size
  760. != mtv222_cb_ptr->cfged_tsp_chunk_size) {
  761. mtv222_cb_ptr->cfged_tsp_chunk_size
  762. = mtv222_cb_ptr->intr_size;
  763. tsb_cb->num_tsp_per_seg
  764. = mtv222_cb_ptr->intr_size
  765. / RTV_TSP_XFER_SIZE;
  766. tsb_cb->num_total_tsp
  767. = tsb_cb->num_tsp_per_seg * tsb_cb->num_total_seg;
  768. }
  769. DMBMSG("svc_type(%d), #tsp_per_seg(%u), #seg(%u), #total_tsp(%u)\n",
  770. mtv222_cb_ptr->cfged_svc, tsb_cb->num_tsp_per_seg,
  771. tsb_cb->num_total_seg, tsb_cb->num_total_tsp);
  772. #endif
  773. #ifdef _MTV_KERNEL_FILE_DUMP_ENABLE
  774. ret = mtv_ts_dump_kfile_open(mtv222_cb_ptr->freq_khz);
  775. if (ret != 0)
  776. return ret;
  777. #endif
  778. mtv222_cb_ptr->tsout_enabled = true;
  779. rtvISDBT_EnableStreamOut();
  780. //DMBMSG("END\n");
  781. return ret;
  782. }
  783. static long mtv222_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  784. {
  785. int ret = 0;
  786. mutex_lock(&mtv222_cb_ptr->ioctl_lock);
  787. switch (cmd) {
  788. case IOCTL_ISDBT_POWER_ON:
  789. ret = isdbt_power_on(arg);
  790. //ret = mtv222_power_on(arg);
  791. if (ret)
  792. isdbt_power_off();
  793. break;
  794. case IOCTL_ISDBT_POWER_OFF:
  795. mtv222_disable_ts_out();
  796. isdbt_power_off();
  797. break;
  798. case IOCTL_ISDBT_SCAN_CHANNEL:
  799. ret = mtv222_scan_channel(arg);
  800. break;
  801. case IOCTL_ISDBT_SET_CHANNEL:
  802. ret = mtv222_set_channel(arg);
  803. break;
  804. case IOCTL_ISDBT_START_TS:
  805. ret = mtv222_enable_ts_out();
  806. break;
  807. case IOCTL_ISDBT_STOP_TS:
  808. mtv222_disable_ts_out();
  809. break;
  810. case IOCTL_ISDBT_GET_LOCK_STATUS:
  811. ret = mtv222_get_lock_status(arg);
  812. break;
  813. case IOCTL_ISDBT_GET_SIGNAL_INFO:
  814. ret = mtv222_get_signal_info(arg);
  815. break;
  816. case IOCTL_ISDBT_SUSPEND:
  817. mtv222_enable_standby_mode(arg);
  818. break;
  819. case IOCTL_ISDBT_RESUME:
  820. mtv222_disable_standby_mode(arg);
  821. break;
  822. case IOCTL_ISDBT_GET_BER_PER_INFO:
  823. ret = mtv222_get_ber_per_info(arg);
  824. break;
  825. case IOCTL_ISDBT_GET_RSSI:
  826. ret = mtv222_get_rssi(arg);
  827. break;
  828. case IOCTL_ISDBT_GET_CNR:
  829. ret = mtv222_get_cnr(arg);
  830. break;
  831. case IOCTL_ISDBT_GET_SIGNAL_QUAL_INFO:
  832. ret = mtv222_get_signal_qual_info(arg);
  833. break;
  834. /* Test IO command */
  835. case IOCTL_TEST_GPIO_SET:
  836. case IOCTL_TEST_GPIO_GET:
  837. ret = test_gpio(arg, cmd);
  838. break;
  839. case IOCTL_TEST_MTV_POWER_ON:
  840. case IOCTL_TEST_MTV_POWER_OFF:
  841. test_power_on_off(cmd);
  842. break;
  843. case IOCTL_TEST_REG_SINGLE_READ:
  844. case IOCTL_TEST_REG_BURST_READ:
  845. case IOCTL_TEST_REG_WRITE:
  846. case IOCTL_TEST_REG_SPI_MEM_READ:
  847. case IOCTL_TEST_REG_ONLY_SPI_MEM_READ:
  848. ret = test_register_io(arg, cmd);
  849. break;
  850. default:
  851. DMBERR("Invalid ioctl command: 0x%X\n", cmd);
  852. ret = -ENOIOCTLCMD;
  853. break;
  854. }
  855. mutex_unlock(&mtv222_cb_ptr->ioctl_lock);
  856. return ret;
  857. }
  858. irqreturn_t mtv222_irq_handler(int irq, void *param)
  859. {
  860. U8 *tspb = NULL; /* reset */
  861. UINT intr_size;
  862. U8 istatus;
  863. if (mtv222_cb_ptr->tsout_enabled == false) {
  864. return IRQ_HANDLED;
  865. }
  866. /*
  867. ¸¸¾à óÀ½À̸é
  868. #ifdef SCHED_FIFO_USE
  869. struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
  870. sched_setscheduler(current, SCHED_FIFO, &param);
  871. #else
  872. set_user_nice(current, -20);
  873. #endif
  874. */
  875. RTV_GUARD_LOCK;
  876. rtv_UpdateAdj();
  877. RTV_REG_MAP_SEL(SPI_CTRL_PAGE);
  878. intr_size = mtv222_cb_ptr->intr_size;
  879. /* Read the register of interrupt status. */
  880. istatus = RTV_REG_GET(0x10);
  881. //DMBMSG("$$istatus(0x%02X)\n", istatus);
  882. if (istatus & SPI_UNDERFLOW_INTR) {
  883. RTV_REG_SET(0x2A, 1);
  884. RTV_REG_SET(0x2A, 0);
  885. DMBMSG("UDF: 0x%02X\n", istatus);
  886. goto exit_isr;
  887. }
  888. if (istatus & (SPI_THRESHOLD_INTR|SPI_OVERFLOW_INTR)) {
  889. /* Allocate a TS buffer from shared memory. */
  890. tspb = tsb_get();
  891. if (tspb) {
  892. RTV_REG_MAP_SEL(SPI_MEM_PAGE);
  893. RTV_REG_BURST_GET(0x10, tspb, intr_size);
  894. #ifdef _MTV_KERNEL_FILE_DUMP_ENABLE
  895. mtv_ts_dump_kfile_write(tspb, intr_size);
  896. #endif
  897. #if 0
  898. {
  899. UINT i;
  900. const U8 *tspb = (const U8 *)tspb;
  901. for (i = 0; i < size/188; i++, tsp_buf_ptr += 188) {
  902. DMBMSG("[%d] 0x%02X 0x%02X 0x%02X 0x%02X | 0x%02X\n",
  903. i, tsp_buf_ptr[0], tsp_buf_ptr[1],
  904. tsp_buf_ptr[2], tsp_buf_ptr[3],
  905. tsp_buf_ptr[187]);
  906. }
  907. }
  908. #endif
  909. /* Enqueue */
  910. tsb_enqueue(tspb);
  911. DMB_LEVEL_INTR_INC;
  912. if (istatus & SPI_OVERFLOW_INTR) {
  913. DMB_OVF_INTR_INC;
  914. DMBMSG("OVF: 0x%02X\n", istatus);
  915. }
  916. } else {
  917. RTV_REG_SET(0x2A, 1); /* SRAM init */
  918. RTV_REG_SET(0x2A, 0);
  919. #ifdef DEBUG_TSP_BUF
  920. mtv222_cb_ptr->alloc_tspb_err_cnt++;
  921. #endif
  922. DMBERR("No more TSP buffer from pool.\n");
  923. }
  924. } else
  925. DMBMSG("No data interrupt (0x%02X)\n", istatus);
  926. exit_isr:
  927. RTV_GUARD_FREE;
  928. return IRQ_HANDLED;
  929. }
  930. static int mtv222_remove(void)
  931. {
  932. mutex_lock(&mtv222_cb_ptr->ioctl_lock);
  933. mtv222_power_off();
  934. mutex_unlock(&mtv222_cb_ptr->ioctl_lock);
  935. mutex_destroy(&mtv222_cb_ptr->ioctl_lock);
  936. tsb_free_mapping_area();
  937. if (mtv222_cb_ptr) {
  938. kfree(mtv222_cb_ptr);
  939. mtv222_cb_ptr = NULL;
  940. }
  941. return 0;
  942. }
  943. static int mtv222_probe(void)
  944. {
  945. int ret;
  946. mtv222_cb_ptr = kzalloc(sizeof(struct MTV222_CB), GFP_KERNEL);
  947. if (!mtv222_cb_ptr) {
  948. DMBERR("MTV222 CB allocating error!\n");
  949. return false;
  950. }
  951. ret = tsb_alloc_mapping_area(MAX_TSB_DESC_SIZE, MAX_TSB_SEG_SIZE,
  952. MAX_NUM_TSB_SEG);
  953. if (ret) {
  954. kfree(mtv222_cb_ptr);
  955. mtv222_cb_ptr = NULL;
  956. return ret;
  957. }
  958. mutex_init(&mtv222_cb_ptr->ioctl_lock);
  959. return ret;
  960. }
  961. static struct isdbt_drv_func raontech_mtv222_drv_func = {
  962. .probe = mtv222_probe,
  963. .remove = mtv222_remove,
  964. .power_on = mtv222_power_on,
  965. .power_off = mtv222_power_off,
  966. .mmap = mtv222_mmap,
  967. .ioctl = mtv222_ioctl,
  968. .irq_handler = mtv222_irq_handler,
  969. };
  970. struct isdbt_drv_func *mtv222_drv_func(void)
  971. {
  972. DMBMSG("isdbt_drv_func : mtv222\n");
  973. return &raontech_mtv222_drv_func;
  974. }