Thanks for "Kbuild test robot" reminding, I forget to update "mode_valid" function define in imx-hdmi side, would send new version out,

--

drivers/gpu/drm/imx/dw_hdmi-imx.c:181:2: warning: initialization from 
incompatible pointer type

     .mode_valid = imx6q_hdmi_mode_valid,
     ^
   drivers/gpu/drm/imx/dw_hdmi-imx.c:181:2: warning: (near initialization for 
'imx6q_hdmi_drv_data.mode_valid')
   drivers/gpu/drm/imx/dw_hdmi-imx.c:189:2: warning: initialization from 
incompatible pointer type
     .mode_valid = imx6dl_hdmi_mode_valid,
     ^
   drivers/gpu/drm/imx/dw_hdmi-imx.c:189:2: warning: (near initialization for 
'imx6dl_hdmi_drv_data.mode_valid')

Sorry,
- Yakir


On 01/07/2016 12:37 PM, Yakir Yang wrote:
RK3229 integrate an DesignedWare HDMI2.0 controller and an INNO HDMI2.0 phy,
the max output resolution is 4K.

Signed-off-by: Yakir Yang <y...@rock-chips.com>
---
  drivers/gpu/drm/bridge/dw-hdmi.c            |  33 ++-
  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 380 +++++++++++++++++++++++++---
  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h | 137 ++++++++++
  include/drm/bridge/dw_hdmi.h                |   5 +-
  4 files changed, 516 insertions(+), 39 deletions(-)
  create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h

diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 6fbec99..60b1dcf 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -735,10 +735,12 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, 
unsigned char prep,
  {
        unsigned res_idx;
        u8 val, msec;
+       int ret;
        const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
        const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
        const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
        const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
+       int mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
if (prep)
                return -EINVAL;
@@ -758,27 +760,38 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, 
unsigned char prep,
                return -EINVAL;
        }
+ if (hdmi->plat_data->extphy_config) {
+               /* gen2 tx power off */
+               dw_hdmi_phy_gen2_txpwron(hdmi, 0);
+               dw_hdmi_phy_gen2_pddq(hdmi, 1);
+
+               ret = hdmi->plat_data->extphy_config(hdmi->plat_data, res_idx,
+                                                    mpixelclock);
+               /* gen2 tx power on */
+               dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+               dw_hdmi_phy_gen2_pddq(hdmi, 0);
+
+               return ret;
+       }
+
        /* PLL/MPLL Cfg - always match on final entry */
        for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
-               if (hdmi->hdmi_data.video_mode.mpixelclock <=
-                   mpll_config->mpixelclock)
+               if (mpixelclock <= mpll_config->mpixelclock)
                        break;
for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++)
-               if (hdmi->hdmi_data.video_mode.mpixelclock <=
-                   curr_ctrl->mpixelclock)
+               if (mpixelclock <= curr_ctrl->mpixelclock)
                        break;
for (; phy_config->mpixelclock != ~0UL; phy_config++)
-               if (hdmi->hdmi_data.video_mode.mpixelclock <=
-                   phy_config->mpixelclock)
+               if (mpixelclock <= phy_config->mpixelclock)
                        break;
if (mpll_config->mpixelclock == ~0UL ||
            curr_ctrl->mpixelclock == ~0UL ||
            phy_config->mpixelclock == ~0UL) {
                dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
-                       hdmi->hdmi_data.video_mode.mpixelclock);
+                       mpixelclock);
                return -EINVAL;
        }
@@ -1476,14 +1489,16 @@ dw_hdmi_connector_mode_valid(struct drm_connector *connector,
  {
        struct dw_hdmi *hdmi = container_of(connector,
                                           struct dw_hdmi, connector);
+       struct dw_hdmi_plat_data *plat_data = hdmi->plat_data;
        enum drm_mode_status mode_status = MODE_OK;
/* We don't support double-clocked modes */
        if (mode->flags & DRM_MODE_FLAG_DBLCLK)
                return MODE_BAD;
- if (hdmi->plat_data->mode_valid)
-               mode_status = hdmi->plat_data->mode_valid(connector, mode);
+       if (plat_data->mode_valid)
+               mode_status = plat_data->mode_valid(plat_data, mode);
+
return mode_status;
  }
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c 
b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index c65ce8c..424d548 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -7,6 +7,7 @@
   * (at your option) any later version.
   */
+#include <linux/clk.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/mfd/syscon.h>
@@ -21,18 +22,135 @@
  #include "rockchip_drm_drv.h"
  #include "rockchip_drm_vop.h"
-#define GRF_SOC_CON6 0x025c
-#define HDMI_SEL_VOP_LIT                (1 << 4)
+#include "dw_hdmi-rockchip.h"
struct rockchip_hdmi {
        struct device *dev;
        struct regmap *regmap;
        struct drm_encoder encoder;
+       struct dw_hdmi_plat_data plat_data;
+
+       void __iomem *extphy_regbase;
+       struct clk *extphy_pclk;
  };
#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) -static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
+static const struct extphy_config_tab rk3229_extphy_cfg[] = {
+       { .mpixelclock = 165000000,
+         .pre_emphasis = 0, .slopeboost = 0, .clk_level = 4,
+         .data0_level = 4, 4, 4,
+       },
+
+       { .mpixelclock = 225000000,
+         .pre_emphasis = 0, .slopeboost = 0, .clk_level = 6,
+         .data0_level = 6, 6, 6,
+       },
+
+       { .mpixelclock = 340000000,
+         .pre_emphasis = 1, .slopeboost = 0, .clk_level = 6,
+         .data0_level = 10, 10, 10,
+       },
+
+       { .mpixelclock = 594000000,
+         .pre_emphasis = 1, .slopeboost = 0, .clk_level = 7,
+         .data0_level = 10, 10, 10,
+       },
+
+       { .mpixelclock = ~0UL},
+};
+
+static const struct extphy_pll_config_tab rk3229_extphy_pll_cfg[] = {
+       {
+               .mpixelclock = 27000000, .param = {
+                       { .pll_nd = 1, .pll_nf = 45,
+                         .tmsd_divider_a = 3, 1, 1,
+                         .pclk_divider_a = 1, 3, 3, 4,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 1, .ppll_nf = 40, .ppll_no = 8,
+                       },
+                       { .pll_nd = 1, .pll_nf = 45,
+                         .tmsd_divider_a = 0, 3, 3,
+                         .pclk_divider_a = 1, 3, 3, 4,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 1, .ppll_nf = 40, .ppll_no = 8,
+                       },
+               },
+       }, {
+               .mpixelclock = 59400000, .param = {
+                       { .pll_nd = 2, .pll_nf = 99,
+                         .tmsd_divider_a = 3, 1, 1,
+                         .pclk_divider_a = 1, 3, 2, 2,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 1, .ppll_nf = 40, .ppll_no = 8,
+                       },
+                       { .pll_nd = 2, .pll_nf = 99,
+                         .tmsd_divider_a = 1, 1, 1,
+                         .pclk_divider_a = 1, 3, 2, 2,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 1, .ppll_nf = 40, .ppll_no = 8,
+                       },
+               },
+       }, {
+               .mpixelclock = 74250000, .param = {
+                       { .pll_nd = 2, .pll_nf = 99,
+                         .tmsd_divider_a = 1, 1, 1,
+                         .pclk_divider_a = 1, 2, 2, 2,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 1, .ppll_nf = 40, .ppll_no = 8,
+                       },
+                       { .pll_nd = 4, .pll_nf = 495,
+                         .tmsd_divider_a = 1, 2, 2,
+                         .pclk_divider_a = 1, 3, 3, 4,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 2, .ppll_nf = 40, .ppll_no = 4,
+                       },
+               },
+       }, {
+               .mpixelclock = 148500000, .param = {
+                       { .pll_nd = 2, .pll_nf = 99,
+                         .tmsd_divider_a = 1, 0, 0,
+                         .pclk_divider_a = 1, 2, 1, 1,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 2, .ppll_nf = 40, .ppll_no = 4,
+                       },
+                       { .pll_nd = 4, .pll_nf = 495,
+                         .tmsd_divider_a = 0, 2, 2,
+                         .pclk_divider_a = 1, 3, 2, 2,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 4, .ppll_nf = 40, .ppll_no = 2,
+                       },
+               },
+       }, {
+               .mpixelclock = 297000000, .param = {
+                       { .pll_nd = 2, .pll_nf = 99,
+                         .tmsd_divider_a = 0, 0, 0,
+                         .pclk_divider_a = 1, 0, 1, 1,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 4, .ppll_nf = 40, .ppll_no = 2,
+                       },
+                       { .pll_nd = 4, .pll_nf = 495,
+                         .tmsd_divider_a = 1, 2, 0,
+                         .pclk_divider_a = 1, 3, 1, 1,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 8, .ppll_nf = 40, .ppll_no = 1,
+                       },
+               },
+       }, {
+               .mpixelclock = 594000000, .param = {
+                       { .pll_nd = 1, .pll_nf = 99,
+                         .tmsd_divider_a = 0, 2, 0,
+                         .pclk_divider_a = 1, 0, 1, 1,
+                         .vco_div_5 = 0,
+                         .ppll_nd = 8, .ppll_nf = 40, .ppll_no = 1,
+                       },
+               }
+       }, {
+               .mpixelclock = ~0UL,
+       }
+};
+
+static const struct dw_hdmi_mpll_config rk3288_mpll_cfg[] = {
        {
                27000000, {
                        { 0x00b3, 0x0000},
@@ -112,7 +230,7 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] 
= {
        }
  };
-static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
+static const struct dw_hdmi_curr_ctrl rk3288_cur_ctr[] = {
        /*      pixelclk    bpp8    bpp10   bpp12 */
        {
                40000000,  { 0x0018, 0x0018, 0x0018 },
@@ -133,7 +251,7 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
        }
  };
-static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
+static const struct dw_hdmi_phy_config rk3288_phy_config[] = {
        /*pixelclk   symbol   term   vlev*/
        { 74250000,  0x8009, 0x0004, 0x0272},
        { 148500000, 0x802b, 0x0004, 0x028d},
@@ -141,9 +259,158 @@ static const struct dw_hdmi_phy_config 
rockchip_phy_config[] = {
        { ~0UL,      0x0000, 0x0000, 0x0000}
  };
+static int hdmi_ext_phy_write(struct rockchip_hdmi *hdmi, unsigned short data,
+                             unsigned char addr)
+{
+       writel_relaxed(data, hdmi->extphy_regbase + (addr) * 0x04);
+       return 0;
+}
+
+static unsigned int hdmi_phy_i2c_read(struct rockchip_hdmi *hdmi,
+                                     unsigned char addr)
+{
+       return readl_relaxed(hdmi->extphy_regbase + (addr) * 0x04);
+}
+
+static int rk3229_extphy_config(struct dw_hdmi_plat_data *plat_data,
+                                 int res, int pixelclock)
+{
+       struct rockchip_hdmi *hdmi = to_rockchip_hdmi(plat_data);
+       const struct extphy_pll_config_tab *mpll = rk3229_extphy_pll_cfg;
+       const struct extphy_config_tab *ctrl = rk3229_extphy_cfg;
+       unsigned long timeout;
+       int i, stat;
+
+       /* Find out the extphy MPLL configure parameters */
+       for (i = 0; mpll[i].mpixelclock != ~0UL; i++)
+               if (pixelclock == mpll[i].mpixelclock)
+                       break;
+       if (mpll[i].mpixelclock == ~0UL) {
+               dev_err(hdmi->dev, "Extphy couldn't support %dHz\n", 
pixelclock);
+               return -EINVAL;
+       }
+
+       regmap_write(hdmi->regmap, RK3229_GRF_SOC_CON2,
+                    RK3229_PLL_POWER_DOWN | RK3229_PLL_PDATA_DEN);
+
+       /*
+        * Configure external phy PLL registers.
+        */
+       stat = ((mpll[i].param[res].pll_nf >> 1) & EXT_PHY_PLL_FB_BIT8_MASK) |
+              ((mpll[i].param[res].vco_div_5 & 1) << 5) |
+              (mpll[i].param[res].pll_nd & EXT_PHY_PLL_PRE_DIVIDER_MASK);
+       hdmi_ext_phy_write(hdmi, stat, EXT_PHY_PLL_PRE_DIVIDER);
+
+       hdmi_ext_phy_write(hdmi, mpll[i].param[res].pll_nf, 
EXT_PHY_PLL_FB_DIVIDER);
+
+       stat = (mpll[i].param[res].pclk_divider_a & EXT_PHY_PCLK_DIVIDERA_MASK) 
|
+              ((mpll[i].param[res].pclk_divider_b & 3) << 5);
+       hdmi_ext_phy_write(hdmi, stat, EXT_PHY_PCLK_DIVIDER1);
+
+       stat = (mpll[i].param[res].pclk_divider_d & EXT_PHY_PCLK_DIVIDERD_MASK) 
|
+              ((mpll[i].param[res].pclk_divider_c & 3) << 5);
+       hdmi_ext_phy_write(hdmi, stat, EXT_PHY_PCLK_DIVIDER2);
+
+       stat = ((mpll[i].param[res].tmsd_divider_c & 3) << 4) |
+              ((mpll[i].param[res].tmsd_divider_a & 3) << 2) |
+              (mpll[i].param[res].tmsd_divider_b & 3);
+       hdmi_ext_phy_write(hdmi, stat, EXT_PHY_TMDSCLK_DIVIDER);
+
+       hdmi_ext_phy_write(hdmi, mpll[i].param[res].ppll_nf, 
EXT_PHY_PPLL_FB_DIVIDER);
+
+       if (mpll[i].param[res].ppll_no == 1) {
+               hdmi_ext_phy_write(hdmi, 0, EXT_PHY_PPLL_POST_DIVIDER);
+
+               stat = 0x20 | mpll[i].param[res].ppll_nd;
+               hdmi_ext_phy_write(hdmi, stat, EXT_PHY_PPLL_PRE_DIVIDER);
+       } else {
+               stat = ((mpll[i].param[res].ppll_no / 2) - 1) << 4;
+               hdmi_ext_phy_write(hdmi, stat, EXT_PHY_PPLL_POST_DIVIDER);
+
+               stat = 0xe0 | mpll[i].param[res].ppll_nd;
+               hdmi_ext_phy_write(hdmi, stat, EXT_PHY_PPLL_PRE_DIVIDER);
+       }
+
+
+       /* Find out the extphy driver configure parameters */
+       for (i = 0; ctrl[i].mpixelclock != ~0UL; i++)
+               if (pixelclock <= ctrl[i].mpixelclock)
+                       break;
+       if (ctrl[i].mpixelclock == ~0UL) {
+               dev_err(hdmi->dev, "Extphy couldn't support %dHz\n", 
pixelclock);
+               return -EINVAL;
+       }
+
+       /*
+        * Configure the extphy driver registers.
+        */
+       if (ctrl[i].slopeboost) {
+               hdmi_ext_phy_write(hdmi, 0xff, EXT_PHY_SIGNAL_CTRL);
+
+               stat = (ctrl[i].slopeboost - 1) & 3;
+               stat = (stat << 6) | (stat << 4) | (stat << 2) | stat;
+               hdmi_ext_phy_write(hdmi, stat, EXT_PHY_SLOPEBOOST);
+       } else
+               hdmi_ext_phy_write(hdmi, 0x0f, EXT_PHY_SIGNAL_CTRL);
+
+       stat = ctrl[i].pre_emphasis & 3;
+       stat = (stat << 4) | (stat << 2) | stat;
+       hdmi_ext_phy_write(hdmi, stat, EXT_PHY_PREEMPHASIS);
+
+       stat = ((ctrl[i].clk_level & 0xf) << 4) | (ctrl[i].data2_level & 0xf);
+       hdmi_ext_phy_write(hdmi, stat, EXT_PHY_LEVEL1);
+
+       stat = ((ctrl[i].data1_level & 0xf) << 4) | (ctrl[i].data0_level & 0xf);
+       hdmi_ext_phy_write(hdmi, stat, EXT_PHY_LEVEL2);
+
+       hdmi_ext_phy_write(hdmi, 0x22, 0xf3);
+
+       stat = clk_get_rate(hdmi->extphy_pclk) / 100000;
+       hdmi_ext_phy_write(hdmi, ((stat >> 8) & 0xff) | 0x80, EXT_PHY_TERM_CAL);
+       hdmi_ext_phy_write(hdmi,  stat & 0xff, EXT_PHY_TERM_CAL_DIV_L);
+
+       if (pixelclock > 340000000)
+               stat = EXT_PHY_AUTO_R100_OHMS;
+       else if (pixelclock > 200000000)
+               stat = EXT_PHY_AUTO_R50_OHMS;
+       else
+               stat = EXT_PHY_AUTO_ROPEN_CIRCUIT;
+       hdmi_ext_phy_write(hdmi, stat | 0x20, EXT_PHY_TERM_RESIS_AUTO);
+       hdmi_ext_phy_write(hdmi, (stat >> 8) & 0xff, EXT_PHY_TERM_CAL);
+
+       stat = (pixelclock > 200000000) ? 0 : 0x11;
+       hdmi_ext_phy_write(hdmi, stat, EXT_PHY_PLL_BW);
+       hdmi_ext_phy_write(hdmi, 0x27, EXT_PHY_PPLL_BW);
+
+       regmap_write(hdmi->regmap, RK3229_GRF_SOC_CON2, RK3229_PLL_POWER_UP);
+
+       /* Detect whether PLL is lock or not */
+       timeout = jiffies + msecs_to_jiffies(100);
+       while (!time_after(jiffies, timeout)) {
+               usleep_range(1000, 2000);
+               stat = hdmi_phy_i2c_read(hdmi, EXT_PHY_PPLL_POST_DIVIDER);
+               if (stat & EXT_PHY_PPLL_LOCK_STATUS_MASK)
+                       break;
+       }
+
+       regmap_write(hdmi->regmap, RK3229_GRF_SOC_CON2, RK3229_PLL_PDATA_EN);
+
+       if ((stat & EXT_PHY_PPLL_LOCK_STATUS_MASK) == 0) {
+               dev_err(hdmi->dev, "EXT PHY PLL not locked\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
  static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
  {
        struct device_node *np = hdmi->dev->of_node;
+       struct platform_device *pdev;
+       struct resource *iores;
+       int ret;
+
+       pdev = container_of(hdmi->dev, struct platform_device, dev);
hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
        if (IS_ERR(hdmi->regmap)) {
@@ -151,24 +418,62 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi 
*hdmi)
                return PTR_ERR(hdmi->regmap);
        }
+ if (hdmi->plat_data.dev_type == RK3229_HDMI) {
+               iores = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               if (!iores)
+                       return -ENXIO;
+
+               hdmi->extphy_regbase = devm_ioremap_resource(hdmi->dev, iores);
+               if (IS_ERR(hdmi->extphy_regbase)) {
+                       dev_err(hdmi->dev, "failed to map extphy regbase\n");
+                       return PTR_ERR(hdmi->extphy_regbase);
+               }
+
+               hdmi->extphy_pclk = devm_clk_get(hdmi->dev, "extphy");
+               if (IS_ERR(hdmi->extphy_pclk)) {
+                       dev_err(hdmi->dev, "failed to get extphy clock\n");
+                       return PTR_ERR(hdmi->extphy_pclk);
+               }
+
+               ret = clk_prepare_enable(hdmi->extphy_pclk);
+               if (ret) {
+                       dev_err(hdmi->dev, "failed to enable extphy clk: %d\n",
+                               ret);
+                       return ret;
+               }
+
+               regmap_write(hdmi->regmap, RK3229_GRF_SOC_CON6,
+                            RK3229_IO_3V_DOMAIN);
+
+               regmap_write(hdmi->regmap, RK3229_GRF_SOC_CON2,
+                            RK3229_DDC_MASK_EN);
+       }
+
        return 0;
  }
static enum drm_mode_status
-dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
+dw_hdmi_rockchip_mode_valid(const struct dw_hdmi_plat_data *plat_data,
                            struct drm_display_mode *mode)
  {
-       const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
        int pclk = mode->clock * 1000;
        bool valid = false;
        int i;
- for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
-               if (pclk == mpll_cfg[i].mpixelclock) {
-                       valid = true;
-                       break;
+       if (plat_data->dev_type == RK3288_HDMI)
+               for (i = 0; rk3288_mpll_cfg[i].mpixelclock != (~0UL); i++)
+                       if (pclk == rk3288_mpll_cfg[i].mpixelclock) {
+                               valid = true;
+                               break;
+                       }
+
+       if (plat_data->dev_type == RK3229_HDMI)
+               for (i = 0; rk3229_extphy_pll_cfg[i].mpixelclock != ~0UL; i++) {
+                       if (pclk == rk3229_extphy_pll_cfg[i].mpixelclock) {
+                               valid = true;
+                               break;
+                       }
                }
-       }
return (valid) ? MODE_OK : MODE_BAD;
  }
@@ -198,21 +503,29 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct 
drm_encoder *encoder,
  static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
  {
        struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
+       int out_mode = ROCKCHIP_OUT_MODE_AAAA;
        u32 val;
        int mux;
+ if (hdmi->plat_data.dev_type == RK3229_HDMI)
+               out_mode = ROCKCHIP_OUT_MODE_P888;
+
        rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
-                                     ROCKCHIP_OUT_MODE_AAAA);
+                                     out_mode);
- mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
-       if (mux)
-               val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16);
-       else
-               val = HDMI_SEL_VOP_LIT << 16;
+       if (hdmi->plat_data.dev_type == RK3288_HDMI) {
+               mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node,
+                                                     encoder);
+               if (mux)
+                       val = RK3288_HDMI_SEL_VOP_LIT |
+                             (RK3288_HDMI_SEL_VOP_LIT << 16);
+               else
+                       val = RK3288_HDMI_SEL_VOP_LIT << 16;
- regmap_write(hdmi->regmap, GRF_SOC_CON6, val);
-       dev_dbg(hdmi->dev, "vop %s output to hdmi\n",
-               (mux) ? "LIT" : "BIG");
+               regmap_write(hdmi->regmap, RK3288_GRF_SOC_CON6, val);
+
+               dev_dbg(hdmi->dev, "vop %s output to hdmi\n", (mux) ? "LIT" : 
"BIG");
+       }
  }
static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
@@ -222,17 +535,26 @@ static const struct drm_encoder_helper_funcs 
dw_hdmi_rockchip_encoder_helper_fun
        .disable    = dw_hdmi_rockchip_encoder_disable,
  };
-static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {
+static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
        .mode_valid = dw_hdmi_rockchip_mode_valid,
-       .mpll_cfg   = rockchip_mpll_cfg,
-       .cur_ctr    = rockchip_cur_ctr,
-       .phy_config = rockchip_phy_config,
+       .mpll_cfg   = rk3288_mpll_cfg,
+       .cur_ctr    = rk3288_cur_ctr,
+       .phy_config = rk3288_phy_config,
        .dev_type   = RK3288_HDMI,
  };
+static const struct dw_hdmi_plat_data rk3229_hdmi_drv_data = {
+       .mode_valid = dw_hdmi_rockchip_mode_valid,
+       .extphy_config = rk3229_extphy_config,
+       .dev_type   = RK3229_HDMI,
+};
+
  static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
        { .compatible = "rockchip,rk3288-dw-hdmi",
-         .data = &rockchip_hdmi_drv_data
+         .data = &rk3288_hdmi_drv_data
+       },
+       { .compatible = "rockchip,rk3229-dw-hdmi",
+         .data = &rk3229_hdmi_drv_data
        },
        {},
  };
@@ -242,7 +564,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct 
device *master,
                                 void *data)
  {
        struct platform_device *pdev = to_platform_device(dev);
-       const struct dw_hdmi_plat_data *plat_data;
        const struct of_device_id *match;
        struct drm_device *drm = data;
        struct drm_encoder *encoder;
@@ -259,7 +580,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct 
device *master,
                return -ENOMEM;
match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
-       plat_data = match->data;
+       hdmi->plat_data = *(struct dw_hdmi_plat_data *)(match->data);
        hdmi->dev = &pdev->dev;
        encoder = &hdmi->encoder;
@@ -293,7 +614,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
        drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
                         DRM_MODE_ENCODER_TMDS, NULL);
- return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+       return dw_hdmi_bind(dev, master, data, encoder, iores, irq,
+                           &hdmi->plat_data);
  }
static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h 
b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h
new file mode 100644
index 0000000..aca2543
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h
@@ -0,0 +1,137 @@
+#ifndef __DW_HDMI_ROCKCHIP__
+#define __DW_HDMI_ROCKCHIP__
+
+struct extphy_config_tab {
+       u32 mpixelclock;
+       int pre_emphasis;
+       int slopeboost;
+       int clk_level;
+       int data0_level;
+       int data1_level;
+       int data2_level;
+};
+
+struct extphy_pll_config_tab {
+       unsigned long mpixelclock;
+       struct {
+               u8      pll_nd;
+               u16     pll_nf;
+               u8      tmsd_divider_a;
+               u8      tmsd_divider_b;
+               u8      tmsd_divider_c;
+               u8      pclk_divider_a;
+               u8      pclk_divider_b;
+               u8      pclk_divider_c;
+               u8      pclk_divider_d;
+               u8      vco_div_5;
+               u8      ppll_nd;
+               u8      ppll_nf;
+               u8      ppll_no;
+       } param[DW_HDMI_RES_MAX];
+};
+
+#define RK3288_GRF_SOC_CON6                    0x025c
+#define RK3288_HDMI_SEL_VOP_LIT                        (1 << 4)
+
+#define RK3229_GRF_SOC_CON6                    0x0418
+#define RK3229_IO_3V_DOMAIN                    ((7 << 4) | (7 << (4 + 16)))
+
+#define RK3229_GRF_SOC_CON2                    0x0408
+#define RK3229_DDC_MASK_EN                     ((3 << 13) | (3 << (13 + 16)))
+
+#define RK3229_PLL_POWER_DOWN                  (BIT(12) | BIT(12 + 16))
+#define RK3229_PLL_POWER_UP                    BIT(12 + 16)
+#define RK3229_PLL_PDATA_DEN                   BIT(11 + 16)
+#define RK3229_PLL_PDATA_EN                    (BIT(11) | BIT(11 + 16))
+
+/* PHY Defined for RK322X */
+#define EXT_PHY_CONTROL                                0
+#define EXT_PHY_ANALOG_RESET_MASK              0x80
+#define EXT_PHY_DIGITAL_RESET_MASK             0x40
+#define EXT_PHY_PCLK_INVERT_MASK               0x08
+#define EXT_PHY_PREPCLK_INVERT_MASK            0x04
+#define EXT_PHY_TMDSCLK_INVERT_MASK            0x02
+#define EXT_PHY_SRC_SELECT_MASK                        0x01
+
+#define EXT_PHY_TERM_CAL                       0x03
+#define EXT_PHY_TERM_CAL_EN_MASK               0x80
+#define EXT_PHY_TERM_CAL_DIV_H_MASK            0x7f
+
+#define EXT_PHY_TERM_CAL_DIV_L                 0x04
+
+#define EXT_PHY_PLL_PRE_DIVIDER                        0xe2
+#define EXT_PHY_PLL_FB_BIT8_MASK               0x80
+#define EXT_PHY_PLL_PCLK_DIV5_EN_MASK          0x20
+#define EXT_PHY_PLL_PRE_DIVIDER_MASK           0x1f
+
+#define EXT_PHY_PLL_FB_DIVIDER                 0xe3
+
+#define EXT_PHY_PCLK_DIVIDER1                  0xe4
+#define EXT_PHY_PCLK_DIVIDERB_MASK             0x60
+#define EXT_PHY_PCLK_DIVIDERA_MASK             0x1f
+
+#define EXT_PHY_PCLK_DIVIDER2                  0xe5
+#define EXT_PHY_PCLK_DIVIDERC_MASK             0x60
+#define EXT_PHY_PCLK_DIVIDERD_MASK             0x1f
+
+#define EXT_PHY_TMDSCLK_DIVIDER                        0xe6
+#define EXT_PHY_TMDSCLK_DIVIDERC_MASK          0x30
+#define EXT_PHY_TMDSCLK_DIVIDERA_MASK          0x0c
+#define EXT_PHY_TMDSCLK_DIVIDERB_MASK          0x03
+
+#define EXT_PHY_PLL_BW                         0xe7
+
+#define EXT_PHY_PPLL_PRE_DIVIDER               0xe9
+#define EXT_PHY_PPLL_ENABLE_MASK               0xc0
+#define EXT_PHY_PPLL_PRE_DIVIDER_MASK          0x1f
+
+#define EXT_PHY_PPLL_FB_DIVIDER                        0xea
+
+#define EXT_PHY_PPLL_POST_DIVIDER              0xeb
+#define EXT_PHY_PPLL_FB_DIVIDER_BIT8_MASK      0x80
+#define EXT_PHY_PPLL_POST_DIVIDER_MASK         0x30
+#define EXT_PHY_PPLL_LOCK_STATUS_MASK          0x01
+
+#define EXT_PHY_PPLL_BW                                0xec
+
+#define EXT_PHY_SIGNAL_CTRL                    0xee
+#define EXT_PHY_TRANSITION_CLK_EN_MASK         0x80
+#define EXT_PHY_TRANSITION_D0_EN_MASK          0x40
+#define EXT_PHY_TRANSITION_D1_EN_MASK          0x20
+#define EXT_PHY_TRANSITION_D2_EN_MASK          0x10
+#define EXT_PHY_LEVEL_CLK_EN_MASK              0x08
+#define EXT_PHY_LEVEL_D0_EN_MASK               0x04
+#define EXT_PHY_LEVEL_D1_EN_MASK               0x02
+#define EXT_PHY_LEVEL_D2_EN_MASK               0x01
+
+#define EXT_PHY_SLOPEBOOST                     0xef
+#define EXT_PHY_SLOPEBOOST_CLK_MASK            0x03
+#define EXT_PHY_SLOPEBOOST_D0_MASK             0x0c
+#define EXT_PHY_SLOPEBOOST_D1_MASK             0x30
+#define EXT_PHY_SLOPEBOOST_D2_MASK             0xc0
+
+#define EXT_PHY_PREEMPHASIS                    0xf0
+#define EXT_PHY_PREEMPHASIS_D0_MASK            0x03
+#define EXT_PHY_PREEMPHASIS_D1_MASK            0x0c
+#define EXT_PHY_PREEMPHASIS_D2_MASK            0x30
+
+#define EXT_PHY_LEVEL1                         0xf1
+#define EXT_PHY_LEVEL_CLK_MASK                 0xf0
+#define EXT_PHY_LEVEL_D2_MASK                  0x0f
+
+#define EXT_PHY_LEVEL2                         0xf2
+#define EXT_PHY_LEVEL_D1_MASK                  0xf0
+#define EXT_PHY_LEVEL_D0_MASK                  0x0f
+
+#define EXT_PHY_TERM_RESIS_AUTO                        0xf4
+#define EXT_PHY_AUTO_R50_OHMS                  0
+#define EXT_PHY_AUTO_R75_OHMS                  (1 << 2)
+#define EXT_PHY_AUTO_R100_OHMS                 (2 << 2)
+#define EXT_PHY_AUTO_ROPEN_CIRCUIT             (3 << 2)
+
+#define EXT_PHY_TERM_RESIS_MANUAL_CLK          0xfb
+#define EXT_PHY_TERM_RESIS_MANUAL_D2           0xfc
+#define EXT_PHY_TERM_RESIS_MANUAL_D1           0xfd
+#define EXT_PHY_TERM_RESIS_MANUAL_D0           0xfe
+
+#endif /* __DW_HDMI_ROCKCHIP__ */
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index bae79f3..44084e8 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -24,6 +24,7 @@ enum {
  enum dw_hdmi_devtype {
        IMX6Q_HDMI,
        IMX6DL_HDMI,
+       RK3229_HDMI,
        RK3288_HDMI,
  };
@@ -52,8 +53,10 @@ struct dw_hdmi_plat_data {
        const struct dw_hdmi_mpll_config *mpll_cfg;
        const struct dw_hdmi_curr_ctrl *cur_ctr;
        const struct dw_hdmi_phy_config *phy_config;
-       enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+       enum drm_mode_status (*mode_valid)(const struct dw_hdmi_plat_data 
*plat_data,
                                           struct drm_display_mode *mode);
+       int (*extphy_config)(struct dw_hdmi_plat_data *plat_data,
+                            int bpp, int pixelclock);
  };
void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to