dpi.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * linux/drivers/video/omap2/dss/dpi.c
  3. *
  4. * Copyright (C) 2009 Nokia Corporation
  5. * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
  6. *
  7. * Some code and ideas taken from drivers/video/omap/ driver
  8. * by Imre Deak.
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License version 2 as published by
  12. * the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  17. * more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along with
  20. * this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #define DSS_SUBSYS_NAME "DPI"
  23. #include <linux/kernel.h>
  24. #include <linux/clk.h>
  25. #include <linux/delay.h>
  26. #include <linux/errno.h>
  27. #include <plat/display.h>
  28. #include <plat/cpu.h>
  29. #include "dss.h"
  30. static struct {
  31. int update_enabled;
  32. } dpi;
  33. #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
  34. static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
  35. unsigned long *fck, int *lck_div, int *pck_div)
  36. {
  37. struct dsi_clock_info dsi_cinfo;
  38. struct dispc_clock_info dispc_cinfo;
  39. int r;
  40. r = dsi_pll_calc_clock_div_pck(is_tft, pck_req, &dsi_cinfo,
  41. &dispc_cinfo);
  42. if (r)
  43. return r;
  44. r = dsi_pll_set_clock_div(&dsi_cinfo);
  45. if (r)
  46. return r;
  47. dss_select_clk_source(0, 1);
  48. r = dispc_set_clock_div(&dispc_cinfo);
  49. if (r)
  50. return r;
  51. *fck = dsi_cinfo.dsi1_pll_fclk;
  52. *lck_div = dispc_cinfo.lck_div;
  53. *pck_div = dispc_cinfo.pck_div;
  54. return 0;
  55. }
  56. #else
  57. static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
  58. unsigned long *fck, int *lck_div, int *pck_div)
  59. {
  60. struct dss_clock_info dss_cinfo;
  61. struct dispc_clock_info dispc_cinfo;
  62. int r;
  63. r = dss_calc_clock_div(is_tft, pck_req, &dss_cinfo, &dispc_cinfo);
  64. if (r)
  65. return r;
  66. r = dss_set_clock_div(&dss_cinfo);
  67. if (r)
  68. return r;
  69. r = dispc_set_clock_div(&dispc_cinfo);
  70. if (r)
  71. return r;
  72. *fck = dss_cinfo.fck;
  73. *lck_div = dispc_cinfo.lck_div;
  74. *pck_div = dispc_cinfo.pck_div;
  75. return 0;
  76. }
  77. #endif
  78. static int dpi_set_mode(struct omap_dss_device *dssdev)
  79. {
  80. struct omap_video_timings *t = &dssdev->panel.timings;
  81. int lck_div, pck_div;
  82. unsigned long fck;
  83. unsigned long pck;
  84. bool is_tft;
  85. int r = 0;
  86. dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
  87. dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
  88. dssdev->panel.acb);
  89. is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
  90. #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
  91. r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
  92. &fck, &lck_div, &pck_div);
  93. #else
  94. r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
  95. &fck, &lck_div, &pck_div);
  96. #endif
  97. if (r)
  98. goto err0;
  99. pck = fck / lck_div / pck_div / 1000;
  100. if (pck != t->pixel_clock) {
  101. DSSWARN("Could not find exact pixel clock. "
  102. "Requested %d kHz, got %lu kHz\n",
  103. t->pixel_clock, pck);
  104. t->pixel_clock = pck;
  105. }
  106. dispc_set_lcd_timings(t);
  107. err0:
  108. dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
  109. return r;
  110. }
  111. static int dpi_basic_init(struct omap_dss_device *dssdev)
  112. {
  113. bool is_tft;
  114. is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
  115. dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
  116. dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
  117. OMAP_DSS_LCD_DISPLAY_STN);
  118. dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
  119. return 0;
  120. }
  121. static int dpi_display_enable(struct omap_dss_device *dssdev)
  122. {
  123. int r;
  124. r = omap_dss_start_device(dssdev);
  125. if (r) {
  126. DSSERR("failed to start device\n");
  127. goto err0;
  128. }
  129. if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
  130. DSSERR("display already enabled\n");
  131. r = -EINVAL;
  132. goto err1;
  133. }
  134. dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
  135. r = dpi_basic_init(dssdev);
  136. if (r)
  137. goto err2;
  138. #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
  139. dss_clk_enable(DSS_CLK_FCK2);
  140. r = dsi_pll_init(dssdev, 0, 1);
  141. if (r)
  142. goto err3;
  143. #endif
  144. r = dpi_set_mode(dssdev);
  145. if (r)
  146. goto err4;
  147. mdelay(2);
  148. dispc_enable_lcd_out(1);
  149. r = dssdev->driver->enable(dssdev);
  150. if (r)
  151. goto err5;
  152. dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
  153. return 0;
  154. err5:
  155. dispc_enable_lcd_out(0);
  156. err4:
  157. #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
  158. dsi_pll_uninit();
  159. err3:
  160. dss_clk_disable(DSS_CLK_FCK2);
  161. #endif
  162. err2:
  163. dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
  164. err1:
  165. omap_dss_stop_device(dssdev);
  166. err0:
  167. return r;
  168. }
  169. static int dpi_display_resume(struct omap_dss_device *dssdev);
  170. static void dpi_display_disable(struct omap_dss_device *dssdev)
  171. {
  172. if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
  173. return;
  174. if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
  175. dpi_display_resume(dssdev);
  176. dssdev->driver->disable(dssdev);
  177. dispc_enable_lcd_out(0);
  178. #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
  179. dss_select_clk_source(0, 0);
  180. dsi_pll_uninit();
  181. dss_clk_disable(DSS_CLK_FCK2);
  182. #endif
  183. dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
  184. dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
  185. omap_dss_stop_device(dssdev);
  186. }
  187. static int dpi_display_suspend(struct omap_dss_device *dssdev)
  188. {
  189. if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
  190. return -EINVAL;
  191. DSSDBG("dpi_display_suspend\n");
  192. if (dssdev->driver->suspend)
  193. dssdev->driver->suspend(dssdev);
  194. dispc_enable_lcd_out(0);
  195. dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
  196. dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
  197. return 0;
  198. }
  199. static int dpi_display_resume(struct omap_dss_device *dssdev)
  200. {
  201. if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
  202. return -EINVAL;
  203. DSSDBG("dpi_display_resume\n");
  204. dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
  205. dispc_enable_lcd_out(1);
  206. if (dssdev->driver->resume)
  207. dssdev->driver->resume(dssdev);
  208. dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
  209. return 0;
  210. }
  211. static void dpi_set_timings(struct omap_dss_device *dssdev,
  212. struct omap_video_timings *timings)
  213. {
  214. DSSDBG("dpi_set_timings\n");
  215. dssdev->panel.timings = *timings;
  216. if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
  217. dpi_set_mode(dssdev);
  218. dispc_go(OMAP_DSS_CHANNEL_LCD);
  219. }
  220. }
  221. static int dpi_check_timings(struct omap_dss_device *dssdev,
  222. struct omap_video_timings *timings)
  223. {
  224. bool is_tft;
  225. int r;
  226. int lck_div, pck_div;
  227. unsigned long fck;
  228. unsigned long pck;
  229. if (!dispc_lcd_timings_ok(timings))
  230. return -EINVAL;
  231. if (timings->pixel_clock == 0)
  232. return -EINVAL;
  233. is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
  234. #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
  235. {
  236. struct dsi_clock_info dsi_cinfo;
  237. struct dispc_clock_info dispc_cinfo;
  238. r = dsi_pll_calc_clock_div_pck(is_tft,
  239. timings->pixel_clock * 1000,
  240. &dsi_cinfo, &dispc_cinfo);
  241. if (r)
  242. return r;
  243. fck = dsi_cinfo.dsi1_pll_fclk;
  244. lck_div = dispc_cinfo.lck_div;
  245. pck_div = dispc_cinfo.pck_div;
  246. }
  247. #else
  248. {
  249. struct dss_clock_info dss_cinfo;
  250. struct dispc_clock_info dispc_cinfo;
  251. r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000,
  252. &dss_cinfo, &dispc_cinfo);
  253. if (r)
  254. return r;
  255. fck = dss_cinfo.fck;
  256. lck_div = dispc_cinfo.lck_div;
  257. pck_div = dispc_cinfo.pck_div;
  258. }
  259. #endif
  260. pck = fck / lck_div / pck_div / 1000;
  261. timings->pixel_clock = pck;
  262. return 0;
  263. }
  264. static void dpi_get_timings(struct omap_dss_device *dssdev,
  265. struct omap_video_timings *timings)
  266. {
  267. *timings = dssdev->panel.timings;
  268. }
  269. static int dpi_display_set_update_mode(struct omap_dss_device *dssdev,
  270. enum omap_dss_update_mode mode)
  271. {
  272. if (mode == OMAP_DSS_UPDATE_MANUAL)
  273. return -EINVAL;
  274. if (mode == OMAP_DSS_UPDATE_DISABLED) {
  275. dispc_enable_lcd_out(0);
  276. dpi.update_enabled = 0;
  277. } else {
  278. dispc_enable_lcd_out(1);
  279. dpi.update_enabled = 1;
  280. }
  281. return 0;
  282. }
  283. static enum omap_dss_update_mode dpi_display_get_update_mode(
  284. struct omap_dss_device *dssdev)
  285. {
  286. return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
  287. OMAP_DSS_UPDATE_DISABLED;
  288. }
  289. int dpi_init_display(struct omap_dss_device *dssdev)
  290. {
  291. DSSDBG("init_display\n");
  292. dssdev->enable = dpi_display_enable;
  293. dssdev->disable = dpi_display_disable;
  294. dssdev->suspend = dpi_display_suspend;
  295. dssdev->resume = dpi_display_resume;
  296. dssdev->set_timings = dpi_set_timings;
  297. dssdev->check_timings = dpi_check_timings;
  298. dssdev->get_timings = dpi_get_timings;
  299. dssdev->set_update_mode = dpi_display_set_update_mode;
  300. dssdev->get_update_mode = dpi_display_get_update_mode;
  301. return 0;
  302. }
  303. int dpi_init(void)
  304. {
  305. return 0;
  306. }
  307. void dpi_exit(void)
  308. {
  309. }