lcdc.c 19 KB

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