mddi.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. /*
  2. * MSM MDDI Transport
  3. *
  4. * Copyright (C) 2007 Google Incorporated
  5. * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
  6. *
  7. * This software is licensed under the terms of the GNU General Public
  8. * License version 2, as published by the Free Software Foundation, and
  9. * may be copied, distributed, and modified under those terms.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. */
  17. #include <linux/module.h>
  18. #include <linux/kernel.h>
  19. #include <linux/sched.h>
  20. #include <linux/time.h>
  21. #include <linux/init.h>
  22. #include <linux/interrupt.h>
  23. #include <linux/spinlock.h>
  24. #include <linux/delay.h>
  25. #include <mach/hardware.h>
  26. #include <asm/io.h>
  27. #include <asm/system.h>
  28. #include <asm/mach-types.h>
  29. #include <linux/semaphore.h>
  30. #include <linux/uaccess.h>
  31. #include <linux/clk.h>
  32. #include <linux/platform_device.h>
  33. #include <linux/pm_runtime.h>
  34. #include "msm_fb.h"
  35. #include "mddihosti.h"
  36. #include "mddihost.h"
  37. #include <mach/gpio.h>
  38. #include <mach/clk.h>
  39. static int mddi_probe(struct platform_device *pdev);
  40. static int mddi_remove(struct platform_device *pdev);
  41. static int mddi_off(struct platform_device *pdev);
  42. static int mddi_on(struct platform_device *pdev);
  43. #ifdef CONFIG_PM
  44. static int mddi_suspend(struct platform_device *pdev, pm_message_t state);
  45. static int mddi_resume(struct platform_device *pdev);
  46. #endif
  47. #ifdef CONFIG_HAS_EARLYSUSPEND
  48. static void mddi_early_suspend(struct early_suspend *h);
  49. static void mddi_early_resume(struct early_suspend *h);
  50. #endif
  51. static void pmdh_clk_disable(void);
  52. static void pmdh_clk_enable(void);
  53. static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
  54. static int pdev_list_cnt;
  55. static struct clk *mddi_clk;
  56. static struct clk *mddi_pclk;
  57. static struct mddi_platform_data *mddi_pdata;
  58. DEFINE_MUTEX(mddi_timer_lock);
  59. static int mddi_runtime_suspend(struct device *dev)
  60. {
  61. dev_dbg(dev, "pm_runtime: suspending...\n");
  62. return 0;
  63. }
  64. static int mddi_runtime_resume(struct device *dev)
  65. {
  66. dev_dbg(dev, "pm_runtime: resuming...\n");
  67. return 0;
  68. }
  69. static int mddi_runtime_idle(struct device *dev)
  70. {
  71. dev_dbg(dev, "pm_runtime: idling...\n");
  72. return 0;
  73. }
  74. static struct dev_pm_ops mddi_dev_pm_ops = {
  75. .runtime_suspend = mddi_runtime_suspend,
  76. .runtime_resume = mddi_runtime_resume,
  77. .runtime_idle = mddi_runtime_idle,
  78. };
  79. static int pmdh_clk_status;
  80. int irq_enabled;
  81. unsigned char mddi_timer_shutdown_flag;
  82. static struct platform_driver mddi_driver = {
  83. .probe = mddi_probe,
  84. .remove = mddi_remove,
  85. #ifndef CONFIG_HAS_EARLYSUSPEND
  86. #ifdef CONFIG_PM
  87. .suspend = mddi_suspend,
  88. .resume = mddi_resume,
  89. #endif
  90. #endif
  91. .shutdown = NULL,
  92. .driver = {
  93. .name = "mddi",
  94. .pm = &mddi_dev_pm_ops,
  95. },
  96. };
  97. extern int int_mddi_pri_flag;
  98. DEFINE_MUTEX(pmdh_clk_lock);
  99. int pmdh_clk_func(int value)
  100. {
  101. int ret = 0;
  102. switch (value) {
  103. case 0:
  104. pmdh_clk_disable();
  105. break;
  106. case 1:
  107. pmdh_clk_enable();
  108. break;
  109. case 2:
  110. default:
  111. mutex_lock(&pmdh_clk_lock);
  112. ret = pmdh_clk_status;
  113. mutex_unlock(&pmdh_clk_lock);
  114. break;
  115. }
  116. return ret;
  117. }
  118. static void pmdh_clk_disable()
  119. {
  120. mutex_lock(&pmdh_clk_lock);
  121. if (pmdh_clk_status == 0) {
  122. mutex_unlock(&pmdh_clk_lock);
  123. return;
  124. }
  125. if (mddi_host_timer.function) {
  126. mutex_lock(&mddi_timer_lock);
  127. mddi_timer_shutdown_flag = 1;
  128. mutex_unlock(&mddi_timer_lock);
  129. del_timer_sync(&mddi_host_timer);
  130. mutex_lock(&mddi_timer_lock);
  131. mddi_timer_shutdown_flag = 0;
  132. mutex_unlock(&mddi_timer_lock);
  133. }
  134. if (int_mddi_pri_flag && irq_enabled) {
  135. disable_irq(INT_MDDI_PRI);
  136. irq_enabled = 0;
  137. }
  138. if (mddi_clk) {
  139. clk_disable_unprepare(mddi_clk);
  140. pmdh_clk_status = 0;
  141. }
  142. if (mddi_pclk)
  143. clk_disable_unprepare(mddi_pclk);
  144. mutex_unlock(&pmdh_clk_lock);
  145. }
  146. static void pmdh_clk_enable()
  147. {
  148. mutex_lock(&pmdh_clk_lock);
  149. if (pmdh_clk_status == 1) {
  150. mutex_unlock(&pmdh_clk_lock);
  151. return;
  152. }
  153. if (mddi_clk) {
  154. clk_prepare_enable(mddi_clk);
  155. pmdh_clk_status = 1;
  156. }
  157. if (mddi_pclk)
  158. clk_prepare_enable(mddi_pclk);
  159. if (int_mddi_pri_flag && !irq_enabled) {
  160. enable_irq(INT_MDDI_PRI);
  161. irq_enabled = 1;
  162. }
  163. if (mddi_host_timer.function)
  164. mddi_host_timer_service(0);
  165. mutex_unlock(&pmdh_clk_lock);
  166. }
  167. static int mddi_off(struct platform_device *pdev)
  168. {
  169. struct msm_fb_data_type *mfd;
  170. boolean dma_pending, dma_update_flag;
  171. int ret, i;
  172. mfd = platform_get_drvdata(pdev);
  173. for (i = 0; i < 6; i++) {
  174. dma_update_flag = mfd->dma_update_flag;
  175. dma_pending = mfd->dma->busy;
  176. if (dma_update_flag && !dma_pending)
  177. break;
  178. msleep(5);
  179. }
  180. pmdh_clk_enable();
  181. ret = panel_next_off(pdev);
  182. pmdh_clk_disable();
  183. if (mddi_pdata && mddi_pdata->mddi_power_save)
  184. mddi_pdata->mddi_power_save(0);
  185. #ifndef CONFIG_MSM_BUS_SCALING
  186. if (mfd->ebi1_clk)
  187. clk_disable_unprepare(mfd->ebi1_clk);
  188. #endif
  189. pm_runtime_put(&pdev->dev);
  190. return ret;
  191. }
  192. static int mddi_on(struct platform_device *pdev)
  193. {
  194. int ret = 0;
  195. u32 clk_rate;
  196. struct msm_fb_data_type *mfd;
  197. #ifdef ENABLE_FWD_LINK_SKEW_CALIBRATION
  198. mddi_host_type host_idx = MDDI_HOST_PRIM;
  199. u32 stat_reg;
  200. #endif
  201. mfd = platform_get_drvdata(pdev);
  202. pm_runtime_get(&pdev->dev);
  203. if (mddi_pdata && mddi_pdata->mddi_power_save)
  204. mddi_pdata->mddi_power_save(1);
  205. pmdh_clk_enable();
  206. #ifdef ENABLE_FWD_LINK_SKEW_CALIBRATION
  207. if (mddi_client_type < 2) {
  208. /* For skew calibration, clock should be less than 50MHz */
  209. clk_rate = clk_round_rate(mddi_clk, 49000000);
  210. if (!clk_set_rate(mddi_clk, clk_rate)) {
  211. stat_reg = mddi_host_reg_in(STAT);
  212. printk(KERN_DEBUG "\n stat_reg = 0x%x", stat_reg);
  213. mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE);
  214. if (stat_reg & (0x1 << 4))
  215. mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
  216. mddi_host_reg_out(CMD, MDDI_CMD_SEND_RTD);
  217. mddi_send_fw_link_skew_cal(host_idx);
  218. mddi_host_reg_out(CMD, MDDI_CMD_SEND_RTD);
  219. mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1);
  220. } else {
  221. printk(KERN_ERR "%s: clk_set_rate failed\n",
  222. __func__);
  223. }
  224. }
  225. #endif
  226. clk_rate = mfd->fbi->var.pixclock;
  227. clk_rate = min(clk_rate, mfd->panel_info.clk_max);
  228. if (mddi_pdata &&
  229. mddi_pdata->mddi_sel_clk &&
  230. mddi_pdata->mddi_sel_clk(&clk_rate))
  231. printk(KERN_ERR
  232. "%s: can't select mddi io clk targate rate = %d\n",
  233. __func__, clk_rate);
  234. clk_rate = clk_round_rate(mddi_clk, clk_rate);
  235. if (clk_set_rate(mddi_clk, clk_rate) < 0)
  236. printk(KERN_ERR "%s: clk_set_rate failed\n",
  237. __func__);
  238. #ifndef CONFIG_MSM_BUS_SCALING
  239. if (mfd->ebi1_clk)
  240. clk_prepare_enable(mfd->ebi1_clk);
  241. #endif
  242. ret = panel_next_on(pdev);
  243. return ret;
  244. }
  245. static int mddi_resource_initialized;
  246. static int mddi_probe(struct platform_device *pdev)
  247. {
  248. struct msm_fb_data_type *mfd;
  249. struct platform_device *mdp_dev = NULL;
  250. struct msm_fb_panel_data *pdata = NULL;
  251. int rc;
  252. resource_size_t size ;
  253. u32 clk_rate;
  254. unsigned long rate;
  255. int ret;
  256. struct clk *ebi1_clk = NULL;
  257. if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
  258. mddi_pdata = pdev->dev.platform_data;
  259. pmdh_clk_status = 0;
  260. mddi_clk = clk_get(&pdev->dev, "core_clk");
  261. if (IS_ERR(mddi_clk)) {
  262. pr_err("can't find mddi_clk\n");
  263. return PTR_ERR(mddi_clk);
  264. }
  265. rate = clk_round_rate(mddi_clk, 49000000);
  266. ret = clk_set_rate(mddi_clk, rate);
  267. if (ret)
  268. pr_err("Can't set mddi_clk min rate to %lu\n",
  269. rate);
  270. pr_info("mddi_clk init rate is %lu\n",
  271. clk_get_rate(mddi_clk));
  272. mddi_pclk = clk_get(&pdev->dev, "iface_clk");
  273. if (IS_ERR(mddi_pclk))
  274. mddi_pclk = NULL;
  275. pmdh_clk_enable();
  276. #ifndef CONFIG_MSM_BUS_SCALING
  277. ebi1_clk = clk_get(&pdev->dev, "mem_clk");
  278. if (IS_ERR(ebi1_clk))
  279. return PTR_ERR(ebi1_clk);
  280. clk_set_rate(ebi1_clk, 65000000);
  281. #endif
  282. size = resource_size(&pdev->resource[0]);
  283. msm_pmdh_base = ioremap(pdev->resource[0].start, size);
  284. MSM_FB_INFO("primary mddi base phy_addr = 0x%x virt = 0x%x\n",
  285. pdev->resource[0].start, (int) msm_pmdh_base);
  286. if (unlikely(!msm_pmdh_base))
  287. return -ENOMEM;
  288. if (mddi_pdata && mddi_pdata->mddi_power_save)
  289. mddi_pdata->mddi_power_save(1);
  290. mddi_resource_initialized = 1;
  291. return 0;
  292. }
  293. if (!mddi_resource_initialized)
  294. return -EPERM;
  295. mfd = platform_get_drvdata(pdev);
  296. mfd->ebi1_clk = ebi1_clk;
  297. if (!mfd)
  298. return -ENODEV;
  299. if (mfd->key != MFD_KEY)
  300. return -EINVAL;
  301. if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
  302. return -ENOMEM;
  303. mdp_dev = platform_device_alloc("mdp", pdev->id);
  304. if (!mdp_dev)
  305. return -ENOMEM;
  306. /*
  307. * link to the latest pdev
  308. */
  309. mfd->pdev = mdp_dev;
  310. mfd->dest = DISPLAY_LCD;
  311. /*
  312. * alloc panel device data
  313. */
  314. if (platform_device_add_data
  315. (mdp_dev, pdev->dev.platform_data,
  316. sizeof(struct msm_fb_panel_data))) {
  317. printk(KERN_ERR "mddi_probe: platform_device_add_data failed!\n");
  318. platform_device_put(mdp_dev);
  319. return -ENOMEM;
  320. }
  321. /*
  322. * data chain
  323. */
  324. pdata = mdp_dev->dev.platform_data;
  325. pdata->on = mddi_on;
  326. pdata->off = mddi_off;
  327. pdata->next = pdev;
  328. pdata->clk_func = pmdh_clk_func;
  329. /*
  330. * get/set panel specific fb info
  331. */
  332. mfd->panel_info = pdata->panel_info;
  333. if (mfd->index == 0)
  334. mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
  335. else
  336. mfd->fb_imgType = MDP_RGB_565;
  337. clk_rate = mfd->panel_info.clk_max;
  338. if (mddi_pdata &&
  339. mddi_pdata->mddi_sel_clk &&
  340. mddi_pdata->mddi_sel_clk(&clk_rate))
  341. printk(KERN_ERR
  342. "%s: can't select mddi io clk targate rate = %d\n",
  343. __func__, clk_rate);
  344. if (clk_set_max_rate(mddi_clk, clk_rate) < 0)
  345. printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
  346. mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
  347. if (!mddi_client_type)
  348. mddi_client_type = mfd->panel_info.lcd.rev;
  349. else if (!mfd->panel_info.lcd.rev)
  350. printk(KERN_ERR
  351. "%s: mddi client is trying to revert back to type 1 !!!\n",
  352. __func__);
  353. /*
  354. * set driver data
  355. */
  356. platform_set_drvdata(mdp_dev, mfd);
  357. rc = pm_runtime_set_active(&pdev->dev);
  358. if (rc < 0)
  359. printk(KERN_ERR "pm_runtime: fail to set active\n");
  360. rc = 0;
  361. pm_runtime_enable(&pdev->dev);
  362. /*
  363. * register in mdp driver
  364. */
  365. rc = platform_device_add(mdp_dev);
  366. if (rc)
  367. goto mddi_probe_err;
  368. pdev_list[pdev_list_cnt++] = pdev;
  369. #ifdef CONFIG_HAS_EARLYSUSPEND
  370. mfd->mddi_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
  371. mfd->mddi_early_suspend.suspend = mddi_early_suspend;
  372. mfd->mddi_early_suspend.resume = mddi_early_resume;
  373. register_early_suspend(&mfd->mddi_early_suspend);
  374. #endif
  375. return 0;
  376. mddi_probe_err:
  377. platform_device_put(mdp_dev);
  378. return rc;
  379. }
  380. static int mddi_pad_ctrl;
  381. static int mddi_power_locked;
  382. int mddi_client_power(unsigned int client_id)
  383. {
  384. int ret = 0;
  385. if (mddi_pdata && mddi_pdata->mddi_client_power)
  386. ret = mddi_pdata->mddi_client_power(client_id);
  387. return ret;
  388. }
  389. void mddi_disable(int lock)
  390. {
  391. mddi_host_type host_idx = MDDI_HOST_PRIM;
  392. if (mddi_power_locked)
  393. return;
  394. if (lock)
  395. mddi_power_locked = 1;
  396. pmdh_clk_enable();
  397. mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL);
  398. mddi_host_reg_out(PAD_CTL, 0x0);
  399. pmdh_clk_disable();
  400. if (mddi_pdata && mddi_pdata->mddi_power_save)
  401. mddi_pdata->mddi_power_save(0);
  402. }
  403. #ifdef CONFIG_PM
  404. static int mddi_is_in_suspend;
  405. static int mddi_suspend(struct platform_device *pdev, pm_message_t state)
  406. {
  407. mddi_host_type host_idx = MDDI_HOST_PRIM;
  408. if (mddi_is_in_suspend)
  409. return 0;
  410. mddi_is_in_suspend = 1;
  411. if (mddi_power_locked)
  412. return 0;
  413. pmdh_clk_enable();
  414. mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL);
  415. mddi_host_reg_out(PAD_CTL, 0x0);
  416. pmdh_clk_disable();
  417. return 0;
  418. }
  419. static int mddi_resume(struct platform_device *pdev)
  420. {
  421. mddi_host_type host_idx = MDDI_HOST_PRIM;
  422. if (!mddi_is_in_suspend)
  423. return 0;
  424. mddi_is_in_suspend = 0;
  425. if (mddi_power_locked)
  426. return 0;
  427. pmdh_clk_enable();
  428. mddi_host_reg_out(PAD_CTL, mddi_pad_ctrl);
  429. return 0;
  430. }
  431. #endif
  432. #ifdef CONFIG_HAS_EARLYSUSPEND
  433. static void mddi_early_suspend(struct early_suspend *h)
  434. {
  435. pm_message_t state;
  436. struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
  437. mddi_early_suspend);
  438. state.event = PM_EVENT_SUSPEND;
  439. mddi_suspend(mfd->pdev, state);
  440. }
  441. static void mddi_early_resume(struct early_suspend *h)
  442. {
  443. struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
  444. mddi_early_suspend);
  445. mddi_resume(mfd->pdev);
  446. }
  447. #endif
  448. static int mddi_remove(struct platform_device *pdev)
  449. {
  450. pm_runtime_disable(&pdev->dev);
  451. if (mddi_host_timer.function) {
  452. mutex_lock(&mddi_timer_lock);
  453. mddi_timer_shutdown_flag = 1;
  454. mutex_unlock(&mddi_timer_lock);
  455. del_timer_sync(&mddi_host_timer);
  456. mutex_lock(&mddi_timer_lock);
  457. mddi_timer_shutdown_flag = 0;
  458. mutex_unlock(&mddi_timer_lock);
  459. }
  460. iounmap(msm_pmdh_base);
  461. return 0;
  462. }
  463. static int mddi_register_driver(void)
  464. {
  465. return platform_driver_register(&mddi_driver);
  466. }
  467. static int __init mddi_driver_init(void)
  468. {
  469. int ret;
  470. ret = mddi_register_driver();
  471. if (ret) {
  472. pmdh_clk_disable();
  473. clk_put(mddi_clk);
  474. if (mddi_pclk)
  475. clk_put(mddi_pclk);
  476. printk(KERN_ERR "mddi_register_driver() failed!\n");
  477. return ret;
  478. }
  479. mddi_init();
  480. return ret;
  481. }
  482. module_init(mddi_driver_init);