msm_dss_io_8x60.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. /* Copyright (c) 2008-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/clk.h>
  14. #include <mach/clk.h>
  15. #include "msm_fb.h"
  16. #include "mipi_dsi.h"
  17. #include "hdmi_msm.h"
  18. #include <mach/msm_iomap.h>
  19. /* multimedia sub system clock control */
  20. char *mmss_cc_base = MSM_MMSS_CLK_CTL_BASE;
  21. /* multimedia sub system sfpb */
  22. char *mmss_sfpb_base;
  23. void __iomem *periph_base;
  24. static struct dsi_clk_desc dsicore_clk;
  25. static struct dsi_clk_desc dsi_pclk;
  26. static struct clk *dsi_byte_div_clk;
  27. static struct clk *dsi_esc_clk;
  28. static struct clk *dsi_m_pclk;
  29. static struct clk *dsi_s_pclk;
  30. static struct clk *amp_pclk;
  31. int mipi_dsi_clk_on;
  32. int mipi_dsi_clk_init(struct platform_device *pdev)
  33. {
  34. struct device *dev = &pdev->dev;
  35. amp_pclk = clk_get(dev, "arb_clk");
  36. if (IS_ERR_OR_NULL(amp_pclk)) {
  37. pr_err("can't find amp_pclk\n");
  38. amp_pclk = NULL;
  39. goto mipi_dsi_clk_err;
  40. }
  41. dsi_m_pclk = clk_get(dev, "master_iface_clk");
  42. if (IS_ERR_OR_NULL(dsi_m_pclk)) {
  43. pr_err("can't find dsi_m_pclk\n");
  44. dsi_m_pclk = NULL;
  45. goto mipi_dsi_clk_err;
  46. }
  47. dsi_s_pclk = clk_get(dev, "slave_iface_clk");
  48. if (IS_ERR_OR_NULL(dsi_s_pclk)) {
  49. pr_err("can't find dsi_s_pclk\n");
  50. dsi_s_pclk = NULL;
  51. goto mipi_dsi_clk_err;
  52. }
  53. dsi_byte_div_clk = clk_get(dev, "byte_clk");
  54. if (IS_ERR_OR_NULL(dsi_byte_div_clk)) {
  55. pr_err("can't find dsi_byte_div_clk\n");
  56. dsi_byte_div_clk = NULL;
  57. goto mipi_dsi_clk_err;
  58. }
  59. dsi_esc_clk = clk_get(dev, "esc_clk");
  60. if (IS_ERR_OR_NULL(dsi_esc_clk)) {
  61. printk(KERN_ERR "can't find dsi_esc_clk\n");
  62. dsi_esc_clk = NULL;
  63. goto mipi_dsi_clk_err;
  64. }
  65. return 0;
  66. mipi_dsi_clk_err:
  67. mipi_dsi_clk_deinit(NULL);
  68. return -EPERM;
  69. }
  70. void mipi_dsi_clk_deinit(struct device *dev)
  71. {
  72. if (amp_pclk)
  73. clk_put(amp_pclk);
  74. if (dsi_m_pclk)
  75. clk_put(dsi_m_pclk);
  76. if (dsi_s_pclk)
  77. clk_put(dsi_s_pclk);
  78. if (dsi_byte_div_clk)
  79. clk_put(dsi_byte_div_clk);
  80. if (dsi_esc_clk)
  81. clk_put(dsi_esc_clk);
  82. }
  83. static void mipi_dsi_clk_ctrl(struct dsi_clk_desc *clk, int clk_en)
  84. {
  85. char *cc, *ns, *md;
  86. int pmxo_sel = 0;
  87. char mnd_en = 1, root_en = 1;
  88. uint32 data, val;
  89. cc = mmss_cc_base + 0x004c;
  90. md = mmss_cc_base + 0x0050;
  91. ns = mmss_cc_base + 0x0054;
  92. if (clk_en) {
  93. if (clk->mnd_mode == 0) {
  94. data = clk->pre_div_func << 14;
  95. data |= clk->src;
  96. MIPI_OUTP_SECURE(ns, data);
  97. MIPI_OUTP_SECURE(cc, ((pmxo_sel << 8)
  98. | (clk->mnd_mode << 6)
  99. | (root_en << 2) | clk_en));
  100. } else {
  101. val = clk->d * 2;
  102. data = (~val) & 0x0ff;
  103. data |= clk->m << 8;
  104. MIPI_OUTP_SECURE(md, data);
  105. val = clk->n - clk->m;
  106. data = (~val) & 0x0ff;
  107. data <<= 24;
  108. data |= clk->src;
  109. MIPI_OUTP_SECURE(ns, data);
  110. MIPI_OUTP_SECURE(cc, ((pmxo_sel << 8)
  111. | (clk->mnd_mode << 6)
  112. | (mnd_en << 5)
  113. | (root_en << 2) | clk_en));
  114. }
  115. } else
  116. MIPI_OUTP_SECURE(cc, 0);
  117. wmb();
  118. }
  119. static void mipi_dsi_sfpb_cfg(void)
  120. {
  121. char *sfpb;
  122. int data;
  123. sfpb = mmss_sfpb_base + 0x058;
  124. data = MIPI_INP(sfpb);
  125. data |= 0x01800;
  126. MIPI_OUTP(sfpb, data);
  127. wmb();
  128. }
  129. static void mipi_dsi_pclk_ctrl(struct dsi_clk_desc *clk, int clk_en)
  130. {
  131. char *cc, *ns, *md;
  132. char mnd_en = 1, root_en = 1;
  133. uint32 data, val;
  134. cc = mmss_cc_base + 0x0130;
  135. md = mmss_cc_base + 0x0134;
  136. ns = mmss_cc_base + 0x0138;
  137. if (clk_en) {
  138. if (clk->mnd_mode == 0) {
  139. data = clk->pre_div_func << 12;
  140. data |= clk->src;
  141. MIPI_OUTP_SECURE(ns, data);
  142. MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6)
  143. | (root_en << 2) | clk_en));
  144. } else {
  145. val = clk->d * 2;
  146. data = (~val) & 0x0ff;
  147. data |= clk->m << 8;
  148. MIPI_OUTP_SECURE(md, data);
  149. val = clk->n - clk->m;
  150. data = (~val) & 0x0ff;
  151. data <<= 24;
  152. data |= clk->src;
  153. MIPI_OUTP_SECURE(ns, data);
  154. MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6)
  155. | (mnd_en << 5)
  156. | (root_en << 2) | clk_en));
  157. }
  158. } else
  159. MIPI_OUTP_SECURE(cc, 0);
  160. wmb();
  161. }
  162. static void mipi_dsi_ahb_en(void)
  163. {
  164. char *ahb;
  165. ahb = mmss_cc_base + 0x08;
  166. pr_debug("%s: ahb=%x %x\n",
  167. __func__, (int) ahb, MIPI_INP_SECURE(ahb));
  168. }
  169. static void mipi_dsi_calibration(void)
  170. {
  171. uint32 data;
  172. MIPI_OUTP(MIPI_DSI_BASE + 0xf4, 0x0000ff11); /* cal_ctrl */
  173. MIPI_OUTP(MIPI_DSI_BASE + 0xf0, 0x01); /* cal_hw_trigger */
  174. while (1) {
  175. data = MIPI_INP(MIPI_DSI_BASE + 0xfc); /* cal_status */
  176. if ((data & 0x10000000) == 0)
  177. break;
  178. udelay(10);
  179. }
  180. }
  181. #define PREF_DIV_RATIO 27
  182. struct dsiphy_pll_divider_config pll_divider_config;
  183. int mipi_dsi_phy_pll_config(u32 clk_rate)
  184. {
  185. struct dsiphy_pll_divider_config *dividers;
  186. u32 fb_divider, tmp;
  187. dividers = &pll_divider_config;
  188. /* DSIPHY_PLL_CTRL_x: 1 2 3 8 9 10 */
  189. /* masks 0xff 0x07 0x3f 0x0f 0xff 0xff */
  190. /* DSIPHY_PLL_CTRL_1 */
  191. fb_divider = ((dividers->fb_divider) / 2) - 1;
  192. MIPI_OUTP(MIPI_DSI_BASE + 0x204, fb_divider & 0xff);
  193. /* DSIPHY_PLL_CTRL_2 */
  194. tmp = MIPI_INP(MIPI_DSI_BASE + 0x208);
  195. tmp &= ~0x07;
  196. tmp |= (fb_divider >> 8) & 0x07;
  197. MIPI_OUTP(MIPI_DSI_BASE + 0x208, tmp);
  198. /* DSIPHY_PLL_CTRL_3 */
  199. tmp = MIPI_INP(MIPI_DSI_BASE + 0x20c);
  200. tmp &= ~0x3f;
  201. tmp |= (dividers->ref_divider_ratio - 1) & 0x3f;
  202. MIPI_OUTP(MIPI_DSI_BASE + 0x20c, tmp);
  203. /* DSIPHY_PLL_CTRL_8 */
  204. tmp = MIPI_INP(MIPI_DSI_BASE + 0x220);
  205. tmp &= ~0x0f;
  206. tmp |= (dividers->bit_clk_divider - 1) & 0x0f;
  207. MIPI_OUTP(MIPI_DSI_BASE + 0x220, tmp);
  208. /* DSIPHY_PLL_CTRL_9 */
  209. MIPI_OUTP(MIPI_DSI_BASE + 0x224, (dividers->byte_clk_divider - 1));
  210. /* DSIPHY_PLL_CTRL_10 */
  211. MIPI_OUTP(MIPI_DSI_BASE + 0x228, (dividers->dsi_clk_divider - 1));
  212. return 0;
  213. }
  214. int mipi_dsi_clk_div_config(uint8 bpp, uint8 lanes,
  215. uint32 *expected_dsi_pclk)
  216. {
  217. u32 fb_divider, rate, vco;
  218. u32 div_ratio = 0;
  219. struct dsi_clk_mnd_table const *mnd_entry = mnd_table;
  220. if (pll_divider_config.clk_rate == 0)
  221. pll_divider_config.clk_rate = 454000000;
  222. rate = pll_divider_config.clk_rate / 1000000; /* In Mhz */
  223. if (rate < 125) {
  224. vco = rate * 8;
  225. div_ratio = 8;
  226. } else if (rate < 250) {
  227. vco = rate * 4;
  228. div_ratio = 4;
  229. } else if (rate < 500) {
  230. vco = rate * 2;
  231. div_ratio = 2;
  232. } else {
  233. vco = rate * 1;
  234. div_ratio = 1;
  235. }
  236. /* find the mnd settings from mnd_table entry */
  237. for (; mnd_entry != mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) {
  238. if (((mnd_entry->lanes) == lanes) &&
  239. ((mnd_entry->bpp) == bpp))
  240. break;
  241. }
  242. if (mnd_entry == mnd_table + ARRAY_SIZE(mnd_table)) {
  243. pr_err("%s: requested Lanes, %u & BPP, %u, not supported\n",
  244. __func__, lanes, bpp);
  245. return -EINVAL;
  246. }
  247. fb_divider = ((vco * PREF_DIV_RATIO) / 27);
  248. pll_divider_config.fb_divider = fb_divider;
  249. pll_divider_config.ref_divider_ratio = PREF_DIV_RATIO;
  250. pll_divider_config.bit_clk_divider = div_ratio;
  251. pll_divider_config.byte_clk_divider =
  252. pll_divider_config.bit_clk_divider * 8;
  253. pll_divider_config.dsi_clk_divider =
  254. (mnd_entry->dsiclk_div) * div_ratio;
  255. if ((mnd_entry->dsiclk_d == 0)
  256. || (mnd_entry->dsiclk_m == 1)) {
  257. dsicore_clk.mnd_mode = 0;
  258. dsicore_clk.src = 0x3;
  259. dsicore_clk.pre_div_func = (mnd_entry->dsiclk_n - 1);
  260. } else {
  261. dsicore_clk.mnd_mode = 2;
  262. dsicore_clk.src = 0x3;
  263. dsicore_clk.m = mnd_entry->dsiclk_m;
  264. dsicore_clk.n = mnd_entry->dsiclk_n;
  265. dsicore_clk.d = mnd_entry->dsiclk_d;
  266. }
  267. if ((mnd_entry->pclk_d == 0)
  268. || (mnd_entry->pclk_m == 1)) {
  269. dsi_pclk.mnd_mode = 0;
  270. dsi_pclk.src = 0x3;
  271. dsi_pclk.pre_div_func = (mnd_entry->pclk_n - 1);
  272. *expected_dsi_pclk = ((vco * 1000000) /
  273. ((pll_divider_config.dsi_clk_divider)
  274. * (mnd_entry->pclk_n)));
  275. } else {
  276. dsi_pclk.mnd_mode = 2;
  277. dsi_pclk.src = 0x3;
  278. dsi_pclk.m = mnd_entry->pclk_m;
  279. dsi_pclk.n = mnd_entry->pclk_n;
  280. dsi_pclk.d = mnd_entry->pclk_d;
  281. *expected_dsi_pclk = ((vco * 1000000 * dsi_pclk.m) /
  282. ((pll_divider_config.dsi_clk_divider)
  283. * (mnd_entry->pclk_n)));
  284. }
  285. return 0;
  286. }
  287. void mipi_dsi_phy_init(int panel_ndx, struct msm_panel_info const *panel_info,
  288. int target_type)
  289. {
  290. struct mipi_dsi_phy_ctrl *pd;
  291. int i, off;
  292. MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0001);/* start phy sw reset */
  293. wmb();
  294. usleep(1);
  295. MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0000);/* end phy w reset */
  296. wmb();
  297. usleep(1);
  298. MIPI_OUTP(MIPI_DSI_BASE + 0x2cc, 0x0003);/* regulator_ctrl_0 */
  299. MIPI_OUTP(MIPI_DSI_BASE + 0x2d0, 0x0001);/* regulator_ctrl_1 */
  300. MIPI_OUTP(MIPI_DSI_BASE + 0x2d4, 0x0001);/* regulator_ctrl_2 */
  301. MIPI_OUTP(MIPI_DSI_BASE + 0x2d8, 0x0000);/* regulator_ctrl_3 */
  302. #ifdef DSI_POWER
  303. MIPI_OUTP(MIPI_DSI_BASE + 0x2dc, 0x0100);/* regulator_ctrl_4 */
  304. #endif
  305. pd = (panel_info->mipi).dsi_phy_db;
  306. off = 0x02cc; /* regulator ctrl 0 */
  307. for (i = 0; i < 4; i++) {
  308. MIPI_OUTP(MIPI_DSI_BASE + off, pd->regulator[i]);
  309. wmb();
  310. off += 4;
  311. }
  312. off = 0x0260; /* phy timig ctrl 0 */
  313. for (i = 0; i < 11; i++) {
  314. MIPI_OUTP(MIPI_DSI_BASE + off, pd->timing[i]);
  315. wmb();
  316. off += 4;
  317. }
  318. off = 0x0290; /* ctrl 0 */
  319. for (i = 0; i < 4; i++) {
  320. MIPI_OUTP(MIPI_DSI_BASE + off, pd->ctrl[i]);
  321. wmb();
  322. off += 4;
  323. }
  324. off = 0x02a0; /* strength 0 */
  325. for (i = 0; i < 4; i++) {
  326. MIPI_OUTP(MIPI_DSI_BASE + off, pd->strength[i]);
  327. wmb();
  328. off += 4;
  329. }
  330. mipi_dsi_calibration();
  331. off = 0x0204; /* pll ctrl 1, skip 0 */
  332. for (i = 1; i < 21; i++) {
  333. MIPI_OUTP(MIPI_DSI_BASE + off, pd->pll[i]);
  334. wmb();
  335. off += 4;
  336. }
  337. if (panel_info)
  338. mipi_dsi_phy_pll_config(panel_info->clk_rate);
  339. /* pll ctrl 0 */
  340. MIPI_OUTP(MIPI_DSI_BASE + 0x200, pd->pll[0]);
  341. wmb();
  342. }
  343. void cont_splash_clk_ctrl(int enable)
  344. {
  345. }
  346. void mipi_dsi_prepare_clocks(void)
  347. {
  348. clk_prepare(amp_pclk);
  349. clk_prepare(dsi_m_pclk);
  350. clk_prepare(dsi_s_pclk);
  351. clk_prepare(dsi_byte_div_clk);
  352. clk_prepare(dsi_esc_clk);
  353. }
  354. void mipi_dsi_unprepare_clocks(void)
  355. {
  356. clk_unprepare(dsi_esc_clk);
  357. clk_unprepare(dsi_byte_div_clk);
  358. clk_unprepare(dsi_m_pclk);
  359. clk_unprepare(dsi_s_pclk);
  360. clk_unprepare(amp_pclk);
  361. }
  362. void mipi_dsi_ahb_ctrl(u32 enable)
  363. {
  364. static int ahb_ctrl_done;
  365. if (enable) {
  366. if (ahb_ctrl_done) {
  367. pr_info("%s: ahb clks already ON\n", __func__);
  368. return;
  369. }
  370. clk_enable(amp_pclk); /* clock for AHB-master to AXI */
  371. clk_enable(dsi_m_pclk);
  372. clk_enable(dsi_s_pclk);
  373. mipi_dsi_ahb_en();
  374. mipi_dsi_sfpb_cfg();
  375. ahb_ctrl_done = 1;
  376. } else {
  377. if (ahb_ctrl_done == 0) {
  378. pr_info("%s: ahb clks already OFF\n", __func__);
  379. return;
  380. }
  381. clk_disable(dsi_m_pclk);
  382. clk_disable(dsi_s_pclk);
  383. clk_disable(amp_pclk); /* clock for AHB-master to AXI */
  384. ahb_ctrl_done = 0;
  385. }
  386. }
  387. void mipi_dsi_clk_enable(void)
  388. {
  389. u32 pll_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0200);
  390. if (mipi_dsi_clk_on) {
  391. pr_info("%s: mipi_dsi_clks already ON\n", __func__);
  392. return;
  393. }
  394. MIPI_OUTP(MIPI_DSI_BASE + 0x0200, pll_ctrl | 0x01);
  395. mb();
  396. if (clk_set_rate(dsi_byte_div_clk, 1) < 0) /* divided by 1 */
  397. pr_err("%s: clk_set_rate failed\n", __func__);
  398. mipi_dsi_pclk_ctrl(&dsi_pclk, 1);
  399. mipi_dsi_clk_ctrl(&dsicore_clk, 1);
  400. clk_enable(dsi_byte_div_clk);
  401. clk_enable(dsi_esc_clk);
  402. mipi_dsi_clk_on = 1;
  403. }
  404. void mipi_dsi_clk_disable(void)
  405. {
  406. if (mipi_dsi_clk_on == 0) {
  407. pr_info("%s: mipi_dsi_clks already OFF\n", __func__);
  408. return;
  409. }
  410. clk_disable(dsi_esc_clk);
  411. clk_disable(dsi_byte_div_clk);
  412. mipi_dsi_pclk_ctrl(&dsi_pclk, 0);
  413. mipi_dsi_clk_ctrl(&dsicore_clk, 0);
  414. /* DSIPHY_PLL_CTRL_0, disable dsi pll */
  415. MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x40);
  416. mipi_dsi_clk_on = 0;
  417. }
  418. void mipi_dsi_phy_ctrl(int on)
  419. {
  420. if (on) {
  421. /* DSIPHY_PLL_CTRL_5 */
  422. MIPI_OUTP(MIPI_DSI_BASE + 0x0214, 0x050);
  423. /* DSIPHY_TPA_CTRL_1 */
  424. MIPI_OUTP(MIPI_DSI_BASE + 0x0258, 0x00f);
  425. /* DSIPHY_TPA_CTRL_2 */
  426. MIPI_OUTP(MIPI_DSI_BASE + 0x025c, 0x000);
  427. } else {
  428. /* DSIPHY_PLL_CTRL_5 */
  429. MIPI_OUTP(MIPI_DSI_BASE + 0x0214, 0x05f);
  430. /* DSIPHY_TPA_CTRL_1 */
  431. MIPI_OUTP(MIPI_DSI_BASE + 0x0258, 0x08f);
  432. /* DSIPHY_TPA_CTRL_2 */
  433. MIPI_OUTP(MIPI_DSI_BASE + 0x025c, 0x001);
  434. /* DSIPHY_REGULATOR_CTRL_0 */
  435. MIPI_OUTP(MIPI_DSI_BASE + 0x02cc, 0x02);
  436. /* DSIPHY_CTRL_0 */
  437. MIPI_OUTP(MIPI_DSI_BASE + 0x0290, 0x00);
  438. /* DSIPHY_CTRL_1 */
  439. MIPI_OUTP(MIPI_DSI_BASE + 0x0294, 0x7f);
  440. /* disable dsi clk */
  441. MIPI_OUTP(MIPI_DSI_BASE + 0x0118, 0);
  442. }
  443. }
  444. #ifdef CONFIG_FB_MSM_HDMI_COMMON
  445. #define SW_RESET BIT(2)
  446. void hdmi_phy_reset(void)
  447. {
  448. unsigned int phy_reset_polarity = 0x0;
  449. unsigned int val = HDMI_INP_ND(0x2D4);
  450. phy_reset_polarity = val >> 3 & 0x1;
  451. if (phy_reset_polarity == 0)
  452. HDMI_OUTP(0x2D4, val | SW_RESET);
  453. else
  454. HDMI_OUTP(0x2D4, val & (~SW_RESET));
  455. msleep(100);
  456. if (phy_reset_polarity == 0)
  457. HDMI_OUTP(0x2D4, val & (~SW_RESET));
  458. else
  459. HDMI_OUTP(0x2D4, val | SW_RESET);
  460. }
  461. void hdmi_msm_reset_core(void)
  462. {
  463. hdmi_msm_clk(0);
  464. udelay(5);
  465. hdmi_msm_clk(1);
  466. clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_ASSERT);
  467. udelay(20);
  468. clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_DEASSERT);
  469. }
  470. void hdmi_msm_init_phy(int video_format)
  471. {
  472. uint32 offset;
  473. /* De-serializer delay D/C for non-lbk mode
  474. * PHY REG0 = (DESER_SEL(0) | DESER_DEL_CTRL(3)
  475. * | AMUX_OUT_SEL(0))
  476. */
  477. HDMI_OUTP_ND(0x0300, 0x0C); /*0b00001100*/
  478. if (video_format == HDMI_VFRMT_720x480p60_16_9) {
  479. /* PHY REG1 = DTEST_MUX_SEL(5) | PLL_GAIN_SEL(0)
  480. * | OUTVOL_SWING_CTRL(3)
  481. */
  482. HDMI_OUTP_ND(0x0304, 0x53); /*0b01010011*/
  483. } else {
  484. /* If the freq. is less than 120MHz, use low gain 0
  485. * for board with termination
  486. * PHY REG1 = DTEST_MUX_SEL(5) | PLL_GAIN_SEL(0)
  487. * | OUTVOL_SWING_CTRL(4)
  488. */
  489. HDMI_OUTP_ND(0x0304, 0x54); /*0b01010100*/
  490. }
  491. /* No matter what, start from the power down mode
  492. * PHY REG2 = PD_PWRGEN | PD_PLL | PD_DRIVE_4 | PD_DRIVE_3
  493. * | PD_DRIVE_2 | PD_DRIVE_1 | PD_DESER
  494. */
  495. HDMI_OUTP_ND(0x0308, 0x7F); /*0b01111111*/
  496. /* Turn PowerGen on
  497. * PHY REG2 = PD_PLL | PD_DRIVE_4 | PD_DRIVE_3
  498. * | PD_DRIVE_2 | PD_DRIVE_1 | PD_DESER
  499. */
  500. HDMI_OUTP_ND(0x0308, 0x3F); /*0b00111111*/
  501. /* Turn PLL power on
  502. * PHY REG2 = PD_DRIVE_4 | PD_DRIVE_3
  503. * | PD_DRIVE_2 | PD_DRIVE_1 | PD_DESER
  504. */
  505. HDMI_OUTP_ND(0x0308, 0x1F); /*0b00011111*/
  506. /* Write to HIGH after PLL power down de-assert
  507. * PHY REG3 = PLL_ENABLE
  508. */
  509. HDMI_OUTP_ND(0x030C, 0x01);
  510. /* ASIC power on; PHY REG9 = 0 */
  511. HDMI_OUTP_ND(0x0324, 0x00);
  512. /* Enable PLL lock detect, PLL lock det will go high after lock
  513. * Enable the re-time logic
  514. * PHY REG12 = PLL_LOCK_DETECT_EN | RETIMING_ENABLE
  515. */
  516. HDMI_OUTP_ND(0x0330, 0x03); /*0b00000011*/
  517. /* Drivers are on
  518. * PHY REG2 = PD_DESER
  519. */
  520. HDMI_OUTP_ND(0x0308, 0x01); /*0b00000001*/
  521. /* If the RX detector is needed
  522. * PHY REG2 = RCV_SENSE_EN | PD_DESER
  523. */
  524. HDMI_OUTP_ND(0x0308, 0x81); /*0b10000001*/
  525. offset = 0x0310;
  526. while (offset <= 0x032C) {
  527. HDMI_OUTP(offset, 0x0);
  528. offset += 0x4;
  529. }
  530. /* If we want to use lock enable based on counting
  531. * PHY REG12 = FORCE_LOCK | PLL_LOCK_DETECT_EN | RETIMING_ENABLE
  532. */
  533. HDMI_OUTP_ND(0x0330, 0x13); /*0b00010011*/
  534. }
  535. void hdmi_msm_powerdown_phy(void)
  536. {
  537. /* Assert RESET PHY from controller */
  538. HDMI_OUTP_ND(0x02D4, 0x4);
  539. udelay(10);
  540. /* De-assert RESET PHY from controller */
  541. HDMI_OUTP_ND(0x02D4, 0x0);
  542. /* Turn off Driver */
  543. HDMI_OUTP_ND(0x0308, 0x1F);
  544. udelay(10);
  545. /* Disable PLL */
  546. HDMI_OUTP_ND(0x030C, 0x00);
  547. /* Power down PHY */
  548. HDMI_OUTP_ND(0x0308, 0x7F); /*0b01111111*/
  549. }
  550. void hdmi_frame_ctrl_cfg(const struct hdmi_disp_mode_timing_type *timing)
  551. {
  552. /* 0x02C8 HDMI_FRAME_CTRL
  553. * 31 INTERLACED_EN Interlaced or progressive enable bit
  554. * 0: Frame in progressive
  555. * 1: Frame is interlaced
  556. * 29 HSYNC_HDMI_POL HSYNC polarity fed to HDMI core
  557. * 0: Active Hi Hsync, detect the rising edge of hsync
  558. * 1: Active lo Hsync, Detect the falling edge of Hsync
  559. * 28 VSYNC_HDMI_POL VSYNC polarity fed to HDMI core
  560. * 0: Active Hi Vsync, detect the rising edge of vsync
  561. * 1: Active Lo Vsync, Detect the falling edge of Vsync
  562. * 12 RGB_MUX_SEL ALPHA mdp4 input is RGB, mdp4 input is BGR
  563. */
  564. HDMI_OUTP(0x02C8,
  565. ((timing->interlaced << 31) & 0x80000000)
  566. | ((timing->active_low_h << 29) & 0x20000000)
  567. | ((timing->active_low_v << 28) & 0x10000000)
  568. | (1 << 12));
  569. }
  570. void hdmi_msm_phy_status_poll(void)
  571. {
  572. unsigned int phy_ready;
  573. phy_ready = 0x1 & HDMI_INP_ND(0x33c);
  574. if (phy_ready) {
  575. pr_debug("HDMI Phy Status bit is set and ready\n");
  576. } else {
  577. pr_debug("HDMI Phy Status bit is not set,"
  578. "waiting for ready status\n");
  579. do {
  580. phy_ready = 0x1 & HDMI_INP_ND(0x33c);
  581. } while (!phy_ready);
  582. }
  583. }
  584. #endif