tdmb_tsi_slsi.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. /* drivers/media/tdmb/tdmb_tsi.c
  2. *
  3. * Driver file for Samsung Transport Stream Interface
  4. *
  5. * Copyright (c) 2009 Samsung Electronics
  6. * http://www.samsungsemi.com/
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/kernel.h>
  14. #include <linux/slab.h>
  15. #include <linux/fs.h>
  16. #include <linux/uaccess.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/init.h>
  19. #include <linux/miscdevice.h>
  20. #include <linux/clk.h>
  21. #include <linux/platform_device.h>
  22. #include <linux/dma-mapping.h>
  23. #include <linux/io.h>
  24. #include <linux/sched.h>
  25. #include <linux/pm_qos.h>
  26. #include <mach/irqs.h>
  27. #include <mach/gpio.h>
  28. #include <mach/map.h>
  29. #include <mach/regs-clock.h>
  30. #include "tdmb.h"
  31. #define EXYNOS5_TSIREG(x) (x)
  32. #define EXYNOS5_TS_CLKCON EXYNOS5_TSIREG(0x00)
  33. #define EXYNOS5_TS_CON EXYNOS5_TSIREG(0x04)
  34. #define EXYNOS5_TS_SYNC EXYNOS5_TSIREG(0x08)
  35. #define EXYNOS5_TS_CNT EXYNOS5_TSIREG(0x0C)
  36. #define EXYNOS5_TS_BASE EXYNOS5_TSIREG(0x10)
  37. #define EXYNOS5_TS_SIZE EXYNOS5_TSIREG(0x14)
  38. #define EXYNOS5_TS_CADDR EXYNOS5_TSIREG(0x18)
  39. #define EXYNOS5_TS_INTMASK EXYNOS5_TSIREG(0x1C)
  40. #define EXYNOS5_TS_INT EXYNOS5_TSIREG(0x20)
  41. #define EXYNOS5_TS_PID0 EXYNOS5_TSIREG(0x24)
  42. #define EXYNOS5_TS_PID1 EXYNOS5_TSIREG(0x28)
  43. #define EXYNOS5_TS_PID2 EXYNOS5_TSIREG(0x2C)
  44. #define EXYNOS5_TS_PID3 EXYNOS5_TSIREG(0x30)
  45. #define EXYNOS5_TS_PID4 EXYNOS5_TSIREG(0x34)
  46. #define EXYNOS5_TS_PID5 EXYNOS5_TSIREG(0x38)
  47. #define EXYNOS5_TS_PID6 EXYNOS5_TSIREG(0x3C)
  48. #define EXYNOS5_TS_PID7 EXYNOS5_TSIREG(0x40)
  49. #define EXYNOS5_TS_PID8 EXYNOS5_TSIREG(0x44)
  50. #define EXYNOS5_TS_PID9 EXYNOS5_TSIREG(0x48)
  51. #define EXYNOS5_TS_PID10 EXYNOS5_TSIREG(0x4C)
  52. #define EXYNOS5_TS_PID11 EXYNOS5_TSIREG(0x50)
  53. #define EXYNOS5_TS_PID12 EXYNOS5_TSIREG(0x54)
  54. #define EXYNOS5_TS_PID13 EXYNOS5_TSIREG(0x58)
  55. #define EXYNOS5_TS_PID14 EXYNOS5_TSIREG(0x5C)
  56. #define EXYNOS5_TS_PID15 EXYNOS5_TSIREG(0x60)
  57. #define EXYNOS5_TS_PID16 EXYNOS5_TSIREG(0x64)
  58. #define EXYNOS5_TS_PID17 EXYNOS5_TSIREG(0x68)
  59. #define EXYNOS5_TS_PID18 EXYNOS5_TSIREG(0x6C)
  60. #define EXYNOS5_TS_PID19 EXYNOS5_TSIREG(0x70)
  61. #define EXYNOS5_TS_PID20 EXYNOS5_TSIREG(0x74)
  62. #define EXYNOS5_TS_PID21 EXYNOS5_TSIREG(0x78)
  63. #define EXYNOS5_TS_PID22 EXYNOS5_TSIREG(0x7C)
  64. #define EXYNOS5_TS_PID23 EXYNOS5_TSIREG(0x80)
  65. #define EXYNOS5_TS_PID24 EXYNOS5_TSIREG(0x84)
  66. #define EXYNOS5_TS_PID25 EXYNOS5_TSIREG(0x88)
  67. #define EXYNOS5_TS_PID26 EXYNOS5_TSIREG(0x8C)
  68. #define EXYNOS5_TS_PID27 EXYNOS5_TSIREG(0x90)
  69. #define EXYNOS5_TS_PID28 EXYNOS5_TSIREG(0x94)
  70. #define EXYNOS5_TS_PID29 EXYNOS5_TSIREG(0x98)
  71. #define EXYNOS5_TS_PID30 EXYNOS5_TSIREG(0x9C)
  72. #define EXYNOS5_TS_PID31 EXYNOS5_TSIREG(0xA0)
  73. #define EXYNOS5_TS_BYTE_SWAP EXYNOS5_TSIREG(0xBC)
  74. #define TS_TIMEOUT_CNT_MAX (0x00FFFFFF)
  75. #define TS_NUM_PKT (4)
  76. #define TS_PKT_SIZE 47
  77. #define TS_PKT_BUF_SIZE (TS_PKT_SIZE*TS_NUM_PKT)
  78. #define TSI_CLK_START 1
  79. #define TSI_CLK_STOP 0
  80. /* CLKCON */
  81. #define EXYNOS5_TSI_ON (0x1<<0)
  82. #define EXYNOS5_TSI_ON_MASK (0x1<<0)
  83. #define EXYNOS5_TSI_BLK_READY (0x1<<1)
  84. /* TS_CON */
  85. #define EXYNOS5_TSI_SWRESET (0x1 << 31)
  86. #define EXYNOS5_TSI_SWRESET_MASK (0x1 << 31)
  87. #define EXYNOS5_TSI_CLKFILTER_ON (0x1 << 30)
  88. #define EXYNOS5_TSI_CLKFILTER_MASK (0x1 << 30)
  89. #define EXYNOS5_TSI_CLKFILTER_SHIFT 30
  90. #define EXYNOS5_TSI_BURST_LEN_0 (0x0 << 28)
  91. #define EXYNOS5_TSI_BURST_LEN_4 (0x1 << 28)
  92. #define EXYNOS5_TSI_BURST_LEN_8 (0x2 << 28)
  93. #define EXYNOS5_TSI_BURST_LEN_MASK (0x3 << 28)
  94. #define EXYNOS5_TSI_BURST_LEN_SHIFT (28)
  95. #define EXYNOS5_TSI_OUT_BUF_FULL_INT_ENA (0x1 << 27)
  96. #define EXYNOS5_TSI_OUT_BUF_FULL_INT_MASK (0x1 << 27)
  97. #define EXYNOS5_TSI_INT_FIFO_FULL_INT_ENA (0x1 << 26)
  98. #define EXYNOS5_TSI_INT_FIFO_FULL_INT_ENA_MASK (0x1 << 26)
  99. #define EXYNOS5_TSI_SYNC_MISMATCH_INT_SKIP (0x2 << 24)
  100. #define EXYNOS5_TSI_SYNC_MISMATCH_INT_STOP (0x3 << 24)
  101. #define EXYNOS5_TSI_SYNC_MISMATCH_INT_MASK (0x3 << 24)
  102. #define EXYNOS5_TSI_PSUF_INT_SKIP (0x2 << 22)
  103. #define EXYNOS5_TSI_PSUF_INT_STOP (0x3 << 22)
  104. #define EXYNOS5_TSI_PSUF_INT_MASK (0x3 << 22)
  105. #define EXYNOS5_TSI_PSOF_INT_SKIP (0x2 << 20)
  106. #define EXYNOS5_TSI_PSOF_INT_STOP (0x3 << 20)
  107. #define EXYNOS5_TSI_PSOF_INT_MASK (0x3 << 20)
  108. #define EXYNOS5_TSI_TS_CLK_TIME_OUT_INT (0x1 << 19)
  109. #define EXYNOS5_TSI_TS_CLK_TIME_OUT_INT_MASK (0x1 << 19)
  110. #define EXYNOS5_TSI_TS_ERROR_SKIP_SIZE_INT (4<<16)
  111. #define EXYNOS5_TSI_TS_ERROR_STOP_SIZE_INT (5<<16)
  112. #define EXYNOS5_TSI_TS_ERROR_SKIP_PKT_INT (6<<16)
  113. #define EXYNOS5_TSI_TS_ERROR_STOP_PKT_INT (7<<16)
  114. #define EXYNOS5_TSI_TS_ERROR_MASK (7<<16)
  115. #define EXYNOS5_TSI_PAD_PATTERN_SHIFT (8)
  116. #define EXYNOS5_TSI_PID_FILTER_ENA (1 << 7)
  117. #define EXYNOS5_TSI_PID_FILTER_MASK (1 << 7)
  118. #define EXYNOS5_TSI_PID_FILTER_SHIFT (7)
  119. #define EXYNOS5_TSI_ERROR_ACTIVE_LOW (1<<6)
  120. #define EXYNOS5_TSI_ERROR_ACTIVE_HIGH (0<<6)
  121. #define EXYNOS5_TSI_ERROR_ACTIVE_MASK (1<<6)
  122. #define EXYNOS5_TSI_DATA_BYTE_ORDER_M2L (0 << 5)
  123. #define EXYNOS5_TSI_DATA_BYTE_ORDER_L2M (1 << 5)
  124. #define EXYNOS5_TSI_DATA_BYTE_ORDER_MASK (1 << 5)
  125. #define EXYNOS5_TSI_DATA_BYTE_ORDER_SHIFT (5)
  126. #define EXYNOS5_TSI_TS_VALID_ACTIVE_HIGH (0<<4)
  127. #define EXYNOS5_TSI_TS_VALID_ACTIVE_LOW (1<<4)
  128. #define EXYNOS5_TSI_TS_VALID_ACTIVE_MASK (1<<4)
  129. #define EXYNOS5_TSI_SYNC_ACTIVE_HIGH (0 << 3)
  130. #define EXYNOS5_TSI_SYNC_ACTIVE_LOW (1 << 3)
  131. #define EXYNOS5_TSI_SYNC_ACTIVE_MASK (1 << 3)
  132. #define EXYNOS5_TSI_CLK_INVERT_HIGH (0 << 2)
  133. #define EXYNOS5_TSI_CLK_INVERT_LOW (1 << 2)
  134. #define EXYNOS5_TSI_CLK_INVERT_MASK (1 << 2)
  135. /* TS_SYNC */
  136. #define EXYNOS5_TSI_SYNC_DET_MODE_TS_SYNC8 (0<<0)
  137. #define EXYNOS5_TSI_SYNC_DET_MODE_TS_SYNC1 (1<<0)
  138. #define EXYNOS5_TSI_SYNC_DET_MODE_TS_SYNC_BYTE (2<<0)
  139. #define EXYNOS5_TSI_SYNC_DET_MODE_TS_SYNC_MASK (3<<0)
  140. /* TS_INT_MASK */
  141. #define EXYNOS5_TSI_DMA_COMPLETE_ENA (1 << 7)
  142. #define EXYNOS5_TSI_OUTPUT_BUF_FULL_ENA (1 << 6)
  143. #define EXYNOS5_TSI_INT_FIFO_FULL_ENA (1 << 5)
  144. #define EXYNOS5_TSI_SYNC_MISMATCH_ENA (1 << 4)
  145. #define EXYNOS5_TSI_PKT_SIZE_UNDERFLOW_ENA (1 << 3)
  146. #define EXYNOS5_TSI_PKT_SIZE_OVERFLOW_ENA (1 << 2)
  147. #define EXYNOS5_TSI_TS_CLK_ENA (1 << 1)
  148. #define EXYNOS5_TSI_TS_ERROR_ENA (1 << 0)
  149. /* TS_INT_FLAG */
  150. #define EXYNOS5_TSI_DMA_COMPLETE (1<<7)
  151. #define EXYNOS5_TSI_OUT_BUF_FULL (1<<6)
  152. #define EXYNOS5_TSI_INT_FIFO_FULL (1<<5)
  153. #define EXYNOS5_TSI_SYNC_MISMATCH (1<<4)
  154. #define EXYNOS5_TSI_PKT_UNDERFLOW (1<<3)
  155. #define EXYNOS5_TSI_PKT_OVERFLOW (1<<2)
  156. #define EXYNOS5_TSI_PKT_CLK (1<<1)
  157. #define EXYNOS5_TSI_ERROR (1<<0)
  158. #define TSI_BUF_SIZE (128*1024)
  159. #define TSI_PKT_CNT 16
  160. enum filter_mode {
  161. OFF,
  162. ON
  163. };
  164. enum pid_filter_mode {
  165. BYPASS = 0,
  166. FILTERING
  167. };
  168. enum data_byte_order {
  169. MSB2LSB = 0,
  170. LSB2MSB
  171. };
  172. struct tsi_pkt {
  173. struct list_head list;
  174. dma_addr_t addr;
  175. void *buf;
  176. u32 len;
  177. };
  178. struct exynos5_tsi_conf {
  179. enum filter_mode flt_mode;
  180. enum pid_filter_mode pid_flt_mode;
  181. enum data_byte_order byte_order;
  182. u16 burst_len;
  183. u8 sync_detect;
  184. u8 byte_swap;
  185. u16 pad_pattern;
  186. u16 num_packet;
  187. };
  188. struct tsi_dev {
  189. spinlock_t tsi_lock;
  190. struct clk *gate_tsi;
  191. void __iomem *tsi_base;
  192. int tsi_irq;
  193. int running;
  194. dma_addr_t tsi_buf_phy;
  195. void *tsi_buf_virt;
  196. u32 tsi_buf_size;
  197. struct exynos5_tsi_conf *tsi_conf;
  198. struct list_head free_list;
  199. struct list_head full_list;
  200. struct list_head partial_list;
  201. };
  202. struct tsi_dev *tsi_priv;
  203. static struct platform_device *exynos5_tsi_dev;
  204. static void (*tsi_data_callback)(u8 *data, u32 length) = NULL;
  205. static void tdmb_tsi_pull_data(struct work_struct *work);
  206. static struct workqueue_struct *tdmb_tsi_workqueue;
  207. static DECLARE_WORK(tdmb_tsi_work, tdmb_tsi_pull_data);
  208. static struct pm_qos_request mif_handle;
  209. /* #define CONFIG_TSI_LIST_DEBUG */
  210. #ifdef CONFIG_TSI_LIST_DEBUG
  211. static void list_debug(struct list_head *head, const char *str)
  212. {
  213. int i;
  214. struct tsi_pkt *pkt;
  215. /* DPRINTK("DEBUGGING FREE LIST\n"); */
  216. i = 1;
  217. list_for_each_entry(pkt, head, list) {
  218. /* DPRINTK("%s node %d node_addr %p physical add %x virt add %p size %d\n",
  219. str, i, pkt, pkt->addr, pkt->buf, pkt->len); */
  220. i++;
  221. }
  222. DPRINTK("%s: %s %d\n", __func__, str, i - 1);
  223. }
  224. #endif
  225. static void exynos5_tsi_set_gpio(bool on)
  226. {
  227. DPRINTK("%s: %d\n", __func__, on);
  228. if (on) {
  229. struct pinctrl *pinctrl;
  230. pinctrl = devm_pinctrl_get_select(&exynos5_tsi_dev->dev, "tdmb_tsi_on");
  231. if (IS_ERR(pinctrl))
  232. DPRINTK("%s: Failed to configure tdmb_tsi_on\n", __func__);
  233. } else {
  234. struct pinctrl *pinctrl;
  235. pinctrl = devm_pinctrl_get_select(&exynos5_tsi_dev->dev, "tdmb_tsi_off");
  236. if (IS_ERR(pinctrl))
  237. DPRINTK("%s: Failed to configure tdmb_tsi_off\n", __func__);
  238. }
  239. }
  240. static void exynos5_tsi_reset(struct tsi_dev *tsi)
  241. {
  242. u32 tscon;
  243. tscon = readl((tsi->tsi_base + EXYNOS5_TS_CON));
  244. tscon |= EXYNOS5_TSI_SWRESET;
  245. writel(tscon, (tsi->tsi_base + EXYNOS5_TS_CON));
  246. }
  247. static void exynos5_tsi_set_timeout(u32 count, struct tsi_dev *tsi)
  248. {
  249. writel(count, (tsi->tsi_base + EXYNOS5_TS_CNT));
  250. }
  251. static struct tsi_pkt *tsi_get_pkt(struct tsi_dev *tsi, struct list_head *head)
  252. {
  253. unsigned long flags;
  254. struct tsi_pkt *pkt;
  255. spin_lock_irqsave(&tsi->tsi_lock, flags);
  256. if (list_empty(head)) {
  257. /* DPRINTK("TSI %p list is null\n", head); */
  258. spin_unlock_irqrestore(&tsi->tsi_lock, flags);
  259. return NULL;
  260. }
  261. pkt = list_first_entry(head, struct tsi_pkt, list);
  262. spin_unlock_irqrestore(&tsi->tsi_lock, flags);
  263. return pkt;
  264. }
  265. static void exynos5_tsi_set_dest_addr(dma_addr_t addr, void __iomem *reg)
  266. {
  267. writel(addr, reg);
  268. }
  269. static void exynos5_tsi_set_sync_mode(u8 mode, void __iomem *reg)
  270. {
  271. u32 val = 0;
  272. val |= (0xff & mode);
  273. writel(val, reg);
  274. }
  275. static void exynos5_tsi_set_clock(u8 enable, void __iomem *reg)
  276. {
  277. u32 val = 0;
  278. if (enable)
  279. val |= 0x1;
  280. writel(val, reg);
  281. }
  282. static int exynos5_tsi_clk_enable(struct tsi_dev *tsi)
  283. {
  284. if (clk_prepare_enable(tsi->gate_tsi))
  285. return -ENOMEM;
  286. return 0;
  287. }
  288. static void exynos5_tsi_clk_disable(struct tsi_dev *tsi)
  289. {
  290. clk_disable_unprepare(tsi->gate_tsi);
  291. }
  292. static void tsi_enable_interrupts(struct tsi_dev *tsi)
  293. {
  294. u32 mask;
  295. /* Enable all the interrupts... */
  296. mask = 0xFF;
  297. writel(mask, (tsi->tsi_base + EXYNOS5_TS_INTMASK));
  298. }
  299. static void tsi_disable_interrupts(struct tsi_dev *tsi)
  300. {
  301. writel(0, (tsi->tsi_base + EXYNOS5_TS_INTMASK));
  302. }
  303. static bool tdmb_tsi_create_workqueue(void)
  304. {
  305. tdmb_tsi_workqueue = create_singlethread_workqueue("ktdmbtsi");
  306. if (tdmb_tsi_workqueue)
  307. return true;
  308. else
  309. return false;
  310. }
  311. static bool tdmb_tsi_destroy_workqueue(void)
  312. {
  313. if (tdmb_tsi_workqueue) {
  314. flush_workqueue(tdmb_tsi_workqueue);
  315. destroy_workqueue(tdmb_tsi_workqueue);
  316. tdmb_tsi_workqueue = NULL;
  317. }
  318. return true;
  319. }
  320. static void exynos5_tsi_setup(struct tsi_dev *tsi)
  321. {
  322. u32 tscon;
  323. struct exynos5_tsi_conf *conf = tsi->tsi_conf;
  324. exynos5_tsi_reset(tsi);
  325. exynos5_tsi_set_timeout(TS_TIMEOUT_CNT_MAX, tsi);
  326. tscon = readl((tsi->tsi_base + EXYNOS5_TS_CON));
  327. tscon &= ~(EXYNOS5_TSI_SWRESET_MASK|EXYNOS5_TSI_CLKFILTER_MASK|
  328. EXYNOS5_TSI_BURST_LEN_MASK | EXYNOS5_TSI_INT_FIFO_FULL_INT_ENA_MASK |
  329. EXYNOS5_TSI_SYNC_MISMATCH_INT_MASK | EXYNOS5_TSI_PSUF_INT_MASK|
  330. EXYNOS5_TSI_PSOF_INT_MASK | EXYNOS5_TSI_TS_CLK_TIME_OUT_INT_MASK |
  331. EXYNOS5_TSI_TS_ERROR_MASK | EXYNOS5_TSI_PID_FILTER_MASK |
  332. EXYNOS5_TSI_ERROR_ACTIVE_MASK | EXYNOS5_TSI_DATA_BYTE_ORDER_MASK |
  333. EXYNOS5_TSI_TS_VALID_ACTIVE_MASK | EXYNOS5_TSI_SYNC_ACTIVE_MASK |
  334. EXYNOS5_TSI_CLK_INVERT_MASK);
  335. tscon |= (conf->flt_mode << EXYNOS5_TSI_CLKFILTER_SHIFT);
  336. tscon |= (conf->pid_flt_mode << EXYNOS5_TSI_PID_FILTER_SHIFT);
  337. tscon |= (conf->byte_order << EXYNOS5_TSI_DATA_BYTE_ORDER_SHIFT);
  338. tscon |= (conf->burst_len << EXYNOS5_TSI_BURST_LEN_SHIFT);
  339. tscon |= (conf->pad_pattern << EXYNOS5_TSI_PAD_PATTERN_SHIFT);
  340. tscon |= (EXYNOS5_TSI_OUT_BUF_FULL_INT_ENA | EXYNOS5_TSI_INT_FIFO_FULL_INT_ENA);
  341. tscon |= (/*EXYNOS5_TSI_SYNC_MISMATCH_INT_SKIP |*/ EXYNOS5_TSI_PSUF_INT_SKIP |
  342. EXYNOS5_TSI_PSOF_INT_SKIP);
  343. tscon |= (EXYNOS5_TSI_TS_CLK_TIME_OUT_INT);
  344. /* These values are bd dependent? */
  345. tscon |= (EXYNOS5_TSI_TS_VALID_ACTIVE_HIGH | EXYNOS5_TSI_CLK_INVERT_LOW);
  346. writel(tscon, (tsi->tsi_base + EXYNOS5_TS_CON));
  347. DPRINTK("%s 0x%x\n", __func__, tscon);
  348. exynos5_tsi_set_sync_mode(conf->sync_detect, tsi->tsi_base + EXYNOS5_TS_SYNC);
  349. }
  350. static int tsi_setup_bufs(struct tsi_dev *dev, struct list_head *head, int packet_cnt)
  351. {
  352. struct tsi_pkt *pkt;
  353. u32 tsi_virt, tsi_size, buf_size;
  354. u16 num_buf;
  355. dma_addr_t tsi_phy;
  356. int i;
  357. tsi_phy = dev->tsi_buf_phy;
  358. tsi_virt = (u32) dev->tsi_buf_virt;
  359. tsi_size = dev->tsi_buf_size;
  360. /* TSI generates interrupt after filling this many bytes */
  361. buf_size = dev->tsi_conf->num_packet * TS_PKT_SIZE * packet_cnt;
  362. num_buf = (tsi_size / buf_size);
  363. for (i = 0; i < num_buf; i++) {
  364. pkt = kmalloc(sizeof(struct tsi_pkt), GFP_KERNEL);
  365. if (!pkt)
  366. return list_empty(head) ? -ENOMEM : 0 ;
  367. /* Address should be byte-aligned
  368. Commented by sjinu, 2009_03_18 */
  369. pkt->addr = ((u32)tsi_phy + i*buf_size);
  370. pkt->buf = (void *)(u8 *)((u32)tsi_virt + i*buf_size);
  371. pkt->len = buf_size;
  372. list_add_tail(&pkt->list, head);
  373. }
  374. DPRINTK("total nodes calulated %d buf_size %d\n", num_buf, buf_size);
  375. #ifdef CONFIG_TSI_LIST_DEBUG1
  376. list_debug(head, "free_list");
  377. #endif
  378. return 0;
  379. }
  380. static void tsi_free_packets(struct tsi_dev *tsi)
  381. {
  382. struct tsi_pkt *pkt;
  383. unsigned long flags;
  384. struct list_head *full = &tsi->full_list;
  385. struct list_head *partial = &tsi->partial_list;
  386. struct list_head *head = &(tsi->free_list);
  387. spin_lock_irqsave(&tsi->tsi_lock, flags);
  388. /* move all the packets from partial and full list to free list */
  389. while (!list_empty(full)) {
  390. pkt = list_entry(full->next, struct tsi_pkt, list);
  391. list_move_tail(&pkt->list, &tsi->free_list);
  392. }
  393. while (!list_empty(partial)) {
  394. pkt = list_entry(partial->next, struct tsi_pkt, list);
  395. list_move_tail(&pkt->list, &tsi->free_list);
  396. }
  397. spin_unlock_irqrestore(&tsi->tsi_lock, flags);
  398. while (!list_empty(head)) {
  399. pkt = list_entry(head->next, struct tsi_pkt, list);
  400. list_del(&pkt->list);
  401. kfree(pkt);
  402. }
  403. }
  404. static int exynos5_tsi_start(struct tsi_dev *tsi, void (*callback)(u8 *data, u32 length), int packet_cnt)
  405. {
  406. unsigned long flags;
  407. u32 pkt_size;
  408. struct tsi_pkt *pkt;
  409. int ret;
  410. pm_qos_add_request(&mif_handle, PM_QOS_BUS_THROUGHPUT, 275000);
  411. exynos5_tsi_set_gpio(true);
  412. if(exynos5_tsi_clk_enable(tsi)) {
  413. DPRINTK("%s: clk_prepare_enable failed\n", __func__);
  414. ret = -ENOMEM;
  415. goto err_gpio;
  416. }
  417. exynos5_tsi_setup(tsi);
  418. if (tsi_setup_bufs(tsi, &tsi->free_list, packet_cnt)) {
  419. DPRINTK("TSI failed to setup pkt list");
  420. ret = -ENOMEM;
  421. goto err_clk;
  422. }
  423. if (tdmb_tsi_create_workqueue() == false) {
  424. DPRINTK("tdmb_tsi_create_workqueue fail\n");
  425. ret = -ENOMEM;
  426. goto err_packets;
  427. }
  428. pkt = tsi_get_pkt(tsi, &tsi->free_list);
  429. if (pkt == NULL) {
  430. DPRINTK("Failed to start TSI--No buffers avaialble\n");
  431. ret = -ENOMEM;
  432. goto err_wq;
  433. }
  434. pkt_size = pkt->len;
  435. tsi_data_callback = callback;
  436. DPRINTK("%s: pkt_size %d\n", __func__, pkt_size);
  437. /* when set the TS BUF SIZE to the EXYNOS5_TS_SIZE,
  438. if you want get a 10-block TS from TSIF,
  439. you should set the value of EXYNOS5_TS_SIZE as 47*10(not 188*10)
  440. This register get a value of word-multiple values.
  441. So, pkt_size which is counted to BYTES must be divided by 4
  442. Commented by sjinu, 2009_03_18
  443. */
  444. writel(pkt_size>>2, (tsi->tsi_base + EXYNOS5_TS_SIZE));
  445. exynos5_tsi_set_dest_addr(pkt->addr, tsi->tsi_base + EXYNOS5_TS_BASE);
  446. spin_lock_irqsave(&tsi->tsi_lock, flags);
  447. list_move_tail(&pkt->list, &tsi->partial_list);
  448. spin_unlock_irqrestore(&tsi->tsi_lock, flags);
  449. /* start the clock */
  450. exynos5_tsi_set_clock(TSI_CLK_START, tsi->tsi_base + EXYNOS5_TS_CLKCON);
  451. /* set the second shadow base address */
  452. pkt = tsi_get_pkt(tsi, &tsi->free_list);
  453. if (pkt == NULL) {
  454. DPRINTK("Failed to start TSI--No buffers avaialble\n");
  455. ret = -ENOMEM;
  456. goto err_wq;
  457. }
  458. exynos5_tsi_set_dest_addr(pkt->addr, tsi->tsi_base + EXYNOS5_TS_BASE);
  459. spin_lock_irqsave(&tsi->tsi_lock, flags);
  460. list_move_tail(&pkt->list, &tsi->partial_list);
  461. spin_unlock_irqrestore(&tsi->tsi_lock, flags);
  462. tsi_enable_interrupts(tsi);
  463. tsi->running = 1;
  464. #ifdef CONFIG_TSI_LIST_DEBUG1
  465. list_debug(&tsi->partial_list, "partial_list");
  466. list_debug(&tsi->free_list, "free_list");
  467. #endif
  468. return 0;
  469. err_wq:
  470. tdmb_tsi_destroy_workqueue();
  471. err_packets:
  472. tsi_free_packets(tsi);
  473. err_clk:
  474. exynos5_tsi_clk_disable(tsi);
  475. err_gpio:
  476. exynos5_tsi_set_gpio(false);
  477. pm_qos_remove_request(&mif_handle);
  478. return ret;
  479. }
  480. int tdmb_tsi_start(void (*callback)(u8 *data, u32 length), int packet_cnt)
  481. {
  482. if (exynos5_tsi_dev) {
  483. struct tsi_dev *tsi = platform_get_drvdata(exynos5_tsi_dev);
  484. DPRINTK("%s: packet_cnt %d run %d\n", __func__, packet_cnt, tsi->running);
  485. if (tsi->running)
  486. return 0;
  487. return exynos5_tsi_start(tsi, callback, packet_cnt);
  488. } else {
  489. DPRINTK("%s: exynos5_tsi_dev is null\n", __func__);
  490. return -1;
  491. }
  492. }
  493. EXPORT_SYMBOL_GPL(tdmb_tsi_start);
  494. static int exynos5_tsi_stop(struct tsi_dev *tsi)
  495. {
  496. tsi->running = 0;
  497. tsi_disable_interrupts(tsi);
  498. exynos5_tsi_set_clock(TSI_CLK_STOP, tsi->tsi_base + EXYNOS5_TS_CLKCON);
  499. tsi_free_packets(tsi);
  500. exynos5_tsi_set_gpio(false);
  501. tdmb_tsi_destroy_workqueue();
  502. exynos5_tsi_clk_disable(tsi);
  503. tsi_data_callback = NULL;
  504. pm_qos_remove_request(&mif_handle);
  505. return 0;
  506. }
  507. int tdmb_tsi_stop(void)
  508. {
  509. if (exynos5_tsi_dev) {
  510. struct tsi_dev *tsi = platform_get_drvdata(exynos5_tsi_dev);
  511. DPRINTK("%s: run %d\n", __func__, tsi->running);
  512. if (!tsi->running)
  513. return 0;
  514. return exynos5_tsi_stop(tsi);
  515. } else {
  516. DPRINTK("%s: exynos5_tsi_dev is null\n", __func__);
  517. return -1;
  518. }
  519. }
  520. EXPORT_SYMBOL_GPL(tdmb_tsi_stop);
  521. static void tdmb_tsi_pull_data(struct work_struct *work)
  522. {
  523. /* DPRINTK("%s\n", __func__); */
  524. if (exynos5_tsi_dev) {
  525. struct tsi_dev *tsi = platform_get_drvdata(exynos5_tsi_dev);
  526. struct tsi_pkt *pkt;
  527. unsigned long flags;
  528. #ifdef CONFIG_TSI_LIST_DEBUG
  529. list_debug(&tsi->free_list, "free_list");
  530. /* list_debug(&tsi->partial_list, "partial_list"); */
  531. /* list_debug(&tsi->full_list, "full_list"); */
  532. #endif
  533. while ((pkt = tsi_get_pkt(tsi, &tsi->full_list)) != NULL) {
  534. if (tsi_data_callback)
  535. tsi_data_callback(pkt->buf, pkt->len);
  536. spin_lock_irqsave(&tsi->tsi_lock, flags);
  537. list_move(&pkt->list, &tsi->free_list);
  538. spin_unlock_irqrestore(&tsi->tsi_lock, flags);
  539. }
  540. }
  541. }
  542. static irqreturn_t exynos5_tsi_irq(int irq, void *dev_id)
  543. {
  544. u32 intpnd;
  545. struct tsi_dev *tsi = platform_get_drvdata((struct platform_device *)dev_id);
  546. if (!tsi->running)
  547. return IRQ_HANDLED;
  548. intpnd = readl(tsi->tsi_base + EXYNOS5_TS_INT);
  549. writel(intpnd, (tsi->tsi_base + EXYNOS5_TS_INT));
  550. if (intpnd & EXYNOS5_TSI_OUT_BUF_FULL) {
  551. struct tsi_pkt *pkt;
  552. /* deque the pcket from partial list to full list
  553. incase the free list is empty, stop the tsi.. */
  554. pkt = tsi_get_pkt(tsi, &tsi->partial_list);
  555. /* this situation should not come.. stop_tsi */
  556. if (pkt == NULL) {
  557. DPRINTK("TSI..Receive interrupt without buffer\n");
  558. return IRQ_HANDLED;
  559. }
  560. #ifdef CONFIG_TSI_LIST_DEBUG1
  561. DPRINTK("moving %p node %x phy %p virt to full list\n",
  562. pkt, pkt->addr, pkt->buf);
  563. #endif
  564. list_move_tail(&pkt->list, &tsi->full_list);
  565. pkt = tsi_get_pkt(tsi, &tsi->free_list);
  566. if (pkt == NULL) {
  567. /* this situation should not come.. stop_tsi */
  568. DPRINTK("TSI..No more free bufs..\n");
  569. return IRQ_HANDLED;
  570. }
  571. list_move_tail(&pkt->list, &tsi->partial_list);
  572. /* namkh, request from Abraham
  573. If there arise a buffer-full interrupt,
  574. a new ts buffer address should be set.
  575. Commented by sjinu, 2009_03_18 */
  576. exynos5_tsi_set_dest_addr(pkt->addr, tsi->tsi_base + EXYNOS5_TS_BASE);
  577. if (tdmb_tsi_workqueue) {
  578. int ret;
  579. ret = queue_work(tdmb_tsi_workqueue, &tdmb_tsi_work);
  580. if (ret == 0)
  581. DPRINTK("failed in queue_work\n");
  582. }
  583. } else
  584. DPRINTK("exynos5_tsi_irq 0x%x\n", intpnd);
  585. return IRQ_HANDLED;
  586. }
  587. static int tdmb_tsi_probe(struct platform_device *pdev)
  588. {
  589. struct resource *res;
  590. static int ret;
  591. struct exynos5_tsi_conf *conf;
  592. dma_addr_t map_dma;
  593. struct device *dev = &pdev->dev;
  594. DPRINTK(" %s\n", __func__);
  595. tsi_priv = kmalloc(sizeof(struct tsi_dev), GFP_KERNEL);
  596. if (tsi_priv == NULL) {
  597. DPRINTK("NO Memory for tsi allocation\n");
  598. return -ENOMEM;
  599. }
  600. conf = kmalloc(sizeof(struct exynos5_tsi_conf), GFP_KERNEL);
  601. if (conf == NULL) {
  602. DPRINTK("NO Memory for tsi conf allocation\n");
  603. kfree(tsi_priv);
  604. return -ENOMEM;
  605. }
  606. /* Initialise the dafault conf parameters..
  607. * this should be obtained from the platform data and ioctl
  608. * move this to platform later */
  609. conf->flt_mode = OFF;
  610. conf->pid_flt_mode = BYPASS;
  611. conf->byte_order = MSB2LSB;
  612. conf->sync_detect = EXYNOS5_TSI_SYNC_DET_MODE_TS_SYNC8;/* EXYNOS5_TSI_SYNC_DET_MODE_TS_SYNC_BYTE */
  613. /*
  614. to avoid making interrupt during getting the TS from TS buffer,
  615. we use the burst-length as 8 beat.
  616. This burst-length may be changed next time.
  617. Commented by sjinu, 2009_03_18
  618. */
  619. conf->burst_len = 2;
  620. conf->byte_swap = 1; /* little endian */
  621. conf->pad_pattern = 0; /* this might vary from bd to bd */
  622. conf->num_packet = TS_NUM_PKT; /* this might vary from bd to bd */
  623. tsi_priv->tsi_conf = conf;
  624. tsi_priv->tsi_buf_size = TSI_BUF_SIZE;
  625. tsi_priv->gate_tsi = devm_clk_get(dev, "gate_tsi");
  626. if (tsi_priv->gate_tsi == NULL) {
  627. DPRINTK(KERN_ERR "Failed to get TSI clock\n");
  628. ret = -ENOENT;
  629. goto err_res;
  630. }
  631. ret = platform_get_irq(pdev, 0);
  632. if (ret < 0) {
  633. DPRINTK("Failed to get IRQ: %d\n", ret);
  634. goto err_res;
  635. }
  636. tsi_priv->tsi_irq = ret;
  637. ret = devm_request_irq(dev, tsi_priv->tsi_irq, exynos5_tsi_irq, 0, pdev->name, pdev);
  638. /* DPRINTK("tsi_irq %d ret %d\n", tsi_priv->tsi_irq, ret); */
  639. if (ret != 0) {
  640. DPRINTK("failed to install irq (%d)\n", ret);
  641. goto err_res;
  642. }
  643. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  644. if (res == NULL) {
  645. DPRINTK("failed to get memory region resouce\n");
  646. ret = -ENOENT;
  647. goto err_irq;
  648. }
  649. tsi_priv->tsi_base = devm_ioremap_resource(dev, res);
  650. /* DPRINTK("base_phy 0x%x base_virt 0x%p\n", res->start, tsi_priv->tsi_base); */
  651. if (IS_ERR(tsi_priv->tsi_base)) {
  652. DPRINTK("failed to get base_addr (0x%p)\n", tsi_priv->tsi_base);
  653. ret = -ENXIO;
  654. goto err_irq;
  655. }
  656. INIT_LIST_HEAD(&tsi_priv->free_list);
  657. INIT_LIST_HEAD(&tsi_priv->full_list);
  658. INIT_LIST_HEAD(&tsi_priv->partial_list);
  659. spin_lock_init(&tsi_priv->tsi_lock);
  660. tsi_priv->running = 0;
  661. /* get the dma coherent mem */
  662. tsi_priv->tsi_buf_virt = dma_alloc_coherent(dev, tsi_priv->tsi_buf_size, &map_dma, GFP_KERNEL);
  663. if (tsi_priv->tsi_buf_virt == NULL) {
  664. DPRINTK("Failed to claim TSI memory\n");
  665. ret = -ENOMEM;
  666. goto err_map;
  667. }
  668. /* DPRINTK("TSI dev dma mem phy %x virt %p\n", map_dma, tsi_priv->tsi_buf_virt); */
  669. tsi_priv->tsi_buf_phy = map_dma;
  670. platform_set_drvdata(pdev, tsi_priv);
  671. exynos5_tsi_dev = pdev;
  672. return 0;
  673. err_map:
  674. iounmap(tsi_priv->tsi_base);
  675. err_irq:
  676. free_irq(tsi_priv->tsi_irq, pdev);
  677. err_res:
  678. kfree(conf);
  679. kfree(tsi_priv);
  680. return ret;
  681. }
  682. static int tdmb_tsi_remove(struct platform_device *dev)
  683. {
  684. struct tsi_dev *tsi = platform_get_drvdata((struct platform_device *)dev);
  685. if (tsi->running)
  686. exynos5_tsi_stop(tsi);
  687. free_irq(tsi->tsi_irq, dev);
  688. dma_free_coherent(&dev->dev, tsi->tsi_buf_size, tsi->tsi_buf_virt, tsi->tsi_buf_phy);
  689. kfree(tsi->tsi_conf);
  690. kfree(tsi);
  691. return 0;
  692. }
  693. static const struct of_device_id tsi_match_table[] = {
  694. {.compatible = "samsung,tsi"},
  695. {}
  696. };
  697. static struct platform_driver tdmb_tsi_driver = {
  698. .driver = {
  699. .name = "tsi",
  700. .of_match_table = tsi_match_table,
  701. .owner = THIS_MODULE,
  702. },
  703. .remove = tdmb_tsi_remove,
  704. };
  705. static int __init tdmb_tsi_init(void)
  706. {
  707. DPRINTK(" %s\n", __func__);
  708. return platform_driver_probe(&tdmb_tsi_driver, tdmb_tsi_probe);
  709. }
  710. static void __exit tdmb_tsi_exit(void)
  711. {
  712. platform_driver_unregister(&tdmb_tsi_driver);
  713. }
  714. module_init(tdmb_tsi_init);
  715. module_exit(tdmb_tsi_exit);
  716. MODULE_AUTHOR("Samsung");
  717. MODULE_DESCRIPTION("Exynos TSI Device Driver");
  718. MODULE_LICENSE("GPL");