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