lcdc.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * OMAP1 internal LCD controller
  4. *
  5. * Copyright (C) 2004 Nokia Corporation
  6. * Author: Imre Deak <[email protected]>
  7. */
  8. #include <linux/module.h>
  9. #include <linux/device.h>
  10. #include <linux/interrupt.h>
  11. #include <linux/spinlock.h>
  12. #include <linux/err.h>
  13. #include <linux/mm.h>
  14. #include <linux/fb.h>
  15. #include <linux/dma-mapping.h>
  16. #include <linux/vmalloc.h>
  17. #include <linux/clk.h>
  18. #include <linux/gfp.h>
  19. #include <linux/soc/ti/omap1-io.h>
  20. #include <linux/soc/ti/omap1-soc.h>
  21. #include <linux/omap-dma.h>
  22. #include <asm/mach-types.h>
  23. #include "omapfb.h"
  24. #include "lcdc.h"
  25. #include "lcd_dma.h"
  26. #define MODULE_NAME "lcdc"
  27. #define MAX_PALETTE_SIZE PAGE_SIZE
  28. enum lcdc_load_mode {
  29. OMAP_LCDC_LOAD_PALETTE,
  30. OMAP_LCDC_LOAD_FRAME,
  31. OMAP_LCDC_LOAD_PALETTE_AND_FRAME
  32. };
  33. static struct omap_lcd_controller {
  34. enum omapfb_update_mode update_mode;
  35. int ext_mode;
  36. unsigned long frame_offset;
  37. int screen_width;
  38. int xres;
  39. int yres;
  40. enum omapfb_color_format color_mode;
  41. int bpp;
  42. void *palette_virt;
  43. dma_addr_t palette_phys;
  44. int palette_code;
  45. int palette_size;
  46. unsigned int irq_mask;
  47. struct completion last_frame_complete;
  48. struct completion palette_load_complete;
  49. struct clk *lcd_ck;
  50. struct omapfb_device *fbdev;
  51. void (*dma_callback)(void *data);
  52. void *dma_callback_data;
  53. dma_addr_t vram_phys;
  54. void *vram_virt;
  55. unsigned long vram_size;
  56. } lcdc;
  57. static inline void enable_irqs(int mask)
  58. {
  59. lcdc.irq_mask |= mask;
  60. }
  61. static inline void disable_irqs(int mask)
  62. {
  63. lcdc.irq_mask &= ~mask;
  64. }
  65. static void set_load_mode(enum lcdc_load_mode mode)
  66. {
  67. u32 l;
  68. l = omap_readl(OMAP_LCDC_CONTROL);
  69. l &= ~(3 << 20);
  70. switch (mode) {
  71. case OMAP_LCDC_LOAD_PALETTE:
  72. l |= 1 << 20;
  73. break;
  74. case OMAP_LCDC_LOAD_FRAME:
  75. l |= 2 << 20;
  76. break;
  77. case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
  78. break;
  79. default:
  80. BUG();
  81. }
  82. omap_writel(l, OMAP_LCDC_CONTROL);
  83. }
  84. static void enable_controller(void)
  85. {
  86. u32 l;
  87. l = omap_readl(OMAP_LCDC_CONTROL);
  88. l |= OMAP_LCDC_CTRL_LCD_EN;
  89. l &= ~OMAP_LCDC_IRQ_MASK;
  90. l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */
  91. omap_writel(l, OMAP_LCDC_CONTROL);
  92. }
  93. static void disable_controller_async(void)
  94. {
  95. u32 l;
  96. u32 mask;
  97. l = omap_readl(OMAP_LCDC_CONTROL);
  98. mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
  99. /*
  100. * Preserve the DONE mask, since we still want to get the
  101. * final DONE irq. It will be disabled in the IRQ handler.
  102. */
  103. mask &= ~OMAP_LCDC_IRQ_DONE;
  104. l &= ~mask;
  105. omap_writel(l, OMAP_LCDC_CONTROL);
  106. }
  107. static void disable_controller(void)
  108. {
  109. init_completion(&lcdc.last_frame_complete);
  110. disable_controller_async();
  111. if (!wait_for_completion_timeout(&lcdc.last_frame_complete,
  112. msecs_to_jiffies(500)))
  113. dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
  114. }
  115. static void reset_controller(u32 status)
  116. {
  117. static unsigned long reset_count;
  118. static unsigned long last_jiffies;
  119. disable_controller_async();
  120. reset_count++;
  121. if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) {
  122. dev_err(lcdc.fbdev->dev,
  123. "resetting (status %#010x,reset count %lu)\n",
  124. status, reset_count);
  125. last_jiffies = jiffies;
  126. }
  127. if (reset_count < 100) {
  128. enable_controller();
  129. } else {
  130. reset_count = 0;
  131. dev_err(lcdc.fbdev->dev,
  132. "too many reset attempts, giving up.\n");
  133. }
  134. }
  135. /*
  136. * Configure the LCD DMA according to the current mode specified by parameters
  137. * in lcdc.fbdev and fbdev->var.
  138. */
  139. static void setup_lcd_dma(void)
  140. {
  141. static const int dma_elem_type[] = {
  142. 0,
  143. OMAP_DMA_DATA_TYPE_S8,
  144. OMAP_DMA_DATA_TYPE_S16,
  145. 0,
  146. OMAP_DMA_DATA_TYPE_S32,
  147. };
  148. struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par;
  149. struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
  150. unsigned long src;
  151. int esize, xelem, yelem;
  152. src = lcdc.vram_phys + lcdc.frame_offset;
  153. switch (var->rotate) {
  154. case 0:
  155. if (plane->info.mirror || (src & 3) ||
  156. lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
  157. (lcdc.xres & 1))
  158. esize = 2;
  159. else
  160. esize = 4;
  161. xelem = lcdc.xres * lcdc.bpp / 8 / esize;
  162. yelem = lcdc.yres;
  163. break;
  164. case 90:
  165. case 180:
  166. case 270:
  167. if (cpu_is_omap15xx()) {
  168. BUG();
  169. }
  170. esize = 2;
  171. xelem = lcdc.yres * lcdc.bpp / 16;
  172. yelem = lcdc.xres;
  173. break;
  174. default:
  175. BUG();
  176. return;
  177. }
  178. #ifdef VERBOSE
  179. dev_dbg(lcdc.fbdev->dev,
  180. "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
  181. src, esize, xelem, yelem);
  182. #endif
  183. omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
  184. if (!cpu_is_omap15xx()) {
  185. int bpp = lcdc.bpp;
  186. /*
  187. * YUV support is only for external mode when we have the
  188. * YUV window embedded in a 16bpp frame buffer.
  189. */
  190. if (lcdc.color_mode == OMAPFB_COLOR_YUV420)
  191. bpp = 16;
  192. /* Set virtual xres elem size */
  193. omap_set_lcd_dma_b1_vxres(
  194. lcdc.screen_width * bpp / 8 / esize);
  195. /* Setup transformations */
  196. omap_set_lcd_dma_b1_rotation(var->rotate);
  197. omap_set_lcd_dma_b1_mirror(plane->info.mirror);
  198. }
  199. omap_setup_lcd_dma();
  200. }
  201. static irqreturn_t lcdc_irq_handler(int irq, void *dev_id)
  202. {
  203. u32 status;
  204. status = omap_readl(OMAP_LCDC_STATUS);
  205. if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
  206. reset_controller(status);
  207. else {
  208. if (status & OMAP_LCDC_STAT_DONE) {
  209. u32 l;
  210. /*
  211. * Disable IRQ_DONE. The status bit will be cleared
  212. * only when the controller is reenabled and we don't
  213. * want to get more interrupts.
  214. */
  215. l = omap_readl(OMAP_LCDC_CONTROL);
  216. l &= ~OMAP_LCDC_IRQ_DONE;
  217. omap_writel(l, OMAP_LCDC_CONTROL);
  218. complete(&lcdc.last_frame_complete);
  219. }
  220. if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
  221. disable_controller_async();
  222. complete(&lcdc.palette_load_complete);
  223. }
  224. }
  225. /*
  226. * Clear these interrupt status bits.
  227. * Sync_lost, FUF bits were cleared by disabling the LCD controller
  228. * LOADED_PALETTE can be cleared this way only in palette only
  229. * load mode. In other load modes it's cleared by disabling the
  230. * controller.
  231. */
  232. status &= ~(OMAP_LCDC_STAT_VSYNC |
  233. OMAP_LCDC_STAT_LOADED_PALETTE |
  234. OMAP_LCDC_STAT_ABC |
  235. OMAP_LCDC_STAT_LINE_INT);
  236. omap_writel(status, OMAP_LCDC_STATUS);
  237. return IRQ_HANDLED;
  238. }
  239. /*
  240. * Change to a new video mode. We defer this to a later time to avoid any
  241. * flicker and not to mess up the current LCD DMA context. For this we disable
  242. * the LCD controller, which will generate a DONE irq after the last frame has
  243. * been transferred. Then it'll be safe to reconfigure both the LCD controller
  244. * as well as the LCD DMA.
  245. */
  246. static int omap_lcdc_setup_plane(int plane, int channel_out,
  247. unsigned long offset, int screen_width,
  248. int pos_x, int pos_y, int width, int height,
  249. int color_mode)
  250. {
  251. struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
  252. struct lcd_panel *panel = lcdc.fbdev->panel;
  253. int rot_x, rot_y;
  254. if (var->rotate == 0) {
  255. rot_x = panel->x_res;
  256. rot_y = panel->y_res;
  257. } else {
  258. rot_x = panel->y_res;
  259. rot_y = panel->x_res;
  260. }
  261. if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
  262. width > rot_x || height > rot_y) {
  263. #ifdef VERBOSE
  264. dev_dbg(lcdc.fbdev->dev,
  265. "invalid plane params plane %d pos_x %d pos_y %d "
  266. "w %d h %d\n", plane, pos_x, pos_y, width, height);
  267. #endif
  268. return -EINVAL;
  269. }
  270. lcdc.frame_offset = offset;
  271. lcdc.xres = width;
  272. lcdc.yres = height;
  273. lcdc.screen_width = screen_width;
  274. lcdc.color_mode = color_mode;
  275. switch (color_mode) {
  276. case OMAPFB_COLOR_CLUT_8BPP:
  277. lcdc.bpp = 8;
  278. lcdc.palette_code = 0x3000;
  279. lcdc.palette_size = 512;
  280. break;
  281. case OMAPFB_COLOR_RGB565:
  282. lcdc.bpp = 16;
  283. lcdc.palette_code = 0x4000;
  284. lcdc.palette_size = 32;
  285. break;
  286. case OMAPFB_COLOR_RGB444:
  287. lcdc.bpp = 16;
  288. lcdc.palette_code = 0x4000;
  289. lcdc.palette_size = 32;
  290. break;
  291. case OMAPFB_COLOR_YUV420:
  292. if (lcdc.ext_mode) {
  293. lcdc.bpp = 12;
  294. break;
  295. }
  296. fallthrough;
  297. case OMAPFB_COLOR_YUV422:
  298. if (lcdc.ext_mode) {
  299. lcdc.bpp = 16;
  300. break;
  301. }
  302. fallthrough;
  303. default:
  304. /* FIXME: other BPPs.
  305. * bpp1: code 0, size 256
  306. * bpp2: code 0x1000 size 256
  307. * bpp4: code 0x2000 size 256
  308. * bpp12: code 0x4000 size 32
  309. */
  310. dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode);
  311. BUG();
  312. return -1;
  313. }
  314. if (lcdc.ext_mode) {
  315. setup_lcd_dma();
  316. return 0;
  317. }
  318. if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
  319. disable_controller();
  320. omap_stop_lcd_dma();
  321. setup_lcd_dma();
  322. enable_controller();
  323. }
  324. return 0;
  325. }
  326. static int omap_lcdc_enable_plane(int plane, int enable)
  327. {
  328. dev_dbg(lcdc.fbdev->dev,
  329. "plane %d enable %d update_mode %d ext_mode %d\n",
  330. plane, enable, lcdc.update_mode, lcdc.ext_mode);
  331. if (plane != OMAPFB_PLANE_GFX)
  332. return -EINVAL;
  333. return 0;
  334. }
  335. /*
  336. * Configure the LCD DMA for a palette load operation and do the palette
  337. * downloading synchronously. We don't use the frame+palette load mode of
  338. * the controller, since the palette can always be downloaded separately.
  339. */
  340. static void load_palette(void)
  341. {
  342. u16 *palette;
  343. palette = (u16 *)lcdc.palette_virt;
  344. *(u16 *)palette &= 0x0fff;
  345. *(u16 *)palette |= lcdc.palette_code;
  346. omap_set_lcd_dma_b1(lcdc.palette_phys,
  347. lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
  348. omap_set_lcd_dma_single_transfer(1);
  349. omap_setup_lcd_dma();
  350. init_completion(&lcdc.palette_load_complete);
  351. enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
  352. set_load_mode(OMAP_LCDC_LOAD_PALETTE);
  353. enable_controller();
  354. if (!wait_for_completion_timeout(&lcdc.palette_load_complete,
  355. msecs_to_jiffies(500)))
  356. dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
  357. /* The controller gets disabled in the irq handler */
  358. disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
  359. omap_stop_lcd_dma();
  360. omap_set_lcd_dma_single_transfer(lcdc.ext_mode);
  361. }
  362. /* Used only in internal controller mode */
  363. static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
  364. u16 transp, int update_hw_pal)
  365. {
  366. u16 *palette;
  367. if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
  368. return -EINVAL;
  369. palette = (u16 *)lcdc.palette_virt;
  370. palette[regno] &= ~0x0fff;
  371. palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
  372. (blue >> 12);
  373. if (update_hw_pal) {
  374. disable_controller();
  375. omap_stop_lcd_dma();
  376. load_palette();
  377. setup_lcd_dma();
  378. set_load_mode(OMAP_LCDC_LOAD_FRAME);
  379. enable_controller();
  380. }
  381. return 0;
  382. }
  383. static void calc_ck_div(int is_tft, int pck, int *pck_div)
  384. {
  385. unsigned long lck;
  386. pck = max(1, pck);
  387. lck = clk_get_rate(lcdc.lcd_ck);
  388. *pck_div = (lck + pck - 1) / pck;
  389. if (is_tft)
  390. *pck_div = max(2, *pck_div);
  391. else
  392. *pck_div = max(3, *pck_div);
  393. if (*pck_div > 255) {
  394. /* FIXME: try to adjust logic clock divider as well */
  395. *pck_div = 255;
  396. dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n",
  397. pck / 1000);
  398. }
  399. }
  400. static inline void setup_regs(void)
  401. {
  402. u32 l;
  403. struct lcd_panel *panel = lcdc.fbdev->panel;
  404. int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
  405. unsigned long lck;
  406. int pcd;
  407. l = omap_readl(OMAP_LCDC_CONTROL);
  408. l &= ~OMAP_LCDC_CTRL_LCD_TFT;
  409. l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
  410. #ifdef CONFIG_MACH_OMAP_PALMTE
  411. /* FIXME:if (machine_is_omap_palmte()) { */
  412. /* PalmTE uses alternate TFT setting in 8BPP mode */
  413. l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0;
  414. /* } */
  415. #endif
  416. omap_writel(l, OMAP_LCDC_CONTROL);
  417. l = omap_readl(OMAP_LCDC_TIMING2);
  418. l &= ~(((1 << 6) - 1) << 20);
  419. l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;
  420. omap_writel(l, OMAP_LCDC_TIMING2);
  421. l = panel->x_res - 1;
  422. l |= (panel->hsw - 1) << 10;
  423. l |= (panel->hfp - 1) << 16;
  424. l |= (panel->hbp - 1) << 24;
  425. omap_writel(l, OMAP_LCDC_TIMING0);
  426. l = panel->y_res - 1;
  427. l |= (panel->vsw - 1) << 10;
  428. l |= panel->vfp << 16;
  429. l |= panel->vbp << 24;
  430. omap_writel(l, OMAP_LCDC_TIMING1);
  431. l = omap_readl(OMAP_LCDC_TIMING2);
  432. l &= ~0xff;
  433. lck = clk_get_rate(lcdc.lcd_ck);
  434. if (!panel->pcd)
  435. calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);
  436. else {
  437. dev_warn(lcdc.fbdev->dev,
  438. "Pixel clock divider value is obsolete.\n"
  439. "Try to set pixel_clock to %lu and pcd to 0 "
  440. "in drivers/video/omap/lcd_%s.c and submit a patch.\n",
  441. lck / panel->pcd / 1000, panel->name);
  442. pcd = panel->pcd;
  443. }
  444. l |= pcd & 0xff;
  445. l |= panel->acb << 8;
  446. omap_writel(l, OMAP_LCDC_TIMING2);
  447. /* update panel info with the exact clock */
  448. panel->pixel_clock = lck / pcd / 1000;
  449. }
  450. /*
  451. * Configure the LCD controller, download the color palette and start a looped
  452. * DMA transfer of the frame image data. Called only in internal
  453. * controller mode.
  454. */
  455. static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
  456. {
  457. int r = 0;
  458. if (mode != lcdc.update_mode) {
  459. switch (mode) {
  460. case OMAPFB_AUTO_UPDATE:
  461. setup_regs();
  462. load_palette();
  463. /* Setup and start LCD DMA */
  464. setup_lcd_dma();
  465. set_load_mode(OMAP_LCDC_LOAD_FRAME);
  466. enable_irqs(OMAP_LCDC_IRQ_DONE);
  467. /* This will start the actual DMA transfer */
  468. enable_controller();
  469. lcdc.update_mode = mode;
  470. break;
  471. case OMAPFB_UPDATE_DISABLED:
  472. disable_controller();
  473. omap_stop_lcd_dma();
  474. lcdc.update_mode = mode;
  475. break;
  476. default:
  477. r = -EINVAL;
  478. }
  479. }
  480. return r;
  481. }
  482. static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
  483. {
  484. return lcdc.update_mode;
  485. }
  486. /* PM code called only in internal controller mode */
  487. static void omap_lcdc_suspend(void)
  488. {
  489. omap_lcdc_set_update_mode(OMAPFB_UPDATE_DISABLED);
  490. }
  491. static void omap_lcdc_resume(void)
  492. {
  493. omap_lcdc_set_update_mode(OMAPFB_AUTO_UPDATE);
  494. }
  495. static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps)
  496. {
  497. return;
  498. }
  499. int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
  500. {
  501. BUG_ON(callback == NULL);
  502. if (lcdc.dma_callback)
  503. return -EBUSY;
  504. else {
  505. lcdc.dma_callback = callback;
  506. lcdc.dma_callback_data = data;
  507. }
  508. return 0;
  509. }
  510. EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
  511. void omap_lcdc_free_dma_callback(void)
  512. {
  513. lcdc.dma_callback = NULL;
  514. }
  515. EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
  516. static void lcdc_dma_handler(u16 status, void *data)
  517. {
  518. if (lcdc.dma_callback)
  519. lcdc.dma_callback(lcdc.dma_callback_data);
  520. }
  521. static int alloc_palette_ram(void)
  522. {
  523. lcdc.palette_virt = dma_alloc_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE,
  524. &lcdc.palette_phys, GFP_KERNEL);
  525. if (lcdc.palette_virt == NULL) {
  526. dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n");
  527. return -ENOMEM;
  528. }
  529. memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
  530. return 0;
  531. }
  532. static void free_palette_ram(void)
  533. {
  534. dma_free_wc(lcdc.fbdev->dev, MAX_PALETTE_SIZE, lcdc.palette_virt,
  535. lcdc.palette_phys);
  536. }
  537. static int alloc_fbmem(struct omapfb_mem_region *region)
  538. {
  539. int bpp;
  540. int frame_size;
  541. struct lcd_panel *panel = lcdc.fbdev->panel;
  542. bpp = panel->bpp;
  543. if (bpp == 12)
  544. bpp = 16;
  545. frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res);
  546. if (region->size > frame_size)
  547. frame_size = region->size;
  548. lcdc.vram_size = frame_size;
  549. lcdc.vram_virt = dma_alloc_wc(lcdc.fbdev->dev, lcdc.vram_size,
  550. &lcdc.vram_phys, GFP_KERNEL);
  551. if (lcdc.vram_virt == NULL) {
  552. dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n");
  553. return -ENOMEM;
  554. }
  555. region->size = frame_size;
  556. region->paddr = lcdc.vram_phys;
  557. region->vaddr = lcdc.vram_virt;
  558. region->alloc = 1;
  559. memset(lcdc.vram_virt, 0, lcdc.vram_size);
  560. return 0;
  561. }
  562. static void free_fbmem(void)
  563. {
  564. dma_free_wc(lcdc.fbdev->dev, lcdc.vram_size, lcdc.vram_virt,
  565. lcdc.vram_phys);
  566. }
  567. static int setup_fbmem(struct omapfb_mem_desc *req_md)
  568. {
  569. if (!req_md->region_cnt) {
  570. dev_err(lcdc.fbdev->dev, "no memory regions defined\n");
  571. return -EINVAL;
  572. }
  573. if (req_md->region_cnt > 1) {
  574. dev_err(lcdc.fbdev->dev, "only one plane is supported\n");
  575. req_md->region_cnt = 1;
  576. }
  577. return alloc_fbmem(&req_md->region[0]);
  578. }
  579. static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
  580. struct omapfb_mem_desc *req_vram)
  581. {
  582. int r;
  583. u32 l;
  584. int rate;
  585. struct clk *tc_ck;
  586. lcdc.irq_mask = 0;
  587. lcdc.fbdev = fbdev;
  588. lcdc.ext_mode = ext_mode;
  589. l = 0;
  590. omap_writel(l, OMAP_LCDC_CONTROL);
  591. /* FIXME:
  592. * According to errata some platforms have a clock rate limitiation
  593. */
  594. lcdc.lcd_ck = clk_get(fbdev->dev, "lcd_ck");
  595. if (IS_ERR(lcdc.lcd_ck)) {
  596. dev_err(fbdev->dev, "unable to access LCD clock\n");
  597. r = PTR_ERR(lcdc.lcd_ck);
  598. goto fail0;
  599. }
  600. tc_ck = clk_get(fbdev->dev, "tc_ck");
  601. if (IS_ERR(tc_ck)) {
  602. dev_err(fbdev->dev, "unable to access TC clock\n");
  603. r = PTR_ERR(tc_ck);
  604. goto fail1;
  605. }
  606. rate = clk_get_rate(tc_ck);
  607. clk_put(tc_ck);
  608. if (machine_is_ams_delta())
  609. rate /= 4;
  610. if (machine_is_omap_h3())
  611. rate /= 3;
  612. r = clk_set_rate(lcdc.lcd_ck, rate);
  613. if (r) {
  614. dev_err(fbdev->dev, "failed to adjust LCD rate\n");
  615. goto fail1;
  616. }
  617. clk_prepare_enable(lcdc.lcd_ck);
  618. r = request_irq(fbdev->int_irq, lcdc_irq_handler, 0, MODULE_NAME, fbdev);
  619. if (r) {
  620. dev_err(fbdev->dev, "unable to get IRQ\n");
  621. goto fail2;
  622. }
  623. r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
  624. if (r) {
  625. dev_err(fbdev->dev, "unable to get LCD DMA\n");
  626. goto fail3;
  627. }
  628. omap_set_lcd_dma_single_transfer(ext_mode);
  629. omap_set_lcd_dma_ext_controller(ext_mode);
  630. if (!ext_mode)
  631. if ((r = alloc_palette_ram()) < 0)
  632. goto fail4;
  633. if ((r = setup_fbmem(req_vram)) < 0)
  634. goto fail5;
  635. pr_info("omapfb: LCDC initialized\n");
  636. return 0;
  637. fail5:
  638. if (!ext_mode)
  639. free_palette_ram();
  640. fail4:
  641. omap_free_lcd_dma();
  642. fail3:
  643. free_irq(fbdev->int_irq, lcdc.fbdev);
  644. fail2:
  645. clk_disable_unprepare(lcdc.lcd_ck);
  646. fail1:
  647. clk_put(lcdc.lcd_ck);
  648. fail0:
  649. return r;
  650. }
  651. static void omap_lcdc_cleanup(void)
  652. {
  653. if (!lcdc.ext_mode)
  654. free_palette_ram();
  655. free_fbmem();
  656. omap_free_lcd_dma();
  657. free_irq(lcdc.fbdev->int_irq, lcdc.fbdev);
  658. clk_disable_unprepare(lcdc.lcd_ck);
  659. clk_put(lcdc.lcd_ck);
  660. }
  661. const struct lcd_ctrl omap1_int_ctrl = {
  662. .name = "internal",
  663. .init = omap_lcdc_init,
  664. .cleanup = omap_lcdc_cleanup,
  665. .get_caps = omap_lcdc_get_caps,
  666. .set_update_mode = omap_lcdc_set_update_mode,
  667. .get_update_mode = omap_lcdc_get_update_mode,
  668. .update_window = NULL,
  669. .suspend = omap_lcdc_suspend,
  670. .resume = omap_lcdc_resume,
  671. .setup_plane = omap_lcdc_setup_plane,
  672. .enable_plane = omap_lcdc_enable_plane,
  673. .setcolreg = omap_lcdc_setcolreg,
  674. };