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> 12cc232a9dSJernej Skrabec #include <dw_hdmi.h> 13c2539483SSimon Glass #include <edid.h> 14c2539483SSimon Glass #include <regmap.h> 15c2539483SSimon Glass #include <syscon.h> 16c2539483SSimon Glass #include <asm/gpio.h> 17c2539483SSimon Glass #include <asm/io.h> 18c2539483SSimon Glass #include <asm/arch/clock.h> 19c2539483SSimon Glass #include <asm/arch/grf_rk3288.h> 20c2539483SSimon Glass #include <power/regulator.h> 21c2539483SSimon Glass 22c2539483SSimon Glass struct rk_hdmi_priv { 23cc232a9dSJernej Skrabec struct dw_hdmi hdmi; 24c2539483SSimon Glass struct rk3288_grf *grf; 25c2539483SSimon Glass }; 26c2539483SSimon Glass 27c2539483SSimon Glass static const struct hdmi_phy_config rockchip_phy_config[] = { 28c2539483SSimon Glass { 290fc41e55SNickey Yang Nickey Yang .mpixelclock = 74250000, 30c2539483SSimon Glass .sym_ctr = 0x8009, .term = 0x0004, .vlev_ctr = 0x0272, 31c2539483SSimon Glass }, { 320fc41e55SNickey Yang Nickey Yang .mpixelclock = 148500000, 33c2539483SSimon Glass .sym_ctr = 0x802b, .term = 0x0004, .vlev_ctr = 0x028d, 34c2539483SSimon Glass }, { 350fc41e55SNickey Yang Nickey Yang .mpixelclock = 297000000, 36c2539483SSimon Glass .sym_ctr = 0x8039, .term = 0x0005, .vlev_ctr = 0x028d, 37c2539483SSimon Glass }, { 38c2539483SSimon Glass .mpixelclock = ~0ul, 39c2539483SSimon Glass .sym_ctr = 0x0000, .term = 0x0000, .vlev_ctr = 0x0000, 40c2539483SSimon Glass } 41c2539483SSimon Glass }; 42c2539483SSimon Glass 43c2539483SSimon Glass static const struct hdmi_mpll_config rockchip_mpll_cfg[] = { 44c2539483SSimon Glass { 450fc41e55SNickey Yang Nickey Yang .mpixelclock = 40000000, 46c2539483SSimon Glass .cpce = 0x00b3, .gmp = 0x0000, .curr = 0x0018, 47c2539483SSimon Glass }, { 480fc41e55SNickey Yang Nickey Yang .mpixelclock = 65000000, 49c2539483SSimon Glass .cpce = 0x0072, .gmp = 0x0001, .curr = 0x0028, 50c2539483SSimon Glass }, { 510fc41e55SNickey Yang Nickey Yang .mpixelclock = 66000000, 52c2539483SSimon Glass .cpce = 0x013e, .gmp = 0x0003, .curr = 0x0038, 53c2539483SSimon Glass }, { 5494412745SNickey Yang Nickey Yang .mpixelclock = 83500000, 55c2539483SSimon Glass .cpce = 0x0072, .gmp = 0x0001, .curr = 0x0028, 56c2539483SSimon Glass }, { 570fc41e55SNickey Yang Nickey Yang .mpixelclock = 146250000, 58c2539483SSimon Glass .cpce = 0x0051, .gmp = 0x0002, .curr = 0x0038, 59c2539483SSimon Glass }, { 600fc41e55SNickey Yang Nickey Yang .mpixelclock = 148500000, 61c2539483SSimon Glass .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, 62c2539483SSimon Glass }, { 63c2539483SSimon Glass .mpixelclock = ~0ul, 64c2539483SSimon Glass .cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000, 65c2539483SSimon Glass } 66c2539483SSimon Glass }; 67c2539483SSimon Glass 68c2539483SSimon Glass static int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) 69c2539483SSimon Glass { 70c2539483SSimon Glass struct rk_hdmi_priv *priv = dev_get_priv(dev); 71c2539483SSimon Glass 72cc232a9dSJernej Skrabec return dw_hdmi_read_edid(&priv->hdmi, buf, buf_size); 73c2539483SSimon Glass } 74c2539483SSimon Glass 75c2539483SSimon Glass static int rk_hdmi_enable(struct udevice *dev, int panel_bpp, 76c2539483SSimon Glass const struct display_timing *edid) 77c2539483SSimon Glass { 78c2539483SSimon Glass struct rk_hdmi_priv *priv = dev_get_priv(dev); 79c2539483SSimon Glass 80cc232a9dSJernej Skrabec return dw_hdmi_enable(&priv->hdmi, edid); 81c2539483SSimon Glass } 82c2539483SSimon Glass 83c2539483SSimon Glass static int rk_hdmi_ofdata_to_platdata(struct udevice *dev) 84c2539483SSimon Glass { 85c2539483SSimon Glass struct rk_hdmi_priv *priv = dev_get_priv(dev); 86cc232a9dSJernej Skrabec struct dw_hdmi *hdmi = &priv->hdmi; 87c2539483SSimon Glass 88*a821c4afSSimon Glass hdmi->ioaddr = (ulong)devfdt_get_addr(dev); 89cc232a9dSJernej Skrabec hdmi->mpll_cfg = rockchip_mpll_cfg; 90cc232a9dSJernej Skrabec hdmi->phy_cfg = rockchip_phy_config; 91cc232a9dSJernej Skrabec hdmi->i2c_clk_high = 0x7a; 92cc232a9dSJernej Skrabec hdmi->i2c_clk_low = 0x8d; 93cc232a9dSJernej Skrabec 94cc232a9dSJernej Skrabec /* 95cc232a9dSJernej Skrabec * TODO(sjg@chromium.org): The above values don't work - these ones 96cc232a9dSJernej Skrabec * work better, but generate lots of errors in the data. 97cc232a9dSJernej Skrabec */ 98cc232a9dSJernej Skrabec hdmi->i2c_clk_high = 0x0d; 99cc232a9dSJernej Skrabec hdmi->i2c_clk_low = 0x0d; 100cc232a9dSJernej Skrabec hdmi->reg_io_width = 4; 101cc232a9dSJernej Skrabec hdmi->phy_set = dw_hdmi_phy_cfg; 102cc232a9dSJernej Skrabec 103c2539483SSimon Glass priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); 104c2539483SSimon Glass 105c2539483SSimon Glass return 0; 106c2539483SSimon Glass } 107c2539483SSimon Glass 108c2539483SSimon Glass static int rk_hdmi_probe(struct udevice *dev) 109c2539483SSimon Glass { 110c2539483SSimon Glass struct display_plat *uc_plat = dev_get_uclass_platdata(dev); 111c2539483SSimon Glass struct rk_hdmi_priv *priv = dev_get_priv(dev); 112cc232a9dSJernej Skrabec struct dw_hdmi *hdmi = &priv->hdmi; 113135aa950SStephen Warren struct udevice *reg; 114135aa950SStephen Warren struct clk clk; 115c2539483SSimon Glass int ret; 116c2539483SSimon Glass int vop_id = uc_plat->source_id; 117c2539483SSimon Glass 118c2539483SSimon Glass ret = clk_get_by_index(dev, 0, &clk); 119c2539483SSimon Glass if (ret >= 0) { 120135aa950SStephen Warren ret = clk_set_rate(&clk, 0); 121135aa950SStephen Warren clk_free(&clk); 122c2539483SSimon Glass } 123c2539483SSimon Glass if (ret) { 1240fc41e55SNickey Yang Nickey Yang debug("%s: Failed to set hdmi clock: ret=%d\n", __func__, ret); 125c2539483SSimon Glass return ret; 126c2539483SSimon Glass } 127c2539483SSimon Glass 128c2539483SSimon Glass /* 129c2539483SSimon Glass * Configure the maximum clock to permit whatever resolution the 130c2539483SSimon Glass * monitor wants 131c2539483SSimon Glass */ 132c2539483SSimon Glass ret = clk_get_by_index(uc_plat->src_dev, 0, &clk); 133c2539483SSimon Glass if (ret >= 0) { 134135aa950SStephen Warren ret = clk_set_rate(&clk, 384000000); 135135aa950SStephen Warren clk_free(&clk); 136c2539483SSimon Glass } 137c2539483SSimon Glass if (ret < 0) { 138c2539483SSimon Glass debug("%s: Failed to set clock in source device '%s': ret=%d\n", 139c2539483SSimon Glass __func__, uc_plat->src_dev->name, ret); 140c2539483SSimon Glass return ret; 141c2539483SSimon Glass } 142c2539483SSimon Glass 143c2539483SSimon Glass ret = regulator_get_by_platname("vcc50_hdmi", ®); 144c2539483SSimon Glass if (!ret) 145c2539483SSimon Glass ret = regulator_set_enable(reg, true); 146c2539483SSimon Glass if (ret) 147c2539483SSimon Glass debug("%s: Cannot set regulator vcc50_hdmi\n", __func__); 148c2539483SSimon Glass 149c2539483SSimon Glass /* hdmi source select hdmi controller */ 150c2539483SSimon Glass rk_setreg(&priv->grf->soc_con6, 1 << 15); 151c2539483SSimon Glass 152c2539483SSimon Glass /* hdmi data from vop id */ 153e4ab3d71SSimon Glass rk_clrsetreg(&priv->grf->soc_con6, 1 << 4, 154e4ab3d71SSimon Glass (vop_id == 1) ? (1 << 4) : 0); 155c2539483SSimon Glass 156cc232a9dSJernej Skrabec ret = dw_hdmi_phy_wait_for_hpd(hdmi); 157c2539483SSimon Glass if (ret < 0) { 158c2539483SSimon Glass debug("hdmi can not get hpd signal\n"); 159c2539483SSimon Glass return -1; 160c2539483SSimon Glass } 161c2539483SSimon Glass 162cc232a9dSJernej Skrabec dw_hdmi_init(hdmi); 163cc232a9dSJernej Skrabec dw_hdmi_phy_init(hdmi); 164c2539483SSimon Glass 165c2539483SSimon Glass return 0; 166c2539483SSimon Glass } 167c2539483SSimon Glass 168c2539483SSimon Glass static const struct dm_display_ops rk_hdmi_ops = { 169c2539483SSimon Glass .read_edid = rk_hdmi_read_edid, 170c2539483SSimon Glass .enable = rk_hdmi_enable, 171c2539483SSimon Glass }; 172c2539483SSimon Glass 173c2539483SSimon Glass static const struct udevice_id rk_hdmi_ids[] = { 174c2539483SSimon Glass { .compatible = "rockchip,rk3288-dw-hdmi" }, 175c2539483SSimon Glass { } 176c2539483SSimon Glass }; 177c2539483SSimon Glass 178c2539483SSimon Glass U_BOOT_DRIVER(hdmi_rockchip) = { 179c2539483SSimon Glass .name = "hdmi_rockchip", 180c2539483SSimon Glass .id = UCLASS_DISPLAY, 181c2539483SSimon Glass .of_match = rk_hdmi_ids, 182c2539483SSimon Glass .ops = &rk_hdmi_ops, 183c2539483SSimon Glass .ofdata_to_platdata = rk_hdmi_ofdata_to_platdata, 184c2539483SSimon Glass .probe = rk_hdmi_probe, 185c2539483SSimon Glass .priv_auto_alloc_size = sizeof(struct rk_hdmi_priv), 186c2539483SSimon Glass }; 187