Hi Philipp,

Thanks for your fast respond :)

On 01/07/2016 06:04 PM, Philipp Zabel wrote:
> Am Donnerstag, den 07.01.2016, 17:02 +0800 schrieb Yakir Yang:
>> RK3229 integrate an DesignedWare HDMI2.0 controller and an INNO HDMI2.0 phy,
>> the max output resolution is 4K.
>>
>> Signed-off-by: Yakir Yang <ykk at rock-chips.com>
> It sounds like the INNO HDMI2.0 phy is not necessarily specific to
> RK3229 but might also appear in other SoCs? If so, I think this should
> be implemented in a separate phy driver and be used by dw_hdmi-rockchip.

Do you mean I should create a new phy driver that place in "driver/phy" 
directly ?

I have think about this idea, and it would make things much clean. But 
INNO PHY
driver need the target pixel clock in drm_display_mode, I didn't find a 
good way
to pass this variable to separate phy driver. Do you have some idea ?

Thanks,
- Yakir

> regards
> Philipp
>
>> ---
>> Changes in v2:
>> - Split some dw-hdmi driver changes into separate patches [01/04] & [02/04]
>>
>>   drivers/gpu/drm/bridge/dw-hdmi.c            |  27 +-
>>   drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 367 
>> ++++++++++++++++++++++++++--
>>   drivers/gpu/drm/rockchip/dw_hdmi-rockchip.h | 137 +++++++++++
>>   include/drm/bridge/dw_hdmi.h                |   3 +
>>   4 files changed, 507 insertions(+), 27 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 5ad72ec..5e03d83 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;
>>      }
>>   
>> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c 
>> b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
>> index 8164823..24fffaa 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,134 @@
>>   #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 extphy_config_tab rockchip_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 rockchip_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 rockchip_mpll_cfg[] = {
>>      {
>>              27000000, {
>> @@ -142,9 +259,164 @@ static const struct dw_hdmi_phy_config 
>> rockchip_phy_config[] = {
>>      { ~0UL,      0x0000, 0x0000, 0x0000}
>>   };
>>   
>> +static inline void hdmi_extphy_write(struct rockchip_hdmi *hdmi,
>> +                                 unsigned short data, unsigned char addr)
>> +{
>> +    writel_relaxed(data, hdmi->extphy_regbase + (addr) * 0x04);
>> +}
>> +
>> +static inline unsigned int hdmi_extphy_read(struct rockchip_hdmi *hdmi,
>> +                                        unsigned char addr)
>> +{
>> +    return readl_relaxed(hdmi->extphy_regbase + (addr) * 0x04);
>> +}
>> +
>> +static int rockchip_extphy_config(const 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 = rockchip_extphy_pll_cfg;
>> +    const struct extphy_config_tab *ctrl = rockchip_extphy_cfg;
>> +    const struct extphy_pll_config_param *param;
>> +    unsigned long timeout;
>> +    int i, stat;
>> +
>> +    if (res >= DW_HDMI_RES_MAX) {
>> +            dev_err(hdmi->dev, "Extphy can't support res %d\n", res);
>> +            return -EINVAL;
>> +    }
>> +
>> +    /* 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 can't support %dHz\n", pixelclock);
>> +            return -EINVAL;
>> +    }
>> +    param = &mpll[i].param[res];
>> +
>> +    regmap_write(hdmi->regmap, RK3229_GRF_SOC_CON2,
>> +                 RK3229_PLL_POWER_DOWN | RK3229_PLL_PDATA_DEN);
>> +
>> +    /*
>> +     * Configure external HDMI PHY PLL registers.
>> +     */
>> +    stat = ((param->pll_nf >> 1) & EXT_PHY_PLL_FB_BIT8_MASK) |
>> +           ((param->vco_div_5 & 1) << 5) |
>> +           (param->pll_nd & EXT_PHY_PLL_PRE_DIVIDER_MASK);
>> +    hdmi_extphy_write(hdmi, stat, EXT_PHY_PLL_PRE_DIVIDER);
>> +
>> +    hdmi_extphy_write(hdmi, param->pll_nf, EXT_PHY_PLL_FB_DIVIDER);
>> +
>> +    stat = (param->pclk_divider_a & EXT_PHY_PCLK_DIVIDERA_MASK) |
>> +           ((param->pclk_divider_b & 3) << 5);
>> +    hdmi_extphy_write(hdmi, stat, EXT_PHY_PCLK_DIVIDER1);
>> +
>> +    stat = (param->pclk_divider_d & EXT_PHY_PCLK_DIVIDERD_MASK) |
>> +           ((param->pclk_divider_c & 3) << 5);
>> +    hdmi_extphy_write(hdmi, stat, EXT_PHY_PCLK_DIVIDER2);
>> +
>> +    stat = ((param->tmsd_divider_c & 3) << 4) |
>> +           ((param->tmsd_divider_a & 3) << 2) |
>> +           (param->tmsd_divider_b & 3);
>> +    hdmi_extphy_write(hdmi, stat, EXT_PHY_TMDSCLK_DIVIDER);
>> +
>> +    hdmi_extphy_write(hdmi, param->ppll_nf, EXT_PHY_PPLL_FB_DIVIDER);
>> +
>> +    if (param->ppll_no == 1) {
>> +            hdmi_extphy_write(hdmi, 0, EXT_PHY_PPLL_POST_DIVIDER);
>> +
>> +            stat = 0x20 | param->ppll_nd;
>> +            hdmi_extphy_write(hdmi, stat, EXT_PHY_PPLL_PRE_DIVIDER);
>> +    } else {
>> +            stat = ((param->ppll_no / 2) - 1) << 4;
>> +            hdmi_extphy_write(hdmi, stat, EXT_PHY_PPLL_POST_DIVIDER);
>> +
>> +            stat = 0xe0 | param->ppll_nd;
>> +            hdmi_extphy_write(hdmi, stat, EXT_PHY_PPLL_PRE_DIVIDER);
>> +    }
>> +
>> +
>> +    /* Find out the external HDMI PHY 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 can't support %dHz\n", pixelclock);
>> +            return -EINVAL;
>> +    }
>> +
>> +    /*
>> +     * Configure the external HDMI PHY driver registers.
>> +     */
>> +    if (ctrl[i].slopeboost) {
>> +            hdmi_extphy_write(hdmi, 0xff, EXT_PHY_SIGNAL_CTRL);
>> +
>> +            stat = (ctrl[i].slopeboost - 1) & 3;
>> +            stat = (stat << 6) | (stat << 4) | (stat << 2) | stat;
>> +            hdmi_extphy_write(hdmi, stat, EXT_PHY_SLOPEBOOST);
>> +    } else
>> +            hdmi_extphy_write(hdmi, 0x0f, EXT_PHY_SIGNAL_CTRL);
>> +
>> +    stat = ctrl[i].pre_emphasis & 3;
>> +    stat = (stat << 4) | (stat << 2) | stat;
>> +    hdmi_extphy_write(hdmi, stat, EXT_PHY_PREEMPHASIS);
>> +
>> +    stat = ((ctrl[i].clk_level & 0xf) << 4) | (ctrl[i].data2_level & 0xf);
>> +    hdmi_extphy_write(hdmi, stat, EXT_PHY_LEVEL1);
>> +
>> +    stat = ((ctrl[i].data1_level & 0xf) << 4) | (ctrl[i].data0_level & 0xf);
>> +    hdmi_extphy_write(hdmi, stat, EXT_PHY_LEVEL2);
>> +
>> +    hdmi_extphy_write(hdmi, 0x22, 0xf3);
>> +
>> +    stat = clk_get_rate(hdmi->extphy_pclk) / 100000;
>> +    hdmi_extphy_write(hdmi, ((stat >> 8) & 0xff) | 0x80, EXT_PHY_TERM_CAL);
>> +    hdmi_extphy_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_extphy_write(hdmi, stat | 0x20, EXT_PHY_TERM_RESIS_AUTO);
>> +    hdmi_extphy_write(hdmi, (stat >> 8) & 0xff, EXT_PHY_TERM_CAL);
>> +
>> +    stat = (pixelclock > 200000000) ? 0 : 0x11;
>> +    hdmi_extphy_write(hdmi, stat, EXT_PHY_PLL_BW);
>> +    hdmi_extphy_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_extphy_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)) {
>> @@ -152,6 +424,37 @@ 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;
>>   }
>>   
>> @@ -159,17 +462,23 @@ static enum drm_mode_status
>>   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; rockchip_mpll_cfg[i].mpixelclock != ~0UL; i++)
>> +                    if (pclk == rockchip_mpll_cfg[i].mpixelclock) {
>> +                            valid = true;
>> +                            break;
>> +                    }
>> +
>> +    if (plat_data->dev_type == RK3229_HDMI)
>> +            for (i = 0; rockchip_extphy_pll_cfg[i].mpixelclock != ~0UL; i++)
>> +                    if (pclk == rockchip_extphy_pll_cfg[i].mpixelclock) {
>> +                            valid = true;
>> +                            break;
>> +                    }
>>   
>>      return (valid) ? MODE_OK : MODE_BAD;
>>   }
>> @@ -199,21 +508,30 @@ 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 = {
>> @@ -223,7 +541,7 @@ 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,
>> @@ -231,9 +549,18 @@ static const struct dw_hdmi_plat_data 
>> rockchip_hdmi_drv_data = {
>>      .dev_type   = RK3288_HDMI,
>>   };
>>   
>> +static const struct dw_hdmi_plat_data rk3229_hdmi_drv_data = {
>> +    .mode_valid = dw_hdmi_rockchip_mode_valid,
>> +    .extphy_config = rockchip_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
>>      },
>>      {},
>>   };
>> 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..f7ec733
>> --- /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 extphy_pll_config_param {
>> +            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 f8dec64..4e63158 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,
>>   };
>>   
>> @@ -54,6 +55,8 @@ struct dw_hdmi_plat_data {
>>      const struct dw_hdmi_phy_config *phy_config;
>>      enum drm_mode_status (*mode_valid)(const struct dw_hdmi_plat_data *pd,
>>                                         struct drm_display_mode *mode);
>> +    int (*extphy_config)(const struct dw_hdmi_plat_data *plat_data,
>> +                         int res_idx, int pixelclock);
>>   };
>>   
>>   void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
>
>
>
>


Reply via email to