1c2539483SSimon Glass /* 2c2539483SSimon Glass * Copyright (c) 2015 Google, Inc 3c2539483SSimon Glass * Copyright 2014 Rockchip Inc. 4c2539483SSimon Glass * 5c2539483SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6c2539483SSimon Glass */ 7c2539483SSimon Glass 8c2539483SSimon Glass #include <common.h> 9c2539483SSimon Glass #include <clk.h> 10c2539483SSimon Glass #include <display.h> 11c2539483SSimon Glass #include <dm.h> 12c2539483SSimon Glass #include <edid.h> 13c2539483SSimon Glass #include <regmap.h> 14c2539483SSimon Glass #include <syscon.h> 15c2539483SSimon Glass #include <asm/gpio.h> 16c2539483SSimon Glass #include <asm/io.h> 17c2539483SSimon Glass #include <asm/arch/clock.h> 18c2539483SSimon Glass #include <asm/arch/grf_rk3288.h> 19c2539483SSimon Glass #include <asm/arch/hdmi_rk3288.h> 20c2539483SSimon Glass #include <power/regulator.h> 21c2539483SSimon Glass 22c2539483SSimon Glass struct tmds_n_cts { 23c2539483SSimon Glass u32 tmds; 24c2539483SSimon Glass u32 cts; 25c2539483SSimon Glass u32 n; 26c2539483SSimon Glass }; 27c2539483SSimon Glass 28c2539483SSimon Glass struct rk_hdmi_priv { 29c2539483SSimon Glass struct rk3288_hdmi *regs; 30c2539483SSimon Glass struct rk3288_grf *grf; 31c2539483SSimon Glass }; 32c2539483SSimon Glass 33c2539483SSimon Glass static const struct tmds_n_cts n_cts_table[] = { 34c2539483SSimon Glass { 35c2539483SSimon Glass .tmds = 25175, .n = 6144, .cts = 25175, 36c2539483SSimon Glass }, { 37c2539483SSimon Glass .tmds = 25200, .n = 6144, .cts = 25200, 38c2539483SSimon Glass }, { 39c2539483SSimon Glass .tmds = 27000, .n = 6144, .cts = 27000, 40c2539483SSimon Glass }, { 41c2539483SSimon Glass .tmds = 27027, .n = 6144, .cts = 27027, 42c2539483SSimon Glass }, { 43c2539483SSimon Glass .tmds = 40000, .n = 6144, .cts = 40000, 44c2539483SSimon Glass }, { 45c2539483SSimon Glass .tmds = 54000, .n = 6144, .cts = 54000, 46c2539483SSimon Glass }, { 47c2539483SSimon Glass .tmds = 54054, .n = 6144, .cts = 54054, 48c2539483SSimon Glass }, { 49c2539483SSimon Glass .tmds = 65000, .n = 6144, .cts = 65000, 50c2539483SSimon Glass }, { 51c2539483SSimon Glass .tmds = 74176, .n = 11648, .cts = 140625, 52c2539483SSimon Glass }, { 53c2539483SSimon Glass .tmds = 74250, .n = 6144, .cts = 74250, 54c2539483SSimon Glass }, { 55c2539483SSimon Glass .tmds = 83500, .n = 6144, .cts = 83500, 56c2539483SSimon Glass }, { 57c2539483SSimon Glass .tmds = 106500, .n = 6144, .cts = 106500, 58c2539483SSimon Glass }, { 59c2539483SSimon Glass .tmds = 108000, .n = 6144, .cts = 108000, 60c2539483SSimon Glass }, { 61c2539483SSimon Glass .tmds = 148352, .n = 5824, .cts = 140625, 62c2539483SSimon Glass }, { 63c2539483SSimon Glass .tmds = 148500, .n = 6144, .cts = 148500, 64c2539483SSimon Glass }, { 65c2539483SSimon Glass .tmds = 297000, .n = 5120, .cts = 247500, 66c2539483SSimon Glass } 67c2539483SSimon Glass }; 68c2539483SSimon Glass 69c2539483SSimon Glass struct hdmi_mpll_config { 70c2539483SSimon Glass u64 mpixelclock; 71c2539483SSimon Glass /* Mode of Operation and PLL Dividers Control Register */ 72c2539483SSimon Glass u32 cpce; 73c2539483SSimon Glass /* PLL Gmp Control Register */ 74c2539483SSimon Glass u32 gmp; 75c2539483SSimon Glass /* PLL Current COntrol Register */ 76c2539483SSimon Glass u32 curr; 77c2539483SSimon Glass }; 78c2539483SSimon Glass 79c2539483SSimon Glass struct hdmi_phy_config { 80c2539483SSimon Glass u64 mpixelclock; 81c2539483SSimon Glass u32 sym_ctr; /* clock symbol and transmitter control */ 82c2539483SSimon Glass u32 term; /* transmission termination value */ 83c2539483SSimon Glass u32 vlev_ctr; /* voltage level control */ 84c2539483SSimon Glass }; 85c2539483SSimon Glass 86c2539483SSimon Glass static const struct hdmi_phy_config rockchip_phy_config[] = { 87c2539483SSimon Glass { 88c2539483SSimon Glass .mpixelclock = 74250, 89c2539483SSimon Glass .sym_ctr = 0x8009, .term = 0x0004, .vlev_ctr = 0x0272, 90c2539483SSimon Glass }, { 91c2539483SSimon Glass .mpixelclock = 148500, 92c2539483SSimon Glass .sym_ctr = 0x802b, .term = 0x0004, .vlev_ctr = 0x028d, 93c2539483SSimon Glass }, { 94c2539483SSimon Glass .mpixelclock = 297000, 95c2539483SSimon Glass .sym_ctr = 0x8039, .term = 0x0005, .vlev_ctr = 0x028d, 96c2539483SSimon Glass }, { 97c2539483SSimon Glass .mpixelclock = ~0ul, 98c2539483SSimon Glass .sym_ctr = 0x0000, .term = 0x0000, .vlev_ctr = 0x0000, 99c2539483SSimon Glass } 100c2539483SSimon Glass }; 101c2539483SSimon Glass 102c2539483SSimon Glass static const struct hdmi_mpll_config rockchip_mpll_cfg[] = { 103c2539483SSimon Glass { 104c2539483SSimon Glass .mpixelclock = 40000, 105c2539483SSimon Glass .cpce = 0x00b3, .gmp = 0x0000, .curr = 0x0018, 106c2539483SSimon Glass }, { 107c2539483SSimon Glass .mpixelclock = 65000, 108c2539483SSimon Glass .cpce = 0x0072, .gmp = 0x0001, .curr = 0x0028, 109c2539483SSimon Glass }, { 110c2539483SSimon Glass .mpixelclock = 66000, 111c2539483SSimon Glass .cpce = 0x013e, .gmp = 0x0003, .curr = 0x0038, 112c2539483SSimon Glass }, { 113c2539483SSimon Glass .mpixelclock = 83500, 114c2539483SSimon Glass .cpce = 0x0072, .gmp = 0x0001, .curr = 0x0028, 115c2539483SSimon Glass }, { 116c2539483SSimon Glass .mpixelclock = 146250, 117c2539483SSimon Glass .cpce = 0x0051, .gmp = 0x0002, .curr = 0x0038, 118c2539483SSimon Glass }, { 119c2539483SSimon Glass .mpixelclock = 148500, 120c2539483SSimon Glass .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, 121c2539483SSimon Glass }, { 122c2539483SSimon Glass .mpixelclock = ~0ul, 123c2539483SSimon Glass .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, 124c2539483SSimon Glass } 125c2539483SSimon Glass }; 126c2539483SSimon Glass 127c2539483SSimon Glass static const u32 csc_coeff_default[3][4] = { 128c2539483SSimon Glass { 0x2000, 0x0000, 0x0000, 0x0000 }, 129c2539483SSimon Glass { 0x0000, 0x2000, 0x0000, 0x0000 }, 130c2539483SSimon Glass { 0x0000, 0x0000, 0x2000, 0x0000 } 131c2539483SSimon Glass }; 132c2539483SSimon Glass 133c2539483SSimon Glass static void hdmi_set_clock_regenerator(struct rk3288_hdmi *regs, u32 n, u32 cts) 134c2539483SSimon Glass { 135c2539483SSimon Glass u8 cts3; 136c2539483SSimon Glass u8 n3; 137c2539483SSimon Glass 138c2539483SSimon Glass /* first set ncts_atomic_write (if present) */ 139c2539483SSimon Glass n3 = HDMI_AUD_N3_NCTS_ATOMIC_WRITE; 140c2539483SSimon Glass writel(n3, ®s->aud_n3); 141c2539483SSimon Glass 142c2539483SSimon Glass /* set cts_manual (if present) */ 143c2539483SSimon Glass cts3 = HDMI_AUD_CTS3_CTS_MANUAL; 144c2539483SSimon Glass 145c2539483SSimon Glass cts3 |= HDMI_AUD_CTS3_N_SHIFT_1 << HDMI_AUD_CTS3_N_SHIFT_OFFSET; 146c2539483SSimon Glass cts3 |= (cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK; 147c2539483SSimon Glass 148c2539483SSimon Glass /* write cts values; cts3 must be written first */ 149c2539483SSimon Glass writel(cts3, ®s->aud_cts3); 150c2539483SSimon Glass writel((cts >> 8) & 0xff, ®s->aud_cts2); 151c2539483SSimon Glass writel(cts & 0xff, ®s->aud_cts1); 152c2539483SSimon Glass 153c2539483SSimon Glass /* write n values; n1 must be written last */ 154c2539483SSimon Glass n3 |= (n >> 16) & HDMI_AUD_N3_AUDN19_16_MASK; 155c2539483SSimon Glass writel(n3, ®s->aud_n3); 156c2539483SSimon Glass writel((n >> 8) & 0xff, ®s->aud_n2); 157c2539483SSimon Glass writel(n & 0xff, ®s->aud_n1); 158c2539483SSimon Glass 159c2539483SSimon Glass writel(HDMI_AUD_INPUTCLKFS_128, ®s->aud_inputclkfs); 160c2539483SSimon Glass } 161c2539483SSimon Glass 162c2539483SSimon Glass static int hdmi_lookup_n_cts(u32 pixel_clk) 163c2539483SSimon Glass { 164c2539483SSimon Glass int i; 165c2539483SSimon Glass 166c2539483SSimon Glass for (i = 0; i < ARRAY_SIZE(n_cts_table); i++) 167c2539483SSimon Glass if (pixel_clk <= n_cts_table[i].tmds) 168c2539483SSimon Glass break; 169c2539483SSimon Glass 170c2539483SSimon Glass if (i >= ARRAY_SIZE(n_cts_table)) 171c2539483SSimon Glass return -1; 172c2539483SSimon Glass 173c2539483SSimon Glass return i; 174c2539483SSimon Glass } 175c2539483SSimon Glass 176c2539483SSimon Glass static void hdmi_audio_set_samplerate(struct rk3288_hdmi *regs, u32 pixel_clk) 177c2539483SSimon Glass { 178c2539483SSimon Glass u32 clk_n, clk_cts; 179c2539483SSimon Glass int index; 180c2539483SSimon Glass 181c2539483SSimon Glass index = hdmi_lookup_n_cts(pixel_clk); 182c2539483SSimon Glass if (index == -1) { 183c2539483SSimon Glass debug("audio not supported for pixel clk %d\n", pixel_clk); 184c2539483SSimon Glass return; 185c2539483SSimon Glass } 186c2539483SSimon Glass 187c2539483SSimon Glass clk_n = n_cts_table[index].n; 188c2539483SSimon Glass clk_cts = n_cts_table[index].cts; 189c2539483SSimon Glass hdmi_set_clock_regenerator(regs, clk_n, clk_cts); 190c2539483SSimon Glass } 191c2539483SSimon Glass 192c2539483SSimon Glass /* 193c2539483SSimon Glass * this submodule is responsible for the video data synchronization. 194c2539483SSimon Glass * for example, for rgb 4:4:4 input, the data map is defined as 195c2539483SSimon Glass * pin{47~40} <==> r[7:0] 196c2539483SSimon Glass * pin{31~24} <==> g[7:0] 197c2539483SSimon Glass * pin{15~8} <==> b[7:0] 198c2539483SSimon Glass */ 199c2539483SSimon Glass static void hdmi_video_sample(struct rk3288_hdmi *regs) 200c2539483SSimon Glass { 201c2539483SSimon Glass u32 color_format = 0x01; 202c2539483SSimon Glass u8 val; 203c2539483SSimon Glass 204c2539483SSimon Glass val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE | 205c2539483SSimon Glass ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) & 206c2539483SSimon Glass HDMI_TX_INVID0_VIDEO_MAPPING_MASK); 207c2539483SSimon Glass 208c2539483SSimon Glass writel(val, ®s->tx_invid0); 209c2539483SSimon Glass 210c2539483SSimon Glass /* enable tx stuffing: when de is inactive, fix the output data to 0 */ 211c2539483SSimon Glass val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE | 212c2539483SSimon Glass HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE | 213c2539483SSimon Glass HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE; 214c2539483SSimon Glass writel(val, ®s->tx_instuffing); 215c2539483SSimon Glass writel(0x0, ®s->tx_gydata0); 216c2539483SSimon Glass writel(0x0, ®s->tx_gydata1); 217c2539483SSimon Glass writel(0x0, ®s->tx_rcrdata0); 218c2539483SSimon Glass writel(0x0, ®s->tx_rcrdata1); 219c2539483SSimon Glass writel(0x0, ®s->tx_bcbdata0); 220c2539483SSimon Glass writel(0x0, ®s->tx_bcbdata1); 221c2539483SSimon Glass } 222c2539483SSimon Glass 223c2539483SSimon Glass static void hdmi_update_csc_coeffs(struct rk3288_hdmi *regs) 224c2539483SSimon Glass { 225c2539483SSimon Glass u32 i, j; 226c2539483SSimon Glass u32 csc_scale = 1; 227c2539483SSimon Glass 228c2539483SSimon Glass /* the csc registers are sequential, alternating msb then lsb */ 229c2539483SSimon Glass for (i = 0; i < ARRAY_SIZE(csc_coeff_default); i++) { 230c2539483SSimon Glass for (j = 0; j < ARRAY_SIZE(csc_coeff_default[0]); j++) { 231c2539483SSimon Glass u32 coeff = csc_coeff_default[i][j]; 232c2539483SSimon Glass writel(coeff >> 8, ®s->csc_coef[i][j].msb); 233c2539483SSimon Glass writel(coeff && 0xff, ®s->csc_coef[i][j].lsb); 234c2539483SSimon Glass } 235c2539483SSimon Glass } 236c2539483SSimon Glass 237c2539483SSimon Glass clrsetbits_le32(®s->csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK, 238c2539483SSimon Glass csc_scale); 239c2539483SSimon Glass } 240c2539483SSimon Glass 241c2539483SSimon Glass static void hdmi_video_csc(struct rk3288_hdmi *regs) 242c2539483SSimon Glass { 243c2539483SSimon Glass u32 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP; 244c2539483SSimon Glass u32 interpolation = HDMI_CSC_CFG_INTMODE_DISABLE; 245c2539483SSimon Glass 246c2539483SSimon Glass /* configure the csc registers */ 247c2539483SSimon Glass writel(interpolation, ®s->csc_cfg); 248c2539483SSimon Glass clrsetbits_le32(®s->csc_scale, 249c2539483SSimon Glass HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK, color_depth); 250c2539483SSimon Glass 251c2539483SSimon Glass hdmi_update_csc_coeffs(regs); 252c2539483SSimon Glass } 253c2539483SSimon Glass 254c2539483SSimon Glass static void hdmi_video_packetize(struct rk3288_hdmi *regs) 255c2539483SSimon Glass { 256c2539483SSimon Glass u32 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; 257c2539483SSimon Glass u32 remap_size = HDMI_VP_REMAP_YCC422_16BIT; 258c2539483SSimon Glass u32 color_depth = 0; 259c2539483SSimon Glass u8 val, vp_conf; 260c2539483SSimon Glass 261c2539483SSimon Glass /* set the packetizer registers */ 262c2539483SSimon Glass val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & 263c2539483SSimon Glass HDMI_VP_PR_CD_COLOR_DEPTH_MASK) | 264c2539483SSimon Glass ((0 << HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) & 265c2539483SSimon Glass HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK); 266c2539483SSimon Glass writel(val, ®s->vp_pr_cd); 267c2539483SSimon Glass 268c2539483SSimon Glass clrsetbits_le32(®s->vp_stuff, HDMI_VP_STUFF_PR_STUFFING_MASK, 269c2539483SSimon Glass HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE); 270c2539483SSimon Glass 271c2539483SSimon Glass /* data from pixel repeater block */ 272c2539483SSimon Glass vp_conf = HDMI_VP_CONF_PR_EN_DISABLE | 273c2539483SSimon Glass HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; 274c2539483SSimon Glass 275c2539483SSimon Glass clrsetbits_le32(®s->vp_conf, HDMI_VP_CONF_PR_EN_MASK | 276c2539483SSimon Glass HDMI_VP_CONF_BYPASS_SELECT_MASK, vp_conf); 277c2539483SSimon Glass 278c2539483SSimon Glass clrsetbits_le32(®s->vp_stuff, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, 279c2539483SSimon Glass 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET); 280c2539483SSimon Glass 281c2539483SSimon Glass writel(remap_size, ®s->vp_remap); 282c2539483SSimon Glass 283c2539483SSimon Glass vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE | 284c2539483SSimon Glass HDMI_VP_CONF_PP_EN_DISABLE | 285c2539483SSimon Glass HDMI_VP_CONF_YCC422_EN_DISABLE; 286c2539483SSimon Glass 287c2539483SSimon Glass clrsetbits_le32(®s->vp_conf, HDMI_VP_CONF_BYPASS_EN_MASK | 288c2539483SSimon Glass HDMI_VP_CONF_PP_EN_ENMASK | HDMI_VP_CONF_YCC422_EN_MASK, 289c2539483SSimon Glass vp_conf); 290c2539483SSimon Glass 291c2539483SSimon Glass clrsetbits_le32(®s->vp_stuff, HDMI_VP_STUFF_PP_STUFFING_MASK | 292c2539483SSimon Glass HDMI_VP_STUFF_YCC422_STUFFING_MASK, 293c2539483SSimon Glass HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | 294c2539483SSimon Glass HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE); 295c2539483SSimon Glass 296c2539483SSimon Glass clrsetbits_le32(®s->vp_conf, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK, 297c2539483SSimon Glass output_select); 298c2539483SSimon Glass } 299c2539483SSimon Glass 300c2539483SSimon Glass static inline void hdmi_phy_test_clear(struct rk3288_hdmi *regs, u8 bit) 301c2539483SSimon Glass { 302c2539483SSimon Glass clrsetbits_le32(®s->phy_tst0, HDMI_PHY_TST0_TSTCLR_MASK, 303c2539483SSimon Glass bit << HDMI_PHY_TST0_TSTCLR_OFFSET); 304c2539483SSimon Glass } 305c2539483SSimon Glass 306c2539483SSimon Glass static int hdmi_phy_wait_i2c_done(struct rk3288_hdmi *regs, u32 msec) 307c2539483SSimon Glass { 308c2539483SSimon Glass ulong start; 309c2539483SSimon Glass u32 val; 310c2539483SSimon Glass 311c2539483SSimon Glass start = get_timer(0); 312c2539483SSimon Glass do { 313c2539483SSimon Glass val = readl(®s->ih_i2cmphy_stat0); 314c2539483SSimon Glass if (val & 0x3) { 315c2539483SSimon Glass writel(val, ®s->ih_i2cmphy_stat0); 316c2539483SSimon Glass return 0; 317c2539483SSimon Glass } 318c2539483SSimon Glass 319c2539483SSimon Glass udelay(100); 320c2539483SSimon Glass } while (get_timer(start) < msec); 321c2539483SSimon Glass 322c2539483SSimon Glass return 1; 323c2539483SSimon Glass } 324c2539483SSimon Glass 325c2539483SSimon Glass static void hdmi_phy_i2c_write(struct rk3288_hdmi *regs, uint data, uint addr) 326c2539483SSimon Glass { 327c2539483SSimon Glass writel(0xff, ®s->ih_i2cmphy_stat0); 328c2539483SSimon Glass writel(addr, ®s->phy_i2cm_address_addr); 329c2539483SSimon Glass writel((u8)(data >> 8), ®s->phy_i2cm_datao_1_addr); 330c2539483SSimon Glass writel((u8)(data >> 0), ®s->phy_i2cm_datao_0_addr); 331c2539483SSimon Glass writel(HDMI_PHY_I2CM_OPERATION_ADDR_WRITE, 332c2539483SSimon Glass ®s->phy_i2cm_operation_addr); 333c2539483SSimon Glass 334c2539483SSimon Glass hdmi_phy_wait_i2c_done(regs, 1000); 335c2539483SSimon Glass } 336c2539483SSimon Glass 337c2539483SSimon Glass static void hdmi_phy_enable_power(struct rk3288_hdmi *regs, uint enable) 338c2539483SSimon Glass { 339c2539483SSimon Glass clrsetbits_le32(®s->phy_conf0, HDMI_PHY_CONF0_PDZ_MASK, 340c2539483SSimon Glass enable << HDMI_PHY_CONF0_PDZ_OFFSET); 341c2539483SSimon Glass } 342c2539483SSimon Glass 343c2539483SSimon Glass static void hdmi_phy_enable_tmds(struct rk3288_hdmi *regs, uint enable) 344c2539483SSimon Glass { 345c2539483SSimon Glass clrsetbits_le32(®s->phy_conf0, HDMI_PHY_CONF0_ENTMDS_MASK, 346c2539483SSimon Glass enable << HDMI_PHY_CONF0_ENTMDS_OFFSET); 347c2539483SSimon Glass } 348c2539483SSimon Glass 349c2539483SSimon Glass static void hdmi_phy_enable_spare(struct rk3288_hdmi *regs, uint enable) 350c2539483SSimon Glass { 351c2539483SSimon Glass clrsetbits_le32(®s->phy_conf0, HDMI_PHY_CONF0_SPARECTRL_MASK, 352c2539483SSimon Glass enable << HDMI_PHY_CONF0_SPARECTRL_OFFSET); 353c2539483SSimon Glass } 354c2539483SSimon Glass 355c2539483SSimon Glass static void hdmi_phy_gen2_pddq(struct rk3288_hdmi *regs, uint enable) 356c2539483SSimon Glass { 357c2539483SSimon Glass clrsetbits_le32(®s->phy_conf0, HDMI_PHY_CONF0_GEN2_PDDQ_MASK, 358c2539483SSimon Glass enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET); 359c2539483SSimon Glass } 360c2539483SSimon Glass 361c2539483SSimon Glass static void hdmi_phy_gen2_txpwron(struct rk3288_hdmi *regs, uint enable) 362c2539483SSimon Glass { 363c2539483SSimon Glass clrsetbits_le32(®s->phy_conf0, 364c2539483SSimon Glass HDMI_PHY_CONF0_GEN2_TXPWRON_MASK, 365c2539483SSimon Glass enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET); 366c2539483SSimon Glass } 367c2539483SSimon Glass 368c2539483SSimon Glass static void hdmi_phy_sel_data_en_pol(struct rk3288_hdmi *regs, uint enable) 369c2539483SSimon Glass { 370c2539483SSimon Glass clrsetbits_le32(®s->phy_conf0, 371c2539483SSimon Glass HDMI_PHY_CONF0_SELDATAENPOL_MASK, 372c2539483SSimon Glass enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET); 373c2539483SSimon Glass } 374c2539483SSimon Glass 375c2539483SSimon Glass static void hdmi_phy_sel_interface_control(struct rk3288_hdmi *regs, 376c2539483SSimon Glass uint enable) 377c2539483SSimon Glass { 378c2539483SSimon Glass clrsetbits_le32(®s->phy_conf0, HDMI_PHY_CONF0_SELDIPIF_MASK, 379c2539483SSimon Glass enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET); 380c2539483SSimon Glass } 381c2539483SSimon Glass 382c2539483SSimon Glass static int hdmi_phy_configure(struct rk3288_hdmi *regs, u32 mpixelclock) 383c2539483SSimon Glass { 384c2539483SSimon Glass ulong start; 385c2539483SSimon Glass u8 i, val; 386c2539483SSimon Glass 387c2539483SSimon Glass writel(HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS, 388c2539483SSimon Glass ®s->mc_flowctrl); 389c2539483SSimon Glass 390c2539483SSimon Glass /* gen2 tx power off */ 391c2539483SSimon Glass hdmi_phy_gen2_txpwron(regs, 0); 392c2539483SSimon Glass 393c2539483SSimon Glass /* gen2 pddq */ 394c2539483SSimon Glass hdmi_phy_gen2_pddq(regs, 1); 395c2539483SSimon Glass 396c2539483SSimon Glass /* phy reset */ 397c2539483SSimon Glass writel(HDMI_MC_PHYRSTZ_DEASSERT, ®s->mc_phyrstz); 398c2539483SSimon Glass writel(HDMI_MC_PHYRSTZ_ASSERT, ®s->mc_phyrstz); 399c2539483SSimon Glass writel(HDMI_MC_HEACPHY_RST_ASSERT, ®s->mc_heacphy_rst); 400c2539483SSimon Glass 401c2539483SSimon Glass hdmi_phy_test_clear(regs, 1); 402c2539483SSimon Glass writel(HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2, ®s->phy_i2cm_slave_addr); 403c2539483SSimon Glass hdmi_phy_test_clear(regs, 0); 404c2539483SSimon Glass 405c2539483SSimon Glass /* pll/mpll cfg - always match on final entry */ 406c2539483SSimon Glass for (i = 0; rockchip_mpll_cfg[i].mpixelclock != (~0ul); i++) 407c2539483SSimon Glass if (mpixelclock <= rockchip_mpll_cfg[i].mpixelclock) 408c2539483SSimon Glass break; 409c2539483SSimon Glass 410c2539483SSimon Glass hdmi_phy_i2c_write(regs, rockchip_mpll_cfg[i].cpce, PHY_OPMODE_PLLCFG); 411c2539483SSimon Glass hdmi_phy_i2c_write(regs, rockchip_mpll_cfg[i].gmp, PHY_PLLGMPCTRL); 412c2539483SSimon Glass hdmi_phy_i2c_write(regs, rockchip_mpll_cfg[i].curr, PHY_PLLCURRCTRL); 413c2539483SSimon Glass 414c2539483SSimon Glass hdmi_phy_i2c_write(regs, 0x0000, PHY_PLLPHBYCTRL); 415c2539483SSimon Glass hdmi_phy_i2c_write(regs, 0x0006, PHY_PLLCLKBISTPHASE); 416c2539483SSimon Glass 417c2539483SSimon Glass for (i = 0; rockchip_phy_config[i].mpixelclock != (~0ul); i++) 418c2539483SSimon Glass if (mpixelclock <= rockchip_phy_config[i].mpixelclock) 419c2539483SSimon Glass break; 420c2539483SSimon Glass 421c2539483SSimon Glass /* 422c2539483SSimon Glass * resistance term 133ohm cfg 423c2539483SSimon Glass * preemp cgf 0.00 424c2539483SSimon Glass * tx/ck lvl 10 425c2539483SSimon Glass */ 426c2539483SSimon Glass hdmi_phy_i2c_write(regs, rockchip_phy_config[i].term, PHY_TXTERM); 427c2539483SSimon Glass hdmi_phy_i2c_write(regs, rockchip_phy_config[i].sym_ctr, 428c2539483SSimon Glass PHY_CKSYMTXCTRL); 429c2539483SSimon Glass hdmi_phy_i2c_write(regs, rockchip_phy_config[i].vlev_ctr, PHY_VLEVCTRL); 430c2539483SSimon Glass 431c2539483SSimon Glass /* remove clk term */ 432c2539483SSimon Glass hdmi_phy_i2c_write(regs, 0x8000, PHY_CKCALCTRL); 433c2539483SSimon Glass 434c2539483SSimon Glass hdmi_phy_enable_power(regs, 1); 435c2539483SSimon Glass 436c2539483SSimon Glass /* toggle tmds enable */ 437c2539483SSimon Glass hdmi_phy_enable_tmds(regs, 0); 438c2539483SSimon Glass hdmi_phy_enable_tmds(regs, 1); 439c2539483SSimon Glass 440c2539483SSimon Glass /* gen2 tx power on */ 441c2539483SSimon Glass hdmi_phy_gen2_txpwron(regs, 1); 442c2539483SSimon Glass hdmi_phy_gen2_pddq(regs, 0); 443c2539483SSimon Glass 444c2539483SSimon Glass hdmi_phy_enable_spare(regs, 1); 445c2539483SSimon Glass 446c2539483SSimon Glass /* wait for phy pll lock */ 447c2539483SSimon Glass start = get_timer(0); 448c2539483SSimon Glass do { 449c2539483SSimon Glass val = readl(®s->phy_stat0); 450c2539483SSimon Glass if (!(val & HDMI_PHY_TX_PHY_LOCK)) 451c2539483SSimon Glass return 0; 452c2539483SSimon Glass 453c2539483SSimon Glass udelay(100); 454c2539483SSimon Glass } while (get_timer(start) < 5); 455c2539483SSimon Glass 456c2539483SSimon Glass return -1; 457c2539483SSimon Glass } 458c2539483SSimon Glass 459c2539483SSimon Glass static int hdmi_phy_init(struct rk3288_hdmi *regs, uint mpixelclock) 460c2539483SSimon Glass { 461c2539483SSimon Glass int i, ret; 462c2539483SSimon Glass 463c2539483SSimon Glass /* hdmi phy spec says to do the phy initialization sequence twice */ 464c2539483SSimon Glass for (i = 0; i < 2; i++) { 465c2539483SSimon Glass hdmi_phy_sel_data_en_pol(regs, 1); 466c2539483SSimon Glass hdmi_phy_sel_interface_control(regs, 0); 467c2539483SSimon Glass hdmi_phy_enable_tmds(regs, 0); 468c2539483SSimon Glass hdmi_phy_enable_power(regs, 0); 469c2539483SSimon Glass 470c2539483SSimon Glass /* enable csc */ 471c2539483SSimon Glass ret = hdmi_phy_configure(regs, mpixelclock); 472c2539483SSimon Glass if (ret) { 473c2539483SSimon Glass debug("hdmi phy config failure %d\n", ret); 474c2539483SSimon Glass return ret; 475c2539483SSimon Glass } 476c2539483SSimon Glass } 477c2539483SSimon Glass 478c2539483SSimon Glass return 0; 479c2539483SSimon Glass } 480c2539483SSimon Glass 481c2539483SSimon Glass static void hdmi_av_composer(struct rk3288_hdmi *regs, 482c2539483SSimon Glass const struct display_timing *edid) 483c2539483SSimon Glass { 484c2539483SSimon Glass u8 mdataenablepolarity = 1; 485c2539483SSimon Glass u8 inv_val; 486c2539483SSimon Glass uint hbl; 487c2539483SSimon Glass uint vbl; 488c2539483SSimon Glass 489c2539483SSimon Glass hbl = edid->hback_porch.typ + edid->hfront_porch.typ + 490c2539483SSimon Glass edid->hsync_len.typ; 491c2539483SSimon Glass vbl = edid->vback_porch.typ + edid->vfront_porch.typ + 492c2539483SSimon Glass edid->vsync_len.typ; 493c2539483SSimon Glass 494c2539483SSimon Glass /* set up hdmi_fc_invidconf */ 495c2539483SSimon Glass inv_val = HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE; 496c2539483SSimon Glass 497c2539483SSimon Glass inv_val |= (edid->flags & DISPLAY_FLAGS_HSYNC_HIGH ? 498c2539483SSimon Glass HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH : 499c2539483SSimon Glass HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW); 500c2539483SSimon Glass 501c2539483SSimon Glass inv_val |= (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH ? 502c2539483SSimon Glass HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH : 503c2539483SSimon Glass HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW); 504c2539483SSimon Glass 505c2539483SSimon Glass inv_val |= (mdataenablepolarity ? 506c2539483SSimon Glass HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH : 507c2539483SSimon Glass HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW); 508c2539483SSimon Glass 509c2539483SSimon Glass /* 510c2539483SSimon Glass * TODO(sjg@chromium.org>: Need to check for HDMI / DVI 511c2539483SSimon Glass * inv_val |= (edid->hdmi_monitor_detected ? 512c2539483SSimon Glass * HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE : 513c2539483SSimon Glass * HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE); 514c2539483SSimon Glass */ 515c2539483SSimon Glass inv_val |= HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE; 516c2539483SSimon Glass 517c2539483SSimon Glass inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW; 518c2539483SSimon Glass 519c2539483SSimon Glass inv_val |= HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE; 520c2539483SSimon Glass 521c2539483SSimon Glass writel(inv_val, ®s->fc_invidconf); 522c2539483SSimon Glass 523c2539483SSimon Glass /* set up horizontal active pixel width */ 524c2539483SSimon Glass writel(edid->hactive.typ >> 8, ®s->fc_inhactv1); 525c2539483SSimon Glass writel(edid->hactive.typ, ®s->fc_inhactv0); 526c2539483SSimon Glass 527c2539483SSimon Glass /* set up vertical active lines */ 528c2539483SSimon Glass writel(edid->vactive.typ >> 8, ®s->fc_invactv1); 529c2539483SSimon Glass writel(edid->vactive.typ, ®s->fc_invactv0); 530c2539483SSimon Glass 531c2539483SSimon Glass /* set up horizontal blanking pixel region width */ 532c2539483SSimon Glass writel(hbl >> 8, ®s->fc_inhblank1); 533c2539483SSimon Glass writel(hbl, ®s->fc_inhblank0); 534c2539483SSimon Glass 535c2539483SSimon Glass /* set up vertical blanking pixel region width */ 536c2539483SSimon Glass writel(vbl, ®s->fc_invblank); 537c2539483SSimon Glass 538c2539483SSimon Glass /* set up hsync active edge delay width (in pixel clks) */ 539c2539483SSimon Glass writel(edid->hfront_porch.typ >> 8, ®s->fc_hsyncindelay1); 540c2539483SSimon Glass writel(edid->hfront_porch.typ, ®s->fc_hsyncindelay0); 541c2539483SSimon Glass 542c2539483SSimon Glass /* set up vsync active edge delay (in lines) */ 543c2539483SSimon Glass writel(edid->vfront_porch.typ, ®s->fc_vsyncindelay); 544c2539483SSimon Glass 545c2539483SSimon Glass /* set up hsync active pulse width (in pixel clks) */ 546c2539483SSimon Glass writel(edid->hsync_len.typ >> 8, ®s->fc_hsyncinwidth1); 547c2539483SSimon Glass writel(edid->hsync_len.typ, ®s->fc_hsyncinwidth0); 548c2539483SSimon Glass 549c2539483SSimon Glass /* set up vsync active edge delay (in lines) */ 550c2539483SSimon Glass writel(edid->vsync_len.typ, ®s->fc_vsyncinwidth); 551c2539483SSimon Glass } 552c2539483SSimon Glass 553c2539483SSimon Glass /* hdmi initialization step b.4 */ 554c2539483SSimon Glass static void hdmi_enable_video_path(struct rk3288_hdmi *regs) 555c2539483SSimon Glass { 556c2539483SSimon Glass u8 clkdis; 557c2539483SSimon Glass 558c2539483SSimon Glass /* control period minimum duration */ 559c2539483SSimon Glass writel(12, ®s->fc_ctrldur); 560c2539483SSimon Glass writel(32, ®s->fc_exctrldur); 561c2539483SSimon Glass writel(1, ®s->fc_exctrlspac); 562c2539483SSimon Glass 563c2539483SSimon Glass /* set to fill tmds data channels */ 564c2539483SSimon Glass writel(0x0b, ®s->fc_ch0pream); 565c2539483SSimon Glass writel(0x16, ®s->fc_ch1pream); 566c2539483SSimon Glass writel(0x21, ®s->fc_ch2pream); 567c2539483SSimon Glass 568c2539483SSimon Glass /* enable pixel clock and tmds data path */ 569c2539483SSimon Glass clkdis = 0x7f; 570c2539483SSimon Glass clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; 571c2539483SSimon Glass writel(clkdis, ®s->mc_clkdis); 572c2539483SSimon Glass 573c2539483SSimon Glass clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; 574c2539483SSimon Glass writel(clkdis, ®s->mc_clkdis); 575c2539483SSimon Glass 576c2539483SSimon Glass clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; 577c2539483SSimon Glass writel(clkdis, ®s->mc_clkdis); 578c2539483SSimon Glass } 579c2539483SSimon Glass 580c2539483SSimon Glass /* workaround to clear the overflow condition */ 581c2539483SSimon Glass static void hdmi_clear_overflow(struct rk3288_hdmi *regs) 582c2539483SSimon Glass { 583c2539483SSimon Glass u8 val, count; 584c2539483SSimon Glass 585c2539483SSimon Glass /* tmds software reset */ 586c2539483SSimon Glass writel((u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, ®s->mc_swrstz); 587c2539483SSimon Glass 588c2539483SSimon Glass val = readl(®s->fc_invidconf); 589c2539483SSimon Glass 590c2539483SSimon Glass for (count = 0; count < 4; count++) 591c2539483SSimon Glass writel(val, ®s->fc_invidconf); 592c2539483SSimon Glass } 593c2539483SSimon Glass 594c2539483SSimon Glass static void hdmi_audio_set_format(struct rk3288_hdmi *regs) 595c2539483SSimon Glass { 596c2539483SSimon Glass writel(HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_IN_EN_0, 597c2539483SSimon Glass ®s->aud_conf0); 598c2539483SSimon Glass 599c2539483SSimon Glass 600c2539483SSimon Glass writel(HDMI_AUD_CONF1_I2S_MODE_STANDARD_MODE | 601c2539483SSimon Glass HDMI_AUD_CONF1_I2S_WIDTH_16BIT, ®s->aud_conf1); 602c2539483SSimon Glass 603c2539483SSimon Glass writel(0x00, ®s->aud_conf2); 604c2539483SSimon Glass } 605c2539483SSimon Glass 606c2539483SSimon Glass static void hdmi_audio_fifo_reset(struct rk3288_hdmi *regs) 607c2539483SSimon Glass { 608c2539483SSimon Glass writel((u8)~HDMI_MC_SWRSTZ_II2SSWRST_REQ, ®s->mc_swrstz); 609c2539483SSimon Glass writel(HDMI_AUD_CONF0_SW_AUDIO_FIFO_RST, ®s->aud_conf0); 610c2539483SSimon Glass 611c2539483SSimon Glass writel(0x00, ®s->aud_int); 612c2539483SSimon Glass writel(0x00, ®s->aud_int1); 613c2539483SSimon Glass } 614c2539483SSimon Glass 615c2539483SSimon Glass static void hdmi_init_interrupt(struct rk3288_hdmi *regs) 616c2539483SSimon Glass { 617c2539483SSimon Glass u8 ih_mute; 618c2539483SSimon Glass 619c2539483SSimon Glass /* 620c2539483SSimon Glass * boot up defaults are: 621c2539483SSimon Glass * hdmi_ih_mute = 0x03 (disabled) 622c2539483SSimon Glass * hdmi_ih_mute_* = 0x00 (enabled) 623c2539483SSimon Glass * 624c2539483SSimon Glass * disable top level interrupt bits in hdmi block 625c2539483SSimon Glass */ 626c2539483SSimon Glass ih_mute = readl(®s->ih_mute) | 627c2539483SSimon Glass HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT | 628c2539483SSimon Glass HDMI_IH_MUTE_MUTE_ALL_INTERRUPT; 629c2539483SSimon Glass 630c2539483SSimon Glass writel(ih_mute, ®s->ih_mute); 631c2539483SSimon Glass 632c2539483SSimon Glass /* enable i2c master done irq */ 633c2539483SSimon Glass writel(~0x04, ®s->i2cm_int); 634c2539483SSimon Glass 635c2539483SSimon Glass /* enable i2c client nack % arbitration error irq */ 636c2539483SSimon Glass writel(~0x44, ®s->i2cm_ctlint); 637c2539483SSimon Glass 638c2539483SSimon Glass /* enable phy i2cm done irq */ 639c2539483SSimon Glass writel(HDMI_PHY_I2CM_INT_ADDR_DONE_POL, ®s->phy_i2cm_int_addr); 640c2539483SSimon Glass 641c2539483SSimon Glass /* enable phy i2cm nack & arbitration error irq */ 642c2539483SSimon Glass writel(HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL | 643c2539483SSimon Glass HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL, 644c2539483SSimon Glass ®s->phy_i2cm_ctlint_addr); 645c2539483SSimon Glass 646c2539483SSimon Glass /* enable cable hot plug irq */ 647c2539483SSimon Glass writel((u8)~HDMI_PHY_HPD, ®s->phy_mask0); 648c2539483SSimon Glass 649c2539483SSimon Glass /* clear hotplug interrupts */ 650c2539483SSimon Glass writel(HDMI_IH_PHY_STAT0_HPD, ®s->ih_phy_stat0); 651c2539483SSimon Glass } 652c2539483SSimon Glass 653c2539483SSimon Glass static u8 hdmi_get_plug_in_status(struct rk3288_hdmi *regs) 654c2539483SSimon Glass { 655c2539483SSimon Glass u8 val = readl(®s->phy_stat0) & HDMI_PHY_HPD; 656c2539483SSimon Glass 657c2539483SSimon Glass return !!(val); 658c2539483SSimon Glass } 659c2539483SSimon Glass 660c2539483SSimon Glass static int hdmi_wait_for_hpd(struct rk3288_hdmi *regs) 661c2539483SSimon Glass { 662c2539483SSimon Glass ulong start; 663c2539483SSimon Glass 664c2539483SSimon Glass start = get_timer(0); 665c2539483SSimon Glass do { 666c2539483SSimon Glass if (hdmi_get_plug_in_status(regs)) 667c2539483SSimon Glass return 0; 668c2539483SSimon Glass udelay(100); 66970c440e5SSjoerd Simons } while (get_timer(start) < 300); 670c2539483SSimon Glass 671c2539483SSimon Glass return -1; 672c2539483SSimon Glass } 673c2539483SSimon Glass 674c2539483SSimon Glass static int hdmi_ddc_wait_i2c_done(struct rk3288_hdmi *regs, int msec) 675c2539483SSimon Glass { 676c2539483SSimon Glass u32 val; 677c2539483SSimon Glass ulong start; 678c2539483SSimon Glass 679c2539483SSimon Glass start = get_timer(0); 680c2539483SSimon Glass do { 681c2539483SSimon Glass val = readl(®s->ih_i2cm_stat0); 682c2539483SSimon Glass if (val & 0x2) { 683c2539483SSimon Glass writel(val, ®s->ih_i2cm_stat0); 684c2539483SSimon Glass return 0; 685c2539483SSimon Glass } 686c2539483SSimon Glass 687c2539483SSimon Glass udelay(100); 688c2539483SSimon Glass } while (get_timer(start) < msec); 689c2539483SSimon Glass 690c2539483SSimon Glass return 1; 691c2539483SSimon Glass } 692c2539483SSimon Glass 693c2539483SSimon Glass static void hdmi_ddc_reset(struct rk3288_hdmi *regs) 694c2539483SSimon Glass { 695c2539483SSimon Glass clrbits_le32(®s->i2cm_softrstz, HDMI_I2CM_SOFTRSTZ); 696c2539483SSimon Glass } 697c2539483SSimon Glass 698c2539483SSimon Glass static int hdmi_read_edid(struct rk3288_hdmi *regs, int block, u8 *buff) 699c2539483SSimon Glass { 700c2539483SSimon Glass int shift = (block % 2) * 0x80; 701c2539483SSimon Glass int edid_read_err = 0; 702c2539483SSimon Glass u32 trytime = 5; 703c2539483SSimon Glass u32 n, j, val; 704c2539483SSimon Glass 705c2539483SSimon Glass /* set ddc i2c clk which devided from ddc_clk to 100khz */ 706c2539483SSimon Glass writel(0x7a, ®s->i2cm_ss_scl_hcnt_0_addr); 707c2539483SSimon Glass writel(0x8d, ®s->i2cm_ss_scl_lcnt_0_addr); 708c2539483SSimon Glass 709c2539483SSimon Glass /* 710c2539483SSimon Glass * TODO(sjg@chromium.org): The above values don't work - these ones 711c2539483SSimon Glass * work better, but generate lots of errors in the data. 712c2539483SSimon Glass */ 713c2539483SSimon Glass writel(0x0d, ®s->i2cm_ss_scl_hcnt_0_addr); 714c2539483SSimon Glass writel(0x0d, ®s->i2cm_ss_scl_lcnt_0_addr); 715c2539483SSimon Glass clrsetbits_le32(®s->i2cm_div, HDMI_I2CM_DIV_FAST_STD_MODE, 716c2539483SSimon Glass HDMI_I2CM_DIV_STD_MODE); 717c2539483SSimon Glass 718c2539483SSimon Glass writel(HDMI_I2CM_SLAVE_DDC_ADDR, ®s->i2cm_slave); 719c2539483SSimon Glass writel(HDMI_I2CM_SEGADDR_DDC, ®s->i2cm_segaddr); 720c2539483SSimon Glass writel(block >> 1, ®s->i2cm_segptr); 721c2539483SSimon Glass 722c2539483SSimon Glass while (trytime--) { 723c2539483SSimon Glass edid_read_err = 0; 724c2539483SSimon Glass 725c2539483SSimon Glass for (n = 0; n < HDMI_EDID_BLOCK_SIZE / 8; n++) { 726c2539483SSimon Glass writel(shift + 8 * n, ®s->i2c_address); 727c2539483SSimon Glass 728c2539483SSimon Glass if (block == 0) 729c2539483SSimon Glass clrsetbits_le32(®s->i2cm_operation, 730c2539483SSimon Glass HDMI_I2CM_OPT_RD8, 731c2539483SSimon Glass HDMI_I2CM_OPT_RD8); 732c2539483SSimon Glass else 733c2539483SSimon Glass clrsetbits_le32(®s->i2cm_operation, 734c2539483SSimon Glass HDMI_I2CM_OPT_RD8_EXT, 735c2539483SSimon Glass HDMI_I2CM_OPT_RD8_EXT); 736c2539483SSimon Glass 737c2539483SSimon Glass if (hdmi_ddc_wait_i2c_done(regs, 10)) { 738c2539483SSimon Glass hdmi_ddc_reset(regs); 739c2539483SSimon Glass edid_read_err = 1; 740c2539483SSimon Glass break; 741c2539483SSimon Glass } 742c2539483SSimon Glass 743c2539483SSimon Glass for (j = 0; j < 8; j++) { 744c2539483SSimon Glass val = readl(®s->i2cm_buf0 + j); 745c2539483SSimon Glass buff[8 * n + j] = val; 746c2539483SSimon Glass } 747c2539483SSimon Glass } 748c2539483SSimon Glass 749c2539483SSimon Glass if (!edid_read_err) 750c2539483SSimon Glass break; 751c2539483SSimon Glass } 752c2539483SSimon Glass 753c2539483SSimon Glass return edid_read_err; 754c2539483SSimon Glass } 755c2539483SSimon Glass 756c2539483SSimon Glass static u8 pre_buf[] = { 757c2539483SSimon Glass 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 758c2539483SSimon Glass 0x04, 0x69, 0xfa, 0x23, 0xc8, 0x28, 0x01, 0x00, 759c2539483SSimon Glass 0x10, 0x17, 0x01, 0x03, 0x80, 0x33, 0x1d, 0x78, 760c2539483SSimon Glass 0x2a, 0xd9, 0x45, 0xa2, 0x55, 0x4d, 0xa0, 0x27, 761c2539483SSimon Glass 0x12, 0x50, 0x54, 0xb7, 0xef, 0x00, 0x71, 0x4f, 762c2539483SSimon Glass 0x81, 0x40, 0x81, 0x80, 0x95, 0x00, 0xb3, 0x00, 763c2539483SSimon Glass 0xd1, 0xc0, 0x81, 0xc0, 0x81, 0x00, 0x02, 0x3a, 764c2539483SSimon Glass 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, 765c2539483SSimon Glass 0x45, 0x00, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e, 766c2539483SSimon Glass 0x00, 0x00, 0x00, 0xff, 0x00, 0x44, 0x34, 0x4c, 767c2539483SSimon Glass 0x4d, 0x54, 0x46, 0x30, 0x37, 0x35, 0x39, 0x37, 768c2539483SSimon Glass 0x36, 0x0a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, 769c2539483SSimon Glass 0x4b, 0x18, 0x53, 0x11, 0x00, 0x0a, 0x20, 0x20, 770c2539483SSimon Glass 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 771c2539483SSimon Glass 0x00, 0x41, 0x53, 0x55, 0x53, 0x20, 0x56, 0x53, 772c2539483SSimon Glass 0x32, 0x33, 0x38, 0x0a, 0x20, 0x20, 0x01, 0xb0, 773c2539483SSimon Glass 0x02, 0x03, 0x22, 0x71, 0x4f, 0x01, 0x02, 0x03, 774c2539483SSimon Glass 0x11, 0x12, 0x13, 0x04, 0x14, 0x05, 0x0e, 0x0f, 775c2539483SSimon Glass 0x1d, 0x1e, 0x1f, 0x10, 0x23, 0x09, 0x17, 0x07, 776c2539483SSimon Glass 0x83, 0x01, 0x00, 0x00, 0x65, 0x03, 0x0c, 0x00, 777c2539483SSimon Glass 0x10, 0x00, 0x8c, 0x0a, 0xd0, 0x8a, 0x20, 0xe0, 778c2539483SSimon Glass 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xfd, 0x1e, 779c2539483SSimon Glass 0x11, 0x00, 0x00, 0x18, 0x01, 0x1d, 0x00, 0x72, 780c2539483SSimon Glass 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00, 781c2539483SSimon Glass 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e, 0x01, 0x1d, 782c2539483SSimon Glass 0x00, 0xbc, 0x52, 0xd0, 0x1e, 0x20, 0xb8, 0x28, 783c2539483SSimon Glass 0x55, 0x40, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e, 784c2539483SSimon Glass 0x8c, 0x0a, 0xd0, 0x90, 0x20, 0x40, 0x31, 0x20, 785c2539483SSimon Glass 0x0c, 0x40, 0x55, 0x00, 0xfd, 0x1e, 0x11, 0x00, 786c2539483SSimon Glass 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 787c2539483SSimon Glass 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 788c2539483SSimon Glass 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 789c2539483SSimon Glass }; 790c2539483SSimon Glass 791c2539483SSimon Glass static int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) 792c2539483SSimon Glass { 793c2539483SSimon Glass struct rk_hdmi_priv *priv = dev_get_priv(dev); 794c2539483SSimon Glass u32 edid_size = HDMI_EDID_BLOCK_SIZE; 795c2539483SSimon Glass int ret; 796c2539483SSimon Glass 797c2539483SSimon Glass if (0) { 798c2539483SSimon Glass edid_size = sizeof(pre_buf); 799c2539483SSimon Glass memcpy(buf, pre_buf, edid_size); 800c2539483SSimon Glass } else { 801c2539483SSimon Glass ret = hdmi_read_edid(priv->regs, 0, buf); 802c2539483SSimon Glass if (ret) { 803c2539483SSimon Glass debug("failed to read edid.\n"); 804c2539483SSimon Glass return -1; 805c2539483SSimon Glass } 806c2539483SSimon Glass 807c2539483SSimon Glass if (buf[0x7e] != 0) { 808c2539483SSimon Glass hdmi_read_edid(priv->regs, 1, 809c2539483SSimon Glass buf + HDMI_EDID_BLOCK_SIZE); 810c2539483SSimon Glass edid_size += HDMI_EDID_BLOCK_SIZE; 811c2539483SSimon Glass } 812c2539483SSimon Glass } 813c2539483SSimon Glass 814c2539483SSimon Glass return edid_size; 815c2539483SSimon Glass } 816c2539483SSimon Glass 817c2539483SSimon Glass static int rk_hdmi_enable(struct udevice *dev, int panel_bpp, 818c2539483SSimon Glass const struct display_timing *edid) 819c2539483SSimon Glass { 820c2539483SSimon Glass struct rk_hdmi_priv *priv = dev_get_priv(dev); 821c2539483SSimon Glass struct rk3288_hdmi *regs = priv->regs; 822c2539483SSimon Glass int ret; 823c2539483SSimon Glass 824c2539483SSimon Glass debug("hdmi, mode info : clock %d hdis %d vdis %d\n", 825c2539483SSimon Glass edid->pixelclock.typ, edid->hactive.typ, edid->vactive.typ); 826c2539483SSimon Glass 827c2539483SSimon Glass hdmi_av_composer(regs, edid); 828c2539483SSimon Glass 829c2539483SSimon Glass ret = hdmi_phy_init(regs, edid->pixelclock.typ); 830c2539483SSimon Glass if (ret) 831c2539483SSimon Glass return ret; 832c2539483SSimon Glass 833c2539483SSimon Glass hdmi_enable_video_path(regs); 834c2539483SSimon Glass 835c2539483SSimon Glass hdmi_audio_fifo_reset(regs); 836c2539483SSimon Glass hdmi_audio_set_format(regs); 837c2539483SSimon Glass hdmi_audio_set_samplerate(regs, edid->pixelclock.typ); 838c2539483SSimon Glass 839c2539483SSimon Glass hdmi_video_packetize(regs); 840c2539483SSimon Glass hdmi_video_csc(regs); 841c2539483SSimon Glass hdmi_video_sample(regs); 842c2539483SSimon Glass 843c2539483SSimon Glass hdmi_clear_overflow(regs); 844c2539483SSimon Glass 845c2539483SSimon Glass return 0; 846c2539483SSimon Glass } 847c2539483SSimon Glass 848c2539483SSimon Glass static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) 849c2539483SSimon Glass { 850c2539483SSimon Glass struct rk_hdmi_priv *priv = dev_get_priv(dev); 851c2539483SSimon Glass 852c2539483SSimon Glass priv->regs = (struct rk3288_hdmi *)dev_get_addr(dev); 853c2539483SSimon Glass priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); 854c2539483SSimon Glass 855c2539483SSimon Glass return 0; 856c2539483SSimon Glass } 857c2539483SSimon Glass 858c2539483SSimon Glass static int rk_hdmi_probe(struct udevice *dev) 859c2539483SSimon Glass { 860c2539483SSimon Glass struct display_plat *uc_plat = dev_get_uclass_platdata(dev); 861c2539483SSimon Glass struct rk_hdmi_priv *priv = dev_get_priv(dev); 862135aa950SStephen Warren struct udevice *reg; 863135aa950SStephen Warren struct clk clk; 864c2539483SSimon Glass int ret; 865c2539483SSimon Glass int vop_id = uc_plat->source_id; 866c2539483SSimon Glass 867c2539483SSimon Glass ret = clk_get_by_index(dev, 0, &clk); 868c2539483SSimon Glass if (ret >= 0) { 869135aa950SStephen Warren ret = clk_set_rate(&clk, 0); 870135aa950SStephen Warren clk_free(&clk); 871c2539483SSimon Glass } 872c2539483SSimon Glass if (ret) { 873c2539483SSimon Glass debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret); 874c2539483SSimon Glass return ret; 875c2539483SSimon Glass } 876c2539483SSimon Glass 877c2539483SSimon Glass /* 878c2539483SSimon Glass * Configure the maximum clock to permit whatever resolution the 879c2539483SSimon Glass * monitor wants 880c2539483SSimon Glass */ 881c2539483SSimon Glass ret = clk_get_by_index(uc_plat->src_dev, 0, &clk); 882c2539483SSimon Glass if (ret >= 0) { 883135aa950SStephen Warren ret = clk_set_rate(&clk, 384000000); 884135aa950SStephen Warren clk_free(&clk); 885c2539483SSimon Glass } 886c2539483SSimon Glass if (ret < 0) { 887c2539483SSimon Glass debug("%s: Failed to set clock in source device '%s': ret=%d\n", 888c2539483SSimon Glass __func__, uc_plat->src_dev->name, ret); 889c2539483SSimon Glass return ret; 890c2539483SSimon Glass } 891c2539483SSimon Glass 892c2539483SSimon Glass ret = regulator_get_by_platname("vcc50_hdmi", ®); 893c2539483SSimon Glass if (!ret) 894c2539483SSimon Glass ret = regulator_set_enable(reg, true); 895c2539483SSimon Glass if (ret) 896c2539483SSimon Glass debug("%s: Cannot set regulator vcc50_hdmi\n", __func__); 897c2539483SSimon Glass 898c2539483SSimon Glass /* hdmi source select hdmi controller */ 899c2539483SSimon Glass rk_setreg(&priv->grf->soc_con6, 1 << 15); 900c2539483SSimon Glass 901c2539483SSimon Glass /* hdmi data from vop id */ 902*e4ab3d71SSimon Glass rk_clrsetreg(&priv->grf->soc_con6, 1 << 4, 903*e4ab3d71SSimon Glass (vop_id == 1) ? (1 << 4) : 0); 904c2539483SSimon Glass 905c2539483SSimon Glass ret = hdmi_wait_for_hpd(priv->regs); 906c2539483SSimon Glass if (ret < 0) { 907c2539483SSimon Glass debug("hdmi can not get hpd signal\n"); 908c2539483SSimon Glass return -1; 909c2539483SSimon Glass } 910c2539483SSimon Glass 911c2539483SSimon Glass hdmi_init_interrupt(priv->regs); 912c2539483SSimon Glass 913c2539483SSimon Glass return 0; 914c2539483SSimon Glass } 915c2539483SSimon Glass 916c2539483SSimon Glass static const struct dm_display_ops rk_hdmi_ops = { 917c2539483SSimon Glass .read_edid = rk_hdmi_read_edid, 918c2539483SSimon Glass .enable = rk_hdmi_enable, 919c2539483SSimon Glass }; 920c2539483SSimon Glass 921c2539483SSimon Glass static const struct udevice_id rk_hdmi_ids[] = { 922c2539483SSimon Glass { .compatible = "rockchip,rk3288-dw-hdmi" }, 923c2539483SSimon Glass { } 924c2539483SSimon Glass }; 925c2539483SSimon Glass 926c2539483SSimon Glass U_BOOT_DRIVER(hdmi_rockchip) = { 927c2539483SSimon Glass .name = "hdmi_rockchip", 928c2539483SSimon Glass .id = UCLASS_DISPLAY, 929c2539483SSimon Glass .of_match = rk_hdmi_ids, 930c2539483SSimon Glass .ops = &rk_hdmi_ops, 931c2539483SSimon Glass .ofdata_to_platdata = rk_hdmi_ofdata_to_platdata, 932c2539483SSimon Glass .probe = rk_hdmi_probe, 933c2539483SSimon Glass .priv_auto_alloc_size = sizeof(struct rk_hdmi_priv), 934c2539483SSimon Glass }; 935