dw_hdmi.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2015 Google, Inc
  4. * Copyright 2014 Rockchip Inc.
  5. * Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net>
  6. */
  7. #include <common.h>
  8. #include <fdtdec.h>
  9. #include <log.h>
  10. #include <asm/io.h>
  11. #include <i2c.h>
  12. #include <media_bus_format.h>
  13. #include <linux/delay.h>
  14. #include "dw_hdmi.h"
  15. struct tmds_n_cts {
  16. u32 tmds;
  17. u32 cts;
  18. u32 n;
  19. };
  20. static const struct tmds_n_cts n_cts_table[] = {
  21. {
  22. .tmds = 25175000, .n = 6144, .cts = 25175,
  23. }, {
  24. .tmds = 25200000, .n = 6144, .cts = 25200,
  25. }, {
  26. .tmds = 27000000, .n = 6144, .cts = 27000,
  27. }, {
  28. .tmds = 27027000, .n = 6144, .cts = 27027,
  29. }, {
  30. .tmds = 40000000, .n = 6144, .cts = 40000,
  31. }, {
  32. .tmds = 54000000, .n = 6144, .cts = 54000,
  33. }, {
  34. .tmds = 54054000, .n = 6144, .cts = 54054,
  35. }, {
  36. .tmds = 65000000, .n = 6144, .cts = 65000,
  37. }, {
  38. .tmds = 74176000, .n = 11648, .cts = 140625,
  39. }, {
  40. .tmds = 74250000, .n = 6144, .cts = 74250,
  41. }, {
  42. .tmds = 83500000, .n = 6144, .cts = 83500,
  43. }, {
  44. .tmds = 106500000, .n = 6144, .cts = 106500,
  45. }, {
  46. .tmds = 108000000, .n = 6144, .cts = 108000,
  47. }, {
  48. .tmds = 148352000, .n = 5824, .cts = 140625,
  49. }, {
  50. .tmds = 148500000, .n = 6144, .cts = 148500,
  51. }, {
  52. .tmds = 297000000, .n = 5120, .cts = 247500,
  53. }
  54. };
  55. static const u16 csc_coeff_default[3][4] = {
  56. { 0x2000, 0x0000, 0x0000, 0x0000 },
  57. { 0x0000, 0x2000, 0x0000, 0x0000 },
  58. { 0x0000, 0x0000, 0x2000, 0x0000 }
  59. };
  60. static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
  61. { 0x2591, 0x1322, 0x074b, 0x0000 },
  62. { 0x6535, 0x2000, 0x7acc, 0x0200 },
  63. { 0x6acd, 0x7534, 0x2000, 0x0200 }
  64. };
  65. static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
  66. { 0x2000, 0x6926, 0x74fd, 0x010e },
  67. { 0x2000, 0x2cdd, 0x0000, 0x7e9a },
  68. { 0x2000, 0x0000, 0x38b4, 0x7e3b }
  69. };
  70. static void dw_hdmi_write(struct dw_hdmi *hdmi, u8 val, int offset)
  71. {
  72. switch (hdmi->reg_io_width) {
  73. case 1:
  74. writeb(val, hdmi->ioaddr + offset);
  75. break;
  76. case 4:
  77. writel(val, hdmi->ioaddr + (offset << 2));
  78. break;
  79. default:
  80. debug("reg_io_width has unsupported width!\n");
  81. break;
  82. }
  83. }
  84. static u8 dw_hdmi_read(struct dw_hdmi *hdmi, int offset)
  85. {
  86. switch (hdmi->reg_io_width) {
  87. case 1:
  88. return readb(hdmi->ioaddr + offset);
  89. case 4:
  90. return readl(hdmi->ioaddr + (offset << 2));
  91. default:
  92. debug("reg_io_width has unsupported width!\n");
  93. break;
  94. }
  95. return 0;
  96. }
  97. static u8 (*hdmi_read)(struct dw_hdmi *hdmi, int offset) = dw_hdmi_read;
  98. static void (*hdmi_write)(struct dw_hdmi *hdmi, u8 val, int offset) =
  99. dw_hdmi_write;
  100. static void hdmi_mod(struct dw_hdmi *hdmi, unsigned reg, u8 mask, u8 data)
  101. {
  102. u8 val = hdmi_read(hdmi, reg) & ~mask;
  103. val |= data & mask;
  104. hdmi_write(hdmi, val, reg);
  105. }
  106. static void hdmi_set_clock_regenerator(struct dw_hdmi *hdmi, u32 n, u32 cts)
  107. {
  108. uint cts3;
  109. uint n3;
  110. /* first set ncts_atomic_write (if present) */
  111. n3 = HDMI_AUD_N3_NCTS_ATOMIC_WRITE;
  112. hdmi_write(hdmi, n3, HDMI_AUD_N3);
  113. /* set cts_manual (if present) */
  114. cts3 = HDMI_AUD_CTS3_CTS_MANUAL;
  115. cts3 |= HDMI_AUD_CTS3_N_SHIFT_1 << HDMI_AUD_CTS3_N_SHIFT_OFFSET;
  116. cts3 |= (cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK;
  117. /* write cts values; cts3 must be written first */
  118. hdmi_write(hdmi, cts3, HDMI_AUD_CTS3);
  119. hdmi_write(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
  120. hdmi_write(hdmi, cts & 0xff, HDMI_AUD_CTS1);
  121. /* write n values; n1 must be written last */
  122. n3 |= (n >> 16) & HDMI_AUD_N3_AUDN19_16_MASK;
  123. hdmi_write(hdmi, n3, HDMI_AUD_N3);
  124. hdmi_write(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2);
  125. hdmi_write(hdmi, n & 0xff, HDMI_AUD_N3);
  126. hdmi_write(hdmi, HDMI_AUD_INPUTCLKFS_128, HDMI_AUD_INPUTCLKFS);
  127. }
  128. static int hdmi_lookup_n_cts(u32 pixel_clk)
  129. {
  130. int i;
  131. for (i = 0; i < ARRAY_SIZE(n_cts_table); i++)
  132. if (pixel_clk <= n_cts_table[i].tmds)
  133. break;
  134. if (i >= ARRAY_SIZE(n_cts_table))
  135. return -1;
  136. return i;
  137. }
  138. static void hdmi_audio_set_samplerate(struct dw_hdmi *hdmi, u32 pixel_clk)
  139. {
  140. u32 clk_n, clk_cts;
  141. int index;
  142. index = hdmi_lookup_n_cts(pixel_clk);
  143. if (index == -1) {
  144. debug("audio not supported for pixel clk %d\n", pixel_clk);
  145. return;
  146. }
  147. clk_n = n_cts_table[index].n;
  148. clk_cts = n_cts_table[index].cts;
  149. hdmi_set_clock_regenerator(hdmi, clk_n, clk_cts);
  150. }
  151. /*
  152. * this submodule is responsible for the video data synchronization.
  153. * for example, for rgb 4:4:4 input, the data map is defined as
  154. * pin{47~40} <==> r[7:0]
  155. * pin{31~24} <==> g[7:0]
  156. * pin{15~8} <==> b[7:0]
  157. */
  158. static void hdmi_video_sample(struct dw_hdmi *hdmi)
  159. {
  160. u32 color_format;
  161. uint val;
  162. switch (hdmi->hdmi_data.enc_in_bus_format) {
  163. case MEDIA_BUS_FMT_RGB888_1X24:
  164. color_format = 0x01;
  165. break;
  166. case MEDIA_BUS_FMT_RGB101010_1X30:
  167. color_format = 0x03;
  168. break;
  169. case MEDIA_BUS_FMT_RGB121212_1X36:
  170. color_format = 0x05;
  171. break;
  172. case MEDIA_BUS_FMT_RGB161616_1X48:
  173. color_format = 0x07;
  174. break;
  175. case MEDIA_BUS_FMT_YUV8_1X24:
  176. case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
  177. color_format = 0x09;
  178. break;
  179. case MEDIA_BUS_FMT_YUV10_1X30:
  180. case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
  181. color_format = 0x0B;
  182. break;
  183. case MEDIA_BUS_FMT_YUV12_1X36:
  184. case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
  185. color_format = 0x0D;
  186. break;
  187. case MEDIA_BUS_FMT_YUV16_1X48:
  188. case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
  189. color_format = 0x0F;
  190. break;
  191. case MEDIA_BUS_FMT_UYVY8_1X16:
  192. color_format = 0x16;
  193. break;
  194. case MEDIA_BUS_FMT_UYVY10_1X20:
  195. color_format = 0x14;
  196. break;
  197. case MEDIA_BUS_FMT_UYVY12_1X24:
  198. color_format = 0x12;
  199. break;
  200. default:
  201. color_format = 0x01;
  202. break;
  203. }
  204. val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
  205. ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
  206. HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
  207. hdmi_write(hdmi, val, HDMI_TX_INVID0);
  208. /* enable tx stuffing: when de is inactive, fix the output data to 0 */
  209. val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
  210. HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
  211. HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
  212. hdmi_write(hdmi, val, HDMI_TX_INSTUFFING);
  213. hdmi_write(hdmi, 0x0, HDMI_TX_GYDATA0);
  214. hdmi_write(hdmi, 0x0, HDMI_TX_GYDATA1);
  215. hdmi_write(hdmi, 0x0, HDMI_TX_RCRDATA0);
  216. hdmi_write(hdmi, 0x0, HDMI_TX_RCRDATA1);
  217. hdmi_write(hdmi, 0x0, HDMI_TX_BCBDATA0);
  218. hdmi_write(hdmi, 0x0, HDMI_TX_BCBDATA1);
  219. }
  220. static void hdmi_video_packetize(struct dw_hdmi *hdmi)
  221. {
  222. u32 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
  223. u32 remap_size = HDMI_VP_REMAP_YCC422_16BIT;
  224. u32 color_depth = 0;
  225. uint val, vp_conf;
  226. /* set the packetizer registers */
  227. val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
  228. HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
  229. ((0 << HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
  230. HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
  231. hdmi_write(hdmi, val, HDMI_VP_PR_CD);
  232. hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_PR_STUFFING_MASK,
  233. HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE);
  234. /* data from pixel repeater block */
  235. vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
  236. HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
  237. hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_PR_EN_MASK |
  238. HDMI_VP_CONF_BYPASS_SELECT_MASK, vp_conf);
  239. hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK,
  240. 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET);
  241. hdmi_write(hdmi, remap_size, HDMI_VP_REMAP);
  242. vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
  243. HDMI_VP_CONF_PP_EN_DISABLE |
  244. HDMI_VP_CONF_YCC422_EN_DISABLE;
  245. hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_BYPASS_EN_MASK |
  246. HDMI_VP_CONF_PP_EN_ENMASK | HDMI_VP_CONF_YCC422_EN_MASK,
  247. vp_conf);
  248. hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_PP_STUFFING_MASK |
  249. HDMI_VP_STUFF_YCC422_STUFFING_MASK,
  250. HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
  251. HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE);
  252. hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
  253. output_select);
  254. }
  255. static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi, uint bit)
  256. {
  257. hdmi_mod(hdmi, HDMI_PHY_TST0, HDMI_PHY_TST0_TSTCLR_MASK,
  258. bit << HDMI_PHY_TST0_TSTCLR_OFFSET);
  259. }
  260. static int hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, u32 msec)
  261. {
  262. ulong start;
  263. u32 val;
  264. start = get_timer(0);
  265. do {
  266. val = hdmi_read(hdmi, HDMI_IH_I2CMPHY_STAT0);
  267. if (val & 0x3) {
  268. hdmi_write(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
  269. return 0;
  270. }
  271. udelay(100);
  272. } while (get_timer(start) < msec);
  273. return 1;
  274. }
  275. static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, uint data, uint addr)
  276. {
  277. hdmi_write(hdmi, 0xff, HDMI_IH_I2CMPHY_STAT0);
  278. hdmi_write(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
  279. hdmi_write(hdmi, (u8)(data >> 8), HDMI_PHY_I2CM_DATAO_1_ADDR);
  280. hdmi_write(hdmi, (u8)(data >> 0), HDMI_PHY_I2CM_DATAO_0_ADDR);
  281. hdmi_write(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
  282. HDMI_PHY_I2CM_OPERATION_ADDR);
  283. hdmi_phy_wait_i2c_done(hdmi, 1000);
  284. }
  285. static void hdmi_phy_enable_power(struct dw_hdmi *hdmi, uint enable)
  286. {
  287. hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_PDZ_MASK,
  288. enable << HDMI_PHY_CONF0_PDZ_OFFSET);
  289. }
  290. static void hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, uint enable)
  291. {
  292. hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_ENTMDS_MASK,
  293. enable << HDMI_PHY_CONF0_ENTMDS_OFFSET);
  294. }
  295. static void hdmi_phy_enable_spare(struct dw_hdmi *hdmi, uint enable)
  296. {
  297. hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_SPARECTRL_MASK,
  298. enable << HDMI_PHY_CONF0_SPARECTRL_OFFSET);
  299. }
  300. static void hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, uint enable)
  301. {
  302. hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_GEN2_PDDQ_MASK,
  303. enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET);
  304. }
  305. static void hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, uint enable)
  306. {
  307. hdmi_mod(hdmi, HDMI_PHY_CONF0,
  308. HDMI_PHY_CONF0_GEN2_TXPWRON_MASK,
  309. enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET);
  310. }
  311. static void hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, uint enable)
  312. {
  313. hdmi_mod(hdmi, HDMI_PHY_CONF0,
  314. HDMI_PHY_CONF0_SELDATAENPOL_MASK,
  315. enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET);
  316. }
  317. static void hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi,
  318. uint enable)
  319. {
  320. hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_SELDIPIF_MASK,
  321. enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET);
  322. }
  323. static int hdmi_phy_configure(struct dw_hdmi *hdmi, u32 mpixelclock)
  324. {
  325. ulong start;
  326. uint i, val;
  327. if (!hdmi->mpll_cfg || !hdmi->phy_cfg)
  328. return -1;
  329. /* gen2 tx power off */
  330. hdmi_phy_gen2_txpwron(hdmi, 0);
  331. /* gen2 pddq */
  332. hdmi_phy_gen2_pddq(hdmi, 1);
  333. /* phy reset */
  334. hdmi_write(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
  335. hdmi_write(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
  336. hdmi_write(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
  337. hdmi_phy_test_clear(hdmi, 1);
  338. hdmi_write(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
  339. HDMI_PHY_I2CM_SLAVE_ADDR);
  340. hdmi_phy_test_clear(hdmi, 0);
  341. /* pll/mpll cfg - always match on final entry */
  342. for (i = 0; hdmi->mpll_cfg[i].mpixelclock != (~0ul); i++)
  343. if (mpixelclock <= hdmi->mpll_cfg[i].mpixelclock)
  344. break;
  345. hdmi_phy_i2c_write(hdmi, hdmi->mpll_cfg[i].cpce, PHY_OPMODE_PLLCFG);
  346. hdmi_phy_i2c_write(hdmi, hdmi->mpll_cfg[i].gmp, PHY_PLLGMPCTRL);
  347. hdmi_phy_i2c_write(hdmi, hdmi->mpll_cfg[i].curr, PHY_PLLCURRCTRL);
  348. hdmi_phy_i2c_write(hdmi, 0x0000, PHY_PLLPHBYCTRL);
  349. hdmi_phy_i2c_write(hdmi, 0x0006, PHY_PLLCLKBISTPHASE);
  350. for (i = 0; hdmi->phy_cfg[i].mpixelclock != (~0ul); i++)
  351. if (mpixelclock <= hdmi->phy_cfg[i].mpixelclock)
  352. break;
  353. /*
  354. * resistance term 133ohm cfg
  355. * preemp cgf 0.00
  356. * tx/ck lvl 10
  357. */
  358. hdmi_phy_i2c_write(hdmi, hdmi->phy_cfg[i].term, PHY_TXTERM);
  359. hdmi_phy_i2c_write(hdmi, hdmi->phy_cfg[i].sym_ctr, PHY_CKSYMTXCTRL);
  360. hdmi_phy_i2c_write(hdmi, hdmi->phy_cfg[i].vlev_ctr, PHY_VLEVCTRL);
  361. /* remove clk term */
  362. hdmi_phy_i2c_write(hdmi, 0x8000, PHY_CKCALCTRL);
  363. hdmi_phy_enable_power(hdmi, 1);
  364. /* toggle tmds enable */
  365. hdmi_phy_enable_tmds(hdmi, 0);
  366. hdmi_phy_enable_tmds(hdmi, 1);
  367. /* gen2 tx power on */
  368. hdmi_phy_gen2_txpwron(hdmi, 1);
  369. hdmi_phy_gen2_pddq(hdmi, 0);
  370. hdmi_phy_enable_spare(hdmi, 1);
  371. /* wait for phy pll lock */
  372. start = get_timer(0);
  373. do {
  374. val = hdmi_read(hdmi, HDMI_PHY_STAT0);
  375. if (!(val & HDMI_PHY_TX_PHY_LOCK))
  376. return 0;
  377. udelay(100);
  378. } while (get_timer(start) < 5);
  379. return -1;
  380. }
  381. static void hdmi_av_composer(struct dw_hdmi *hdmi,
  382. const struct display_timing *edid)
  383. {
  384. bool mdataenablepolarity = true;
  385. uint inv_val;
  386. uint hbl;
  387. uint vbl;
  388. hbl = edid->hback_porch.typ + edid->hfront_porch.typ +
  389. edid->hsync_len.typ;
  390. vbl = edid->vback_porch.typ + edid->vfront_porch.typ +
  391. edid->vsync_len.typ;
  392. /* set up hdmi_fc_invidconf */
  393. inv_val = HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE;
  394. inv_val |= (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
  395. HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
  396. HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
  397. inv_val |= (edid->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
  398. HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
  399. HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
  400. inv_val |= (mdataenablepolarity ?
  401. HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
  402. HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
  403. inv_val |= (edid->hdmi_monitor ?
  404. HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
  405. HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE);
  406. inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW;
  407. inv_val |= HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE;
  408. hdmi_write(hdmi, inv_val, HDMI_FC_INVIDCONF);
  409. /* set up horizontal active pixel width */
  410. hdmi_write(hdmi, edid->hactive.typ >> 8, HDMI_FC_INHACTV1);
  411. hdmi_write(hdmi, edid->hactive.typ, HDMI_FC_INHACTV0);
  412. /* set up vertical active lines */
  413. hdmi_write(hdmi, edid->vactive.typ >> 8, HDMI_FC_INVACTV1);
  414. hdmi_write(hdmi, edid->vactive.typ, HDMI_FC_INVACTV0);
  415. /* set up horizontal blanking pixel region width */
  416. hdmi_write(hdmi, hbl >> 8, HDMI_FC_INHBLANK1);
  417. hdmi_write(hdmi, hbl, HDMI_FC_INHBLANK0);
  418. /* set up vertical blanking pixel region width */
  419. hdmi_write(hdmi, vbl, HDMI_FC_INVBLANK);
  420. /* set up hsync active edge delay width (in pixel clks) */
  421. hdmi_write(hdmi, edid->hfront_porch.typ >> 8, HDMI_FC_HSYNCINDELAY1);
  422. hdmi_write(hdmi, edid->hfront_porch.typ, HDMI_FC_HSYNCINDELAY0);
  423. /* set up vsync active edge delay (in lines) */
  424. hdmi_write(hdmi, edid->vfront_porch.typ, HDMI_FC_VSYNCINDELAY);
  425. /* set up hsync active pulse width (in pixel clks) */
  426. hdmi_write(hdmi, edid->hsync_len.typ >> 8, HDMI_FC_HSYNCINWIDTH1);
  427. hdmi_write(hdmi, edid->hsync_len.typ, HDMI_FC_HSYNCINWIDTH0);
  428. /* set up vsync active edge delay (in lines) */
  429. hdmi_write(hdmi, edid->vsync_len.typ, HDMI_FC_VSYNCINWIDTH);
  430. }
  431. static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format)
  432. {
  433. switch (bus_format) {
  434. case MEDIA_BUS_FMT_RGB888_1X24:
  435. case MEDIA_BUS_FMT_RGB101010_1X30:
  436. case MEDIA_BUS_FMT_RGB121212_1X36:
  437. case MEDIA_BUS_FMT_RGB161616_1X48:
  438. return true;
  439. default:
  440. return false;
  441. }
  442. }
  443. static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format)
  444. {
  445. switch (bus_format) {
  446. case MEDIA_BUS_FMT_YUV8_1X24:
  447. case MEDIA_BUS_FMT_YUV10_1X30:
  448. case MEDIA_BUS_FMT_YUV12_1X36:
  449. case MEDIA_BUS_FMT_YUV16_1X48:
  450. return true;
  451. default:
  452. return false;
  453. }
  454. }
  455. static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
  456. {
  457. switch (bus_format) {
  458. case MEDIA_BUS_FMT_UYVY8_1X16:
  459. case MEDIA_BUS_FMT_UYVY10_1X20:
  460. case MEDIA_BUS_FMT_UYVY12_1X24:
  461. return true;
  462. default:
  463. return false;
  464. }
  465. }
  466. static int is_color_space_interpolation(struct dw_hdmi *hdmi)
  467. {
  468. if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_in_bus_format))
  469. return 0;
  470. if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) ||
  471. hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
  472. return 1;
  473. return 0;
  474. }
  475. static int is_color_space_decimation(struct dw_hdmi *hdmi)
  476. {
  477. if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
  478. return 0;
  479. if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format) ||
  480. hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_in_bus_format))
  481. return 1;
  482. return 0;
  483. }
  484. static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
  485. {
  486. switch (bus_format) {
  487. case MEDIA_BUS_FMT_RGB888_1X24:
  488. case MEDIA_BUS_FMT_YUV8_1X24:
  489. case MEDIA_BUS_FMT_UYVY8_1X16:
  490. case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
  491. return 8;
  492. case MEDIA_BUS_FMT_RGB101010_1X30:
  493. case MEDIA_BUS_FMT_YUV10_1X30:
  494. case MEDIA_BUS_FMT_UYVY10_1X20:
  495. case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
  496. return 10;
  497. case MEDIA_BUS_FMT_RGB121212_1X36:
  498. case MEDIA_BUS_FMT_YUV12_1X36:
  499. case MEDIA_BUS_FMT_UYVY12_1X24:
  500. case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
  501. return 12;
  502. case MEDIA_BUS_FMT_RGB161616_1X48:
  503. case MEDIA_BUS_FMT_YUV16_1X48:
  504. case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
  505. return 16;
  506. default:
  507. return 0;
  508. }
  509. }
  510. static int is_color_space_conversion(struct dw_hdmi *hdmi)
  511. {
  512. return hdmi->hdmi_data.enc_in_bus_format !=
  513. hdmi->hdmi_data.enc_out_bus_format;
  514. }
  515. static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
  516. {
  517. const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
  518. unsigned int i;
  519. u32 csc_scale = 1;
  520. if (is_color_space_conversion(hdmi)) {
  521. if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
  522. csc_coeff = &csc_coeff_rgb_out_eitu601;
  523. } else if (hdmi_bus_fmt_is_rgb(
  524. hdmi->hdmi_data.enc_in_bus_format)) {
  525. csc_coeff = &csc_coeff_rgb_in_eitu601;
  526. csc_scale = 0;
  527. }
  528. }
  529. /* The CSC registers are sequential, alternating MSB then LSB */
  530. for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
  531. u16 coeff_a = (*csc_coeff)[0][i];
  532. u16 coeff_b = (*csc_coeff)[1][i];
  533. u16 coeff_c = (*csc_coeff)[2][i];
  534. hdmi_write(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
  535. hdmi_write(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
  536. hdmi_write(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
  537. hdmi_write(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
  538. hdmi_write(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
  539. hdmi_write(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
  540. }
  541. hdmi_mod(hdmi, HDMI_CSC_SCALE, HDMI_CSC_SCALE_CSCSCALE_MASK, csc_scale);
  542. }
  543. static void hdmi_video_csc(struct dw_hdmi *hdmi)
  544. {
  545. int color_depth = 0;
  546. int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
  547. int decimation = 0;
  548. /* YCC422 interpolation to 444 mode */
  549. if (is_color_space_interpolation(hdmi))
  550. interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
  551. else if (is_color_space_decimation(hdmi))
  552. decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
  553. switch (hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format)) {
  554. case 8:
  555. color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
  556. break;
  557. case 10:
  558. color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
  559. break;
  560. case 12:
  561. color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
  562. break;
  563. case 16:
  564. color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
  565. break;
  566. default:
  567. return;
  568. }
  569. /* Configure the CSC registers */
  570. hdmi_write(hdmi, interpolation | decimation, HDMI_CSC_CFG);
  571. hdmi_mod(hdmi, HDMI_CSC_SCALE, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
  572. color_depth);
  573. dw_hdmi_update_csc_coeffs(hdmi);
  574. }
  575. /* hdmi initialization step b.4 */
  576. static void hdmi_enable_video_path(struct dw_hdmi *hdmi, bool audio)
  577. {
  578. uint clkdis;
  579. /* control period minimum duration */
  580. hdmi_write(hdmi, 12, HDMI_FC_CTRLDUR);
  581. hdmi_write(hdmi, 32, HDMI_FC_EXCTRLDUR);
  582. hdmi_write(hdmi, 1, HDMI_FC_EXCTRLSPAC);
  583. /* set to fill tmds data channels */
  584. hdmi_write(hdmi, 0x0b, HDMI_FC_CH0PREAM);
  585. hdmi_write(hdmi, 0x16, HDMI_FC_CH1PREAM);
  586. hdmi_write(hdmi, 0x21, HDMI_FC_CH2PREAM);
  587. hdmi_write(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS,
  588. HDMI_MC_FLOWCTRL);
  589. /* enable pixel clock and tmds data path */
  590. clkdis = 0x7f;
  591. clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
  592. hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
  593. clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
  594. hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
  595. /* Enable csc path */
  596. if (is_color_space_conversion(hdmi)) {
  597. clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
  598. hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
  599. }
  600. /* Enable color space conversion if needed */
  601. if (is_color_space_conversion(hdmi))
  602. hdmi_write(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
  603. HDMI_MC_FLOWCTRL);
  604. else
  605. hdmi_write(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS,
  606. HDMI_MC_FLOWCTRL);
  607. if (audio) {
  608. clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
  609. hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
  610. }
  611. }
  612. /* workaround to clear the overflow condition */
  613. static void hdmi_clear_overflow(struct dw_hdmi *hdmi)
  614. {
  615. uint val, count;
  616. /* tmds software reset */
  617. hdmi_write(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
  618. val = hdmi_read(hdmi, HDMI_FC_INVIDCONF);
  619. for (count = 0; count < 4; count++)
  620. hdmi_write(hdmi, val, HDMI_FC_INVIDCONF);
  621. }
  622. static void hdmi_audio_set_format(struct dw_hdmi *hdmi)
  623. {
  624. hdmi_write(hdmi, HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_IN_EN_0,
  625. HDMI_AUD_CONF0);
  626. hdmi_write(hdmi, HDMI_AUD_CONF1_I2S_MODE_STANDARD_MODE |
  627. HDMI_AUD_CONF1_I2S_WIDTH_16BIT, HDMI_AUD_CONF1);
  628. hdmi_write(hdmi, 0x00, HDMI_AUD_CONF2);
  629. }
  630. static void hdmi_audio_fifo_reset(struct dw_hdmi *hdmi)
  631. {
  632. hdmi_write(hdmi, (u8)~HDMI_MC_SWRSTZ_II2SSWRST_REQ, HDMI_MC_SWRSTZ);
  633. hdmi_write(hdmi, HDMI_AUD_CONF0_SW_AUDIO_FIFO_RST, HDMI_AUD_CONF0);
  634. hdmi_write(hdmi, 0x00, HDMI_AUD_INT);
  635. hdmi_write(hdmi, 0x00, HDMI_AUD_INT1);
  636. }
  637. static int hdmi_get_plug_in_status(struct dw_hdmi *hdmi)
  638. {
  639. uint val = hdmi_read(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD;
  640. return !!val;
  641. }
  642. static int hdmi_ddc_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
  643. {
  644. u32 val;
  645. ulong start;
  646. start = get_timer(0);
  647. do {
  648. val = hdmi_read(hdmi, HDMI_IH_I2CM_STAT0);
  649. if (val & 0x2) {
  650. hdmi_write(hdmi, val, HDMI_IH_I2CM_STAT0);
  651. return 0;
  652. }
  653. udelay(100);
  654. } while (get_timer(start) < msec);
  655. return 1;
  656. }
  657. static void hdmi_ddc_reset(struct dw_hdmi *hdmi)
  658. {
  659. hdmi_mod(hdmi, HDMI_I2CM_SOFTRSTZ, HDMI_I2CM_SOFTRSTZ_MASK, 0);
  660. }
  661. static int hdmi_read_edid(struct dw_hdmi *hdmi, int block, u8 *buff)
  662. {
  663. int shift = (block % 2) * 0x80;
  664. int edid_read_err = 0;
  665. u32 trytime = 5;
  666. u32 n;
  667. if (CONFIG_IS_ENABLED(DM_I2C) && hdmi->ddc_bus) {
  668. struct udevice *chip;
  669. edid_read_err = i2c_get_chip(hdmi->ddc_bus,
  670. HDMI_I2CM_SLAVE_DDC_ADDR,
  671. 1, &chip);
  672. if (edid_read_err)
  673. return edid_read_err;
  674. return dm_i2c_read(chip, shift, buff, HDMI_EDID_BLOCK_SIZE);
  675. }
  676. /* set ddc i2c clk which devided from ddc_clk to 100khz */
  677. hdmi_write(hdmi, hdmi->i2c_clk_high, HDMI_I2CM_SS_SCL_HCNT_0_ADDR);
  678. hdmi_write(hdmi, hdmi->i2c_clk_low, HDMI_I2CM_SS_SCL_LCNT_0_ADDR);
  679. hdmi_mod(hdmi, HDMI_I2CM_DIV, HDMI_I2CM_DIV_FAST_STD_MODE,
  680. HDMI_I2CM_DIV_STD_MODE);
  681. hdmi_write(hdmi, HDMI_I2CM_SLAVE_DDC_ADDR, HDMI_I2CM_SLAVE);
  682. hdmi_write(hdmi, HDMI_I2CM_SEGADDR_DDC, HDMI_I2CM_SEGADDR);
  683. hdmi_write(hdmi, block >> 1, HDMI_I2CM_SEGPTR);
  684. while (trytime--) {
  685. edid_read_err = 0;
  686. for (n = 0; n < HDMI_EDID_BLOCK_SIZE; n++) {
  687. hdmi_write(hdmi, shift + n, HDMI_I2CM_ADDRESS);
  688. if (block == 0)
  689. hdmi_write(hdmi, HDMI_I2CM_OP_RD8,
  690. HDMI_I2CM_OPERATION);
  691. else
  692. hdmi_write(hdmi, HDMI_I2CM_OP_RD8_EXT,
  693. HDMI_I2CM_OPERATION);
  694. if (hdmi_ddc_wait_i2c_done(hdmi, 10)) {
  695. hdmi_ddc_reset(hdmi);
  696. edid_read_err = 1;
  697. break;
  698. }
  699. buff[n] = hdmi_read(hdmi, HDMI_I2CM_DATAI);
  700. }
  701. if (!edid_read_err)
  702. break;
  703. }
  704. return edid_read_err;
  705. }
  706. static const u8 pre_buf[] = {
  707. 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  708. 0x04, 0x69, 0xfa, 0x23, 0xc8, 0x28, 0x01, 0x00,
  709. 0x10, 0x17, 0x01, 0x03, 0x80, 0x33, 0x1d, 0x78,
  710. 0x2a, 0xd9, 0x45, 0xa2, 0x55, 0x4d, 0xa0, 0x27,
  711. 0x12, 0x50, 0x54, 0xb7, 0xef, 0x00, 0x71, 0x4f,
  712. 0x81, 0x40, 0x81, 0x80, 0x95, 0x00, 0xb3, 0x00,
  713. 0xd1, 0xc0, 0x81, 0xc0, 0x81, 0x00, 0x02, 0x3a,
  714. 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
  715. 0x45, 0x00, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e,
  716. 0x00, 0x00, 0x00, 0xff, 0x00, 0x44, 0x34, 0x4c,
  717. 0x4d, 0x54, 0x46, 0x30, 0x37, 0x35, 0x39, 0x37,
  718. 0x36, 0x0a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32,
  719. 0x4b, 0x18, 0x53, 0x11, 0x00, 0x0a, 0x20, 0x20,
  720. 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
  721. 0x00, 0x41, 0x53, 0x55, 0x53, 0x20, 0x56, 0x53,
  722. 0x32, 0x33, 0x38, 0x0a, 0x20, 0x20, 0x01, 0xb0,
  723. 0x02, 0x03, 0x22, 0x71, 0x4f, 0x01, 0x02, 0x03,
  724. 0x11, 0x12, 0x13, 0x04, 0x14, 0x05, 0x0e, 0x0f,
  725. 0x1d, 0x1e, 0x1f, 0x10, 0x23, 0x09, 0x17, 0x07,
  726. 0x83, 0x01, 0x00, 0x00, 0x65, 0x03, 0x0c, 0x00,
  727. 0x10, 0x00, 0x8c, 0x0a, 0xd0, 0x8a, 0x20, 0xe0,
  728. 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xfd, 0x1e,
  729. 0x11, 0x00, 0x00, 0x18, 0x01, 0x1d, 0x00, 0x72,
  730. 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
  731. 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e, 0x01, 0x1d,
  732. 0x00, 0xbc, 0x52, 0xd0, 0x1e, 0x20, 0xb8, 0x28,
  733. 0x55, 0x40, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e,
  734. 0x8c, 0x0a, 0xd0, 0x90, 0x20, 0x40, 0x31, 0x20,
  735. 0x0c, 0x40, 0x55, 0x00, 0xfd, 0x1e, 0x11, 0x00,
  736. 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  737. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  738. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9,
  739. };
  740. int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
  741. {
  742. int i, ret;
  743. /* hdmi phy spec says to do the phy initialization sequence twice */
  744. for (i = 0; i < 2; i++) {
  745. hdmi_phy_sel_data_en_pol(hdmi, 1);
  746. hdmi_phy_sel_interface_control(hdmi, 0);
  747. hdmi_phy_enable_tmds(hdmi, 0);
  748. hdmi_phy_enable_power(hdmi, 0);
  749. ret = hdmi_phy_configure(hdmi, mpixelclock);
  750. if (ret) {
  751. debug("hdmi phy config failure %d\n", ret);
  752. return ret;
  753. }
  754. }
  755. return 0;
  756. }
  757. int dw_hdmi_phy_wait_for_hpd(struct dw_hdmi *hdmi)
  758. {
  759. ulong start;
  760. start = get_timer(0);
  761. do {
  762. if (hdmi_get_plug_in_status(hdmi))
  763. return 0;
  764. udelay(100);
  765. } while (get_timer(start) < 300);
  766. return -1;
  767. }
  768. void dw_hdmi_phy_init(struct dw_hdmi *hdmi)
  769. {
  770. /* enable phy i2cm done irq */
  771. hdmi_write(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
  772. HDMI_PHY_I2CM_INT_ADDR);
  773. /* enable phy i2cm nack & arbitration error irq */
  774. hdmi_write(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
  775. HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
  776. HDMI_PHY_I2CM_CTLINT_ADDR);
  777. /* enable cable hot plug irq */
  778. hdmi_write(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
  779. /* clear hotplug interrupts */
  780. hdmi_write(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
  781. }
  782. int dw_hdmi_read_edid(struct dw_hdmi *hdmi, u8 *buf, int buf_size)
  783. {
  784. u32 edid_size = HDMI_EDID_BLOCK_SIZE;
  785. int ret;
  786. if (0) {
  787. edid_size = sizeof(pre_buf);
  788. memcpy(buf, pre_buf, edid_size);
  789. } else {
  790. ret = hdmi_read_edid(hdmi, 0, buf);
  791. if (ret) {
  792. debug("failed to read edid.\n");
  793. return -1;
  794. }
  795. if (buf[0x7e] != 0) {
  796. hdmi_read_edid(hdmi, 1, buf + HDMI_EDID_BLOCK_SIZE);
  797. edid_size += HDMI_EDID_BLOCK_SIZE;
  798. }
  799. }
  800. return edid_size;
  801. }
  802. int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid)
  803. {
  804. int ret;
  805. debug("%s, mode info : clock %d hdis %d vdis %d\n",
  806. edid->hdmi_monitor ? "hdmi" : "dvi",
  807. edid->pixelclock.typ, edid->hactive.typ, edid->vactive.typ);
  808. hdmi_av_composer(hdmi, edid);
  809. ret = hdmi->phy_set(hdmi, edid->pixelclock.typ);
  810. if (ret)
  811. return ret;
  812. hdmi_enable_video_path(hdmi, edid->hdmi_monitor);
  813. if (edid->hdmi_monitor) {
  814. hdmi_audio_fifo_reset(hdmi);
  815. hdmi_audio_set_format(hdmi);
  816. hdmi_audio_set_samplerate(hdmi, edid->pixelclock.typ);
  817. }
  818. hdmi_video_packetize(hdmi);
  819. hdmi_video_csc(hdmi);
  820. hdmi_video_sample(hdmi);
  821. hdmi_clear_overflow(hdmi);
  822. return 0;
  823. }
  824. void dw_hdmi_init(struct dw_hdmi *hdmi)
  825. {
  826. uint ih_mute;
  827. /*
  828. * boot up defaults are:
  829. * hdmi_ih_mute = 0x03 (disabled)
  830. * hdmi_ih_mute_* = 0x00 (enabled)
  831. *
  832. * disable top level interrupt bits in hdmi block
  833. */
  834. ih_mute = /*hdmi_read(hdmi, HDMI_IH_MUTE) |*/
  835. HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
  836. HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
  837. if (hdmi->write_reg)
  838. hdmi_write = hdmi->write_reg;
  839. if (hdmi->read_reg)
  840. hdmi_read = hdmi->read_reg;
  841. hdmi_write(hdmi, ih_mute, HDMI_IH_MUTE);
  842. /* enable i2c master done irq */
  843. hdmi_write(hdmi, ~0x04, HDMI_I2CM_INT);
  844. /* enable i2c client nack % arbitration error irq */
  845. hdmi_write(hdmi, ~0x44, HDMI_I2CM_CTLINT);
  846. }