lcd_dma.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * linux/arch/arm/mach-omap1/lcd_dma.c
  4. *
  5. * Extracted from arch/arm/plat-omap/dma.c
  6. * Copyright (C) 2003 - 2008 Nokia Corporation
  7. * Author: Juha Yrjölä <juha.yrjola@nokia.com>
  8. * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>
  9. * Graphics DMA and LCD DMA graphics tranformations
  10. * by Imre Deak <imre.deak@nokia.com>
  11. * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc.
  12. * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com>
  13. * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
  14. *
  15. * Copyright (C) 2009 Texas Instruments
  16. * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
  17. *
  18. * Support functions for the OMAP internal DMA channels.
  19. */
  20. #include <linux/export.h>
  21. #include <linux/module.h>
  22. #include <linux/spinlock.h>
  23. #include <linux/interrupt.h>
  24. #include <linux/io.h>
  25. #include <linux/omap-dma.h>
  26. #include <linux/soc/ti/omap1-soc.h>
  27. #include <linux/soc/ti/omap1-io.h>
  28. #include "lcdc.h"
  29. #include "lcd_dma.h"
  30. int omap_lcd_dma_running(void)
  31. {
  32. /*
  33. * On OMAP1510, internal LCD controller will start the transfer
  34. * when it gets enabled, so assume DMA running if LCD enabled.
  35. */
  36. if (cpu_is_omap15xx())
  37. if (omap_readw(OMAP_LCDC_CONTROL) & OMAP_LCDC_CTRL_LCD_EN)
  38. return 1;
  39. /* Check if LCD DMA is running */
  40. if (cpu_is_omap16xx())
  41. if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN)
  42. return 1;
  43. return 0;
  44. }
  45. static struct lcd_dma_info {
  46. spinlock_t lock;
  47. int reserved;
  48. void (*callback)(u16 status, void *data);
  49. void *cb_data;
  50. int active;
  51. unsigned long addr;
  52. int rotate, data_type, xres, yres;
  53. int vxres;
  54. int mirror;
  55. int xscale, yscale;
  56. int ext_ctrl;
  57. int src_port;
  58. int single_transfer;
  59. } lcd_dma;
  60. void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,
  61. int data_type)
  62. {
  63. lcd_dma.addr = addr;
  64. lcd_dma.data_type = data_type;
  65. lcd_dma.xres = fb_xres;
  66. lcd_dma.yres = fb_yres;
  67. }
  68. EXPORT_SYMBOL(omap_set_lcd_dma_b1);
  69. void omap_set_lcd_dma_ext_controller(int external)
  70. {
  71. lcd_dma.ext_ctrl = external;
  72. }
  73. EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller);
  74. void omap_set_lcd_dma_single_transfer(int single)
  75. {
  76. lcd_dma.single_transfer = single;
  77. }
  78. EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);
  79. void omap_set_lcd_dma_b1_rotation(int rotate)
  80. {
  81. if (cpu_is_omap15xx()) {
  82. printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n");
  83. BUG();
  84. return;
  85. }
  86. lcd_dma.rotate = rotate;
  87. }
  88. EXPORT_SYMBOL(omap_set_lcd_dma_b1_rotation);
  89. void omap_set_lcd_dma_b1_mirror(int mirror)
  90. {
  91. if (cpu_is_omap15xx()) {
  92. printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n");
  93. BUG();
  94. }
  95. lcd_dma.mirror = mirror;
  96. }
  97. EXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror);
  98. void omap_set_lcd_dma_b1_vxres(unsigned long vxres)
  99. {
  100. if (cpu_is_omap15xx()) {
  101. pr_err("DMA virtual resolution is not supported in 1510 mode\n");
  102. BUG();
  103. }
  104. lcd_dma.vxres = vxres;
  105. }
  106. EXPORT_SYMBOL(omap_set_lcd_dma_b1_vxres);
  107. void omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale)
  108. {
  109. if (cpu_is_omap15xx()) {
  110. printk(KERN_ERR "DMA scale is not supported in 1510 mode\n");
  111. BUG();
  112. }
  113. lcd_dma.xscale = xscale;
  114. lcd_dma.yscale = yscale;
  115. }
  116. EXPORT_SYMBOL(omap_set_lcd_dma_b1_scale);
  117. static void set_b1_regs(void)
  118. {
  119. unsigned long top, bottom;
  120. int es;
  121. u16 w;
  122. unsigned long en, fn;
  123. long ei, fi;
  124. unsigned long vxres;
  125. unsigned int xscale, yscale;
  126. switch (lcd_dma.data_type) {
  127. case OMAP_DMA_DATA_TYPE_S8:
  128. es = 1;
  129. break;
  130. case OMAP_DMA_DATA_TYPE_S16:
  131. es = 2;
  132. break;
  133. case OMAP_DMA_DATA_TYPE_S32:
  134. es = 4;
  135. break;
  136. default:
  137. BUG();
  138. return;
  139. }
  140. vxres = lcd_dma.vxres ? lcd_dma.vxres : lcd_dma.xres;
  141. xscale = lcd_dma.xscale ? lcd_dma.xscale : 1;
  142. yscale = lcd_dma.yscale ? lcd_dma.yscale : 1;
  143. BUG_ON(vxres < lcd_dma.xres);
  144. #define PIXADDR(x, y) (lcd_dma.addr + \
  145. ((y) * vxres * yscale + (x) * xscale) * es)
  146. #define PIXSTEP(sx, sy, dx, dy) (PIXADDR(dx, dy) - PIXADDR(sx, sy) - es + 1)
  147. switch (lcd_dma.rotate) {
  148. case 0:
  149. if (!lcd_dma.mirror) {
  150. top = PIXADDR(0, 0);
  151. bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
  152. /* 1510 DMA requires the bottom address to be 2 more
  153. * than the actual last memory access location. */
  154. if (cpu_is_omap15xx() &&
  155. lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32)
  156. bottom += 2;
  157. ei = PIXSTEP(0, 0, 1, 0);
  158. fi = PIXSTEP(lcd_dma.xres - 1, 0, 0, 1);
  159. } else {
  160. top = PIXADDR(lcd_dma.xres - 1, 0);
  161. bottom = PIXADDR(0, lcd_dma.yres - 1);
  162. ei = PIXSTEP(1, 0, 0, 0);
  163. fi = PIXSTEP(0, 0, lcd_dma.xres - 1, 1);
  164. }
  165. en = lcd_dma.xres;
  166. fn = lcd_dma.yres;
  167. break;
  168. case 90:
  169. if (!lcd_dma.mirror) {
  170. top = PIXADDR(0, lcd_dma.yres - 1);
  171. bottom = PIXADDR(lcd_dma.xres - 1, 0);
  172. ei = PIXSTEP(0, 1, 0, 0);
  173. fi = PIXSTEP(0, 0, 1, lcd_dma.yres - 1);
  174. } else {
  175. top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
  176. bottom = PIXADDR(0, 0);
  177. ei = PIXSTEP(0, 1, 0, 0);
  178. fi = PIXSTEP(1, 0, 0, lcd_dma.yres - 1);
  179. }
  180. en = lcd_dma.yres;
  181. fn = lcd_dma.xres;
  182. break;
  183. case 180:
  184. if (!lcd_dma.mirror) {
  185. top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
  186. bottom = PIXADDR(0, 0);
  187. ei = PIXSTEP(1, 0, 0, 0);
  188. fi = PIXSTEP(0, 1, lcd_dma.xres - 1, 0);
  189. } else {
  190. top = PIXADDR(0, lcd_dma.yres - 1);
  191. bottom = PIXADDR(lcd_dma.xres - 1, 0);
  192. ei = PIXSTEP(0, 0, 1, 0);
  193. fi = PIXSTEP(lcd_dma.xres - 1, 1, 0, 0);
  194. }
  195. en = lcd_dma.xres;
  196. fn = lcd_dma.yres;
  197. break;
  198. case 270:
  199. if (!lcd_dma.mirror) {
  200. top = PIXADDR(lcd_dma.xres - 1, 0);
  201. bottom = PIXADDR(0, lcd_dma.yres - 1);
  202. ei = PIXSTEP(0, 0, 0, 1);
  203. fi = PIXSTEP(1, lcd_dma.yres - 1, 0, 0);
  204. } else {
  205. top = PIXADDR(0, 0);
  206. bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
  207. ei = PIXSTEP(0, 0, 0, 1);
  208. fi = PIXSTEP(0, lcd_dma.yres - 1, 1, 0);
  209. }
  210. en = lcd_dma.yres;
  211. fn = lcd_dma.xres;
  212. break;
  213. default:
  214. BUG();
  215. return; /* Suppress warning about uninitialized vars */
  216. }
  217. if (cpu_is_omap15xx()) {
  218. omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U);
  219. omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L);
  220. omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);
  221. omap_writew(bottom, OMAP1510_DMA_LCD_BOT_F1_L);
  222. return;
  223. }
  224. /* 1610 regs */
  225. omap_writew(top >> 16, OMAP1610_DMA_LCD_TOP_B1_U);
  226. omap_writew(top, OMAP1610_DMA_LCD_TOP_B1_L);
  227. omap_writew(bottom >> 16, OMAP1610_DMA_LCD_BOT_B1_U);
  228. omap_writew(bottom, OMAP1610_DMA_LCD_BOT_B1_L);
  229. omap_writew(en, OMAP1610_DMA_LCD_SRC_EN_B1);
  230. omap_writew(fn, OMAP1610_DMA_LCD_SRC_FN_B1);
  231. w = omap_readw(OMAP1610_DMA_LCD_CSDP);
  232. w &= ~0x03;
  233. w |= lcd_dma.data_type;
  234. omap_writew(w, OMAP1610_DMA_LCD_CSDP);
  235. w = omap_readw(OMAP1610_DMA_LCD_CTRL);
  236. /* Always set the source port as SDRAM for now*/
  237. w &= ~(0x03 << 6);
  238. if (lcd_dma.callback != NULL)
  239. w |= 1 << 1; /* Block interrupt enable */
  240. else
  241. w &= ~(1 << 1);
  242. omap_writew(w, OMAP1610_DMA_LCD_CTRL);
  243. if (!(lcd_dma.rotate || lcd_dma.mirror ||
  244. lcd_dma.vxres || lcd_dma.xscale || lcd_dma.yscale))
  245. return;
  246. w = omap_readw(OMAP1610_DMA_LCD_CCR);
  247. /* Set the double-indexed addressing mode */
  248. w |= (0x03 << 12);
  249. omap_writew(w, OMAP1610_DMA_LCD_CCR);
  250. omap_writew(ei, OMAP1610_DMA_LCD_SRC_EI_B1);
  251. omap_writew(fi >> 16, OMAP1610_DMA_LCD_SRC_FI_B1_U);
  252. omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L);
  253. }
  254. static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id)
  255. {
  256. u16 w;
  257. w = omap_readw(OMAP1610_DMA_LCD_CTRL);
  258. if (unlikely(!(w & (1 << 3)))) {
  259. printk(KERN_WARNING "Spurious LCD DMA IRQ\n");
  260. return IRQ_NONE;
  261. }
  262. /* Ack the IRQ */
  263. w |= (1 << 3);
  264. omap_writew(w, OMAP1610_DMA_LCD_CTRL);
  265. lcd_dma.active = 0;
  266. if (lcd_dma.callback != NULL)
  267. lcd_dma.callback(w, lcd_dma.cb_data);
  268. return IRQ_HANDLED;
  269. }
  270. int omap_request_lcd_dma(void (*callback)(u16 status, void *data),
  271. void *data)
  272. {
  273. spin_lock_irq(&lcd_dma.lock);
  274. if (lcd_dma.reserved) {
  275. spin_unlock_irq(&lcd_dma.lock);
  276. printk(KERN_ERR "LCD DMA channel already reserved\n");
  277. BUG();
  278. return -EBUSY;
  279. }
  280. lcd_dma.reserved = 1;
  281. spin_unlock_irq(&lcd_dma.lock);
  282. lcd_dma.callback = callback;
  283. lcd_dma.cb_data = data;
  284. lcd_dma.active = 0;
  285. lcd_dma.single_transfer = 0;
  286. lcd_dma.rotate = 0;
  287. lcd_dma.vxres = 0;
  288. lcd_dma.mirror = 0;
  289. lcd_dma.xscale = 0;
  290. lcd_dma.yscale = 0;
  291. lcd_dma.ext_ctrl = 0;
  292. lcd_dma.src_port = 0;
  293. return 0;
  294. }
  295. EXPORT_SYMBOL(omap_request_lcd_dma);
  296. void omap_free_lcd_dma(void)
  297. {
  298. spin_lock(&lcd_dma.lock);
  299. if (!lcd_dma.reserved) {
  300. spin_unlock(&lcd_dma.lock);
  301. printk(KERN_ERR "LCD DMA is not reserved\n");
  302. BUG();
  303. return;
  304. }
  305. if (!cpu_is_omap15xx())
  306. omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1,
  307. OMAP1610_DMA_LCD_CCR);
  308. lcd_dma.reserved = 0;
  309. spin_unlock(&lcd_dma.lock);
  310. }
  311. EXPORT_SYMBOL(omap_free_lcd_dma);
  312. void omap_enable_lcd_dma(void)
  313. {
  314. u16 w;
  315. /*
  316. * Set the Enable bit only if an external controller is
  317. * connected. Otherwise the OMAP internal controller will
  318. * start the transfer when it gets enabled.
  319. */
  320. if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
  321. return;
  322. w = omap_readw(OMAP1610_DMA_LCD_CTRL);
  323. w |= 1 << 8;
  324. omap_writew(w, OMAP1610_DMA_LCD_CTRL);
  325. lcd_dma.active = 1;
  326. w = omap_readw(OMAP1610_DMA_LCD_CCR);
  327. w |= 1 << 7;
  328. omap_writew(w, OMAP1610_DMA_LCD_CCR);
  329. }
  330. EXPORT_SYMBOL(omap_enable_lcd_dma);
  331. void omap_setup_lcd_dma(void)
  332. {
  333. BUG_ON(lcd_dma.active);
  334. if (!cpu_is_omap15xx()) {
  335. /* Set some reasonable defaults */
  336. omap_writew(0x5440, OMAP1610_DMA_LCD_CCR);
  337. omap_writew(0x9102, OMAP1610_DMA_LCD_CSDP);
  338. omap_writew(0x0004, OMAP1610_DMA_LCD_LCH_CTRL);
  339. }
  340. set_b1_regs();
  341. if (!cpu_is_omap15xx()) {
  342. u16 w;
  343. w = omap_readw(OMAP1610_DMA_LCD_CCR);
  344. /*
  345. * If DMA was already active set the end_prog bit to have
  346. * the programmed register set loaded into the active
  347. * register set.
  348. */
  349. w |= 1 << 11; /* End_prog */
  350. if (!lcd_dma.single_transfer)
  351. w |= (3 << 8); /* Auto_init, repeat */
  352. omap_writew(w, OMAP1610_DMA_LCD_CCR);
  353. }
  354. }
  355. EXPORT_SYMBOL(omap_setup_lcd_dma);
  356. void omap_stop_lcd_dma(void)
  357. {
  358. u16 w;
  359. lcd_dma.active = 0;
  360. if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
  361. return;
  362. w = omap_readw(OMAP1610_DMA_LCD_CCR);
  363. w &= ~(1 << 7);
  364. omap_writew(w, OMAP1610_DMA_LCD_CCR);
  365. w = omap_readw(OMAP1610_DMA_LCD_CTRL);
  366. w &= ~(1 << 8);
  367. omap_writew(w, OMAP1610_DMA_LCD_CTRL);
  368. }
  369. EXPORT_SYMBOL(omap_stop_lcd_dma);
  370. static int __init omap_init_lcd_dma(void)
  371. {
  372. int r;
  373. if (!cpu_class_is_omap1())
  374. return -ENODEV;
  375. if (cpu_is_omap16xx()) {
  376. u16 w;
  377. /* this would prevent OMAP sleep */
  378. w = omap_readw(OMAP1610_DMA_LCD_CTRL);
  379. w &= ~(1 << 8);
  380. omap_writew(w, OMAP1610_DMA_LCD_CTRL);
  381. }
  382. spin_lock_init(&lcd_dma.lock);
  383. r = request_threaded_irq(INT_DMA_LCD, NULL, lcd_dma_irq_handler,
  384. IRQF_ONESHOT, "LCD DMA", NULL);
  385. if (r != 0)
  386. pr_err("unable to request IRQ for LCD DMA (error %d)\n", r);
  387. return r;
  388. }
  389. arch_initcall(omap_init_lcd_dma);