lvds.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/sched.h>
  16. #include <linux/time.h>
  17. #include <linux/init.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/spinlock.h>
  20. #include <linux/delay.h>
  21. #include <linux/io.h>
  22. #include <mach/hardware.h>
  23. #include <mach/msm_iomap.h>
  24. #include <mach/clk.h>
  25. #include <asm/system.h>
  26. #include <asm/mach-types.h>
  27. #include <linux/semaphore.h>
  28. #include <linux/uaccess.h>
  29. #include <linux/clk.h>
  30. #include <linux/platform_device.h>
  31. #include <linux/regulator/consumer.h>
  32. #include "msm_fb.h"
  33. #include "mdp4.h"
  34. #define LVDS_PIXEL_MAP_PATTERN_2 2
  35. static int lvds_probe(struct platform_device *pdev);
  36. static int lvds_remove(struct platform_device *pdev);
  37. static int lvds_off(struct platform_device *pdev);
  38. static int lvds_on(struct platform_device *pdev);
  39. static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
  40. static int pdev_list_cnt;
  41. static struct clk *lvds_clk;
  42. static struct platform_driver lvds_driver = {
  43. .probe = lvds_probe,
  44. .remove = lvds_remove,
  45. .suspend = NULL,
  46. .resume = NULL,
  47. .shutdown = NULL,
  48. .driver = {
  49. .name = "lvds",
  50. },
  51. };
  52. static struct lcdc_platform_data *lvds_pdata;
  53. static void lvds_init(struct msm_fb_data_type *mfd)
  54. {
  55. unsigned int lvds_intf = 0, lvds_phy_cfg0 = 0;
  56. MDP_OUTP(MDP_BASE + 0xc2034, 0x33);
  57. usleep(1000);
  58. /* LVDS PHY PLL configuration */
  59. if (mfd->panel_info.clk_rate == 74250000) {
  60. MDP_OUTP(MDP_BASE + 0xc3000, 0x08);
  61. MDP_OUTP(MDP_BASE + 0xc3004, 0x4c);
  62. MDP_OUTP(MDP_BASE + 0xc3008, 0x30);
  63. MDP_OUTP(MDP_BASE + 0xc300c, 0xc3);
  64. MDP_OUTP(MDP_BASE + 0xc3014, 0x10);
  65. MDP_OUTP(MDP_BASE + 0xc3018, 0x04);
  66. MDP_OUTP(MDP_BASE + 0xc301c, 0x62);
  67. MDP_OUTP(MDP_BASE + 0xc3020, 0x41);
  68. MDP_OUTP(MDP_BASE + 0xc3024, 0x0d);
  69. MDP_OUTP(MDP_BASE + 0xc3028, 0x07);
  70. MDP_OUTP(MDP_BASE + 0xc302c, 0x00);
  71. MDP_OUTP(MDP_BASE + 0xc3030, 0x1c);
  72. MDP_OUTP(MDP_BASE + 0xc3034, 0x01);
  73. MDP_OUTP(MDP_BASE + 0xc3038, 0x00);
  74. MDP_OUTP(MDP_BASE + 0xc3040, 0xC0);
  75. MDP_OUTP(MDP_BASE + 0xc3044, 0x00);
  76. MDP_OUTP(MDP_BASE + 0xc3048, 0x30);
  77. MDP_OUTP(MDP_BASE + 0xc304c, 0x00);
  78. MDP_OUTP(MDP_BASE + 0xc3000, 0x11);
  79. MDP_OUTP(MDP_BASE + 0xc3064, 0x05);
  80. MDP_OUTP(MDP_BASE + 0xc3050, 0x20);
  81. } else {
  82. MDP_OUTP(MDP_BASE + 0xc3004, 0x8f);
  83. MDP_OUTP(MDP_BASE + 0xc3008, 0x30);
  84. MDP_OUTP(MDP_BASE + 0xc300c, 0xc6);
  85. MDP_OUTP(MDP_BASE + 0xc3014, 0x10);
  86. MDP_OUTP(MDP_BASE + 0xc3018, 0x07);
  87. MDP_OUTP(MDP_BASE + 0xc301c, 0x62);
  88. MDP_OUTP(MDP_BASE + 0xc3020, 0x41);
  89. MDP_OUTP(MDP_BASE + 0xc3024, 0x0d);
  90. }
  91. MDP_OUTP(MDP_BASE + 0xc3000, 0x01);
  92. /* Wait until LVDS PLL is locked and ready */
  93. while (!readl_relaxed(MDP_BASE + 0xc3080))
  94. cpu_relax();
  95. writel_relaxed(0x00, mmss_cc_base + 0x0264);
  96. writel_relaxed(0x00, mmss_cc_base + 0x0094);
  97. writel_relaxed(0x02, mmss_cc_base + 0x00E4);
  98. writel_relaxed((0x80 | readl_relaxed(mmss_cc_base + 0x00E4)),
  99. mmss_cc_base + 0x00E4);
  100. usleep(1000);
  101. writel_relaxed((~0x80 & readl_relaxed(mmss_cc_base + 0x00E4)),
  102. mmss_cc_base + 0x00E4);
  103. writel_relaxed(0x05, mmss_cc_base + 0x0094);
  104. writel_relaxed(0x02, mmss_cc_base + 0x0264);
  105. /* Wait until LVDS pixel clock output is enabled */
  106. mb();
  107. if (mfd->panel_info.bpp == 24) {
  108. if (lvds_pdata &&
  109. lvds_pdata->lvds_pixel_remap &&
  110. lvds_pdata->lvds_pixel_remap()) {
  111. if (lvds_pdata->lvds_pixel_remap() ==
  112. LVDS_PIXEL_MAP_PATTERN_2) {
  113. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
  114. MDP_OUTP(MDP_BASE + 0xc2014, 0x070A1B1B);
  115. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
  116. MDP_OUTP(MDP_BASE + 0xc2018, 0x00040506);
  117. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
  118. MDP_OUTP(MDP_BASE + 0xc201c, 0x12131B1B);
  119. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
  120. MDP_OUTP(MDP_BASE + 0xc2020, 0x000B0C0D);
  121. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
  122. MDP_OUTP(MDP_BASE + 0xc2024, 0x191A1B1B);
  123. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
  124. MDP_OUTP(MDP_BASE + 0xc2028, 0x00141518);
  125. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
  126. MDP_OUTP(MDP_BASE + 0xc202c, 0x171B1B1B);
  127. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
  128. MDP_OUTP(MDP_BASE + 0xc2030, 0x000e0f16);
  129. } else {
  130. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
  131. MDP_OUTP(MDP_BASE + 0xc2014, 0x05080001);
  132. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
  133. MDP_OUTP(MDP_BASE + 0xc2018, 0x00020304);
  134. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
  135. MDP_OUTP(MDP_BASE + 0xc201c, 0x1011090a);
  136. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
  137. MDP_OUTP(MDP_BASE + 0xc2020, 0x000b0c0d);
  138. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
  139. MDP_OUTP(MDP_BASE + 0xc2024, 0x191a1213);
  140. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
  141. MDP_OUTP(MDP_BASE + 0xc2028, 0x00141518);
  142. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
  143. MDP_OUTP(MDP_BASE + 0xc202c, 0x171b0607);
  144. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
  145. MDP_OUTP(MDP_BASE + 0xc2030, 0x000e0f16);
  146. }
  147. } else {
  148. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
  149. MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508);
  150. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
  151. MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102);
  152. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
  153. MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011);
  154. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
  155. MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b);
  156. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
  157. MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a);
  158. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
  159. MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
  160. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
  161. MDP_OUTP(MDP_BASE + 0xc202c, 0x0f16171b);
  162. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
  163. MDP_OUTP(MDP_BASE + 0xc2030, 0x0006070e);
  164. }
  165. if (mfd->panel_info.lvds.channel_mode ==
  166. LVDS_DUAL_CHANNEL_MODE) {
  167. lvds_intf = 0x0003ff80;
  168. lvds_phy_cfg0 = BIT(6) | BIT(7);
  169. if (mfd->panel_info.lvds.channel_swap)
  170. lvds_intf |= BIT(4);
  171. } else {
  172. lvds_intf = 0x00010f84;
  173. lvds_phy_cfg0 = BIT(6);
  174. }
  175. } else if (mfd->panel_info.bpp == 18) {
  176. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
  177. MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508);
  178. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
  179. MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102);
  180. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
  181. MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011);
  182. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
  183. MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b);
  184. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
  185. MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a);
  186. /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
  187. MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
  188. if (mfd->panel_info.lvds.channel_mode ==
  189. LVDS_DUAL_CHANNEL_MODE) {
  190. lvds_intf = 0x00037788;
  191. lvds_phy_cfg0 = BIT(6) | BIT(7);
  192. if (mfd->panel_info.lvds.channel_swap)
  193. lvds_intf |= BIT(4);
  194. } else {
  195. lvds_intf = 0x0001078c;
  196. lvds_phy_cfg0 = BIT(6);
  197. }
  198. } else {
  199. BUG();
  200. }
  201. /* MDP_LVDSPHY_CFG0 */
  202. MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0);
  203. /* MDP_LCDC_LVDS_INTF_CTL */
  204. MDP_OUTP(MDP_BASE + 0xc2000, lvds_intf);
  205. MDP_OUTP(MDP_BASE + 0xc3108, 0x30);
  206. lvds_phy_cfg0 |= BIT(4);
  207. /* Wait until LVDS PHY registers are configured */
  208. mb();
  209. usleep(1);
  210. /* MDP_LVDSPHY_CFG0, enable serialization */
  211. MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0);
  212. }
  213. static int lvds_off(struct platform_device *pdev)
  214. {
  215. int ret = 0;
  216. struct msm_fb_data_type *mfd;
  217. mfd = platform_get_drvdata(pdev);
  218. ret = panel_next_off(pdev);
  219. if (lvds_clk)
  220. clk_disable_unprepare(lvds_clk);
  221. MDP_OUTP(MDP_BASE + 0xc3100, 0x0);
  222. MDP_OUTP(MDP_BASE + 0xc3000, 0x0);
  223. usleep(10);
  224. if (lvds_pdata && lvds_pdata->lcdc_power_save)
  225. lvds_pdata->lcdc_power_save(0);
  226. if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
  227. ret = lvds_pdata->lcdc_gpio_config(0);
  228. return ret;
  229. }
  230. static int lvds_on(struct platform_device *pdev)
  231. {
  232. int ret = 0;
  233. struct msm_fb_data_type *mfd;
  234. unsigned long panel_pixclock_freq = 0;
  235. mfd = platform_get_drvdata(pdev);
  236. if (lvds_pdata && lvds_pdata->lcdc_get_clk)
  237. panel_pixclock_freq = lvds_pdata->lcdc_get_clk();
  238. if (!panel_pixclock_freq)
  239. panel_pixclock_freq = mfd->fbi->var.pixclock;
  240. mfd = platform_get_drvdata(pdev);
  241. if (lvds_clk) {
  242. mfd->fbi->var.pixclock = clk_round_rate(lvds_clk,
  243. mfd->fbi->var.pixclock);
  244. ret = clk_set_rate(lvds_clk, mfd->fbi->var.pixclock);
  245. if (ret) {
  246. pr_err("%s: Can't set lvds clock to rate %u\n",
  247. __func__, mfd->fbi->var.pixclock);
  248. goto out;
  249. }
  250. clk_prepare_enable(lvds_clk);
  251. }
  252. if (lvds_pdata && lvds_pdata->lcdc_power_save)
  253. lvds_pdata->lcdc_power_save(1);
  254. if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
  255. ret = lvds_pdata->lcdc_gpio_config(1);
  256. lvds_init(mfd);
  257. ret = panel_next_on(pdev);
  258. out:
  259. return ret;
  260. }
  261. static int lvds_probe(struct platform_device *pdev)
  262. {
  263. struct msm_fb_data_type *mfd;
  264. struct fb_info *fbi;
  265. struct platform_device *mdp_dev = NULL;
  266. struct msm_fb_panel_data *pdata = NULL;
  267. int rc;
  268. if (pdev->id == 0) {
  269. lvds_pdata = pdev->dev.platform_data;
  270. lvds_clk = clk_get(&pdev->dev, "lvds_clk");
  271. if (IS_ERR_OR_NULL(lvds_clk)) {
  272. pr_err("Couldnt find lvds_clk\n");
  273. lvds_clk = NULL;
  274. }
  275. return 0;
  276. }
  277. mfd = platform_get_drvdata(pdev);
  278. if (!mfd)
  279. return -ENODEV;
  280. if (mfd->key != MFD_KEY)
  281. return -EINVAL;
  282. if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
  283. return -ENOMEM;
  284. mdp_dev = platform_device_alloc("mdp", pdev->id);
  285. if (!mdp_dev)
  286. return -ENOMEM;
  287. /*
  288. * link to the latest pdev
  289. */
  290. mfd->pdev = mdp_dev;
  291. mfd->dest = DISPLAY_LCDC;
  292. /*
  293. * alloc panel device data
  294. */
  295. if (platform_device_add_data
  296. (mdp_dev, pdev->dev.platform_data,
  297. sizeof(struct msm_fb_panel_data))) {
  298. pr_err("lvds_probe: platform_device_add_data failed!\n");
  299. platform_device_put(mdp_dev);
  300. return -ENOMEM;
  301. }
  302. /*
  303. * data chain
  304. */
  305. pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data;
  306. pdata->on = lvds_on;
  307. pdata->off = lvds_off;
  308. pdata->next = pdev;
  309. /*
  310. * get/set panel specific fb info
  311. */
  312. mfd->panel_info = pdata->panel_info;
  313. if (mfd->index == 0)
  314. mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
  315. else
  316. mfd->fb_imgType = MDP_RGB_565;
  317. fbi = mfd->fbi;
  318. if (lvds_clk) {
  319. fbi->var.pixclock = clk_round_rate(lvds_clk,
  320. mfd->panel_info.clk_rate);
  321. }
  322. fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
  323. fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
  324. fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
  325. fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
  326. fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
  327. fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
  328. /*
  329. * set driver data
  330. */
  331. platform_set_drvdata(mdp_dev, mfd);
  332. /*
  333. * register in mdp driver
  334. */
  335. rc = platform_device_add(mdp_dev);
  336. if (rc)
  337. goto lvds_probe_err;
  338. pdev_list[pdev_list_cnt++] = pdev;
  339. return 0;
  340. lvds_probe_err:
  341. platform_device_put(mdp_dev);
  342. return rc;
  343. }
  344. static int lvds_remove(struct platform_device *pdev)
  345. {
  346. return 0;
  347. }
  348. static int lvds_register_driver(void)
  349. {
  350. return platform_driver_register(&lvds_driver);
  351. }
  352. static int __init lvds_driver_init(void)
  353. {
  354. return lvds_register_driver();
  355. }
  356. module_init(lvds_driver_init);