cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dw_hdmi-rockchip.c (18125B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
      4 */
      5
      6#include <linux/clk.h>
      7#include <linux/mfd/syscon.h>
      8#include <linux/module.h>
      9#include <linux/platform_device.h>
     10#include <linux/phy/phy.h>
     11#include <linux/regmap.h>
     12#include <linux/regulator/consumer.h>
     13
     14#include <drm/bridge/dw_hdmi.h>
     15#include <drm/drm_edid.h>
     16#include <drm/drm_of.h>
     17#include <drm/drm_probe_helper.h>
     18#include <drm/drm_simple_kms_helper.h>
     19
     20#include "rockchip_drm_drv.h"
     21#include "rockchip_drm_vop.h"
     22
     23#define RK3228_GRF_SOC_CON2		0x0408
     24#define RK3228_HDMI_SDAIN_MSK		BIT(14)
     25#define RK3228_HDMI_SCLIN_MSK		BIT(13)
     26#define RK3228_GRF_SOC_CON6		0x0418
     27#define RK3228_HDMI_HPD_VSEL		BIT(6)
     28#define RK3228_HDMI_SDA_VSEL		BIT(5)
     29#define RK3228_HDMI_SCL_VSEL		BIT(4)
     30
     31#define RK3288_GRF_SOC_CON6		0x025C
     32#define RK3288_HDMI_LCDC_SEL		BIT(4)
     33#define RK3328_GRF_SOC_CON2		0x0408
     34
     35#define RK3328_HDMI_SDAIN_MSK		BIT(11)
     36#define RK3328_HDMI_SCLIN_MSK		BIT(10)
     37#define RK3328_HDMI_HPD_IOE		BIT(2)
     38#define RK3328_GRF_SOC_CON3		0x040c
     39/* need to be unset if hdmi or i2c should control voltage */
     40#define RK3328_HDMI_SDA5V_GRF		BIT(15)
     41#define RK3328_HDMI_SCL5V_GRF		BIT(14)
     42#define RK3328_HDMI_HPD5V_GRF		BIT(13)
     43#define RK3328_HDMI_CEC5V_GRF		BIT(12)
     44#define RK3328_GRF_SOC_CON4		0x0410
     45#define RK3328_HDMI_HPD_SARADC		BIT(13)
     46#define RK3328_HDMI_CEC_5V		BIT(11)
     47#define RK3328_HDMI_SDA_5V		BIT(10)
     48#define RK3328_HDMI_SCL_5V		BIT(9)
     49#define RK3328_HDMI_HPD_5V		BIT(8)
     50
     51#define RK3399_GRF_SOC_CON20		0x6250
     52#define RK3399_HDMI_LCDC_SEL		BIT(6)
     53
     54#define RK3568_GRF_VO_CON1		0x0364
     55#define RK3568_HDMI_SDAIN_MSK		BIT(15)
     56#define RK3568_HDMI_SCLIN_MSK		BIT(14)
     57
     58#define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)
     59
     60/**
     61 * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips
     62 * @lcdsel_grf_reg: grf register offset of lcdc select
     63 * @lcdsel_big: reg value of selecting vop big for HDMI
     64 * @lcdsel_lit: reg value of selecting vop little for HDMI
     65 */
     66struct rockchip_hdmi_chip_data {
     67	int	lcdsel_grf_reg;
     68	u32	lcdsel_big;
     69	u32	lcdsel_lit;
     70};
     71
     72struct rockchip_hdmi {
     73	struct device *dev;
     74	struct regmap *regmap;
     75	struct rockchip_encoder encoder;
     76	const struct rockchip_hdmi_chip_data *chip_data;
     77	struct clk *ref_clk;
     78	struct clk *grf_clk;
     79	struct dw_hdmi *hdmi;
     80	struct regulator *avdd_0v9;
     81	struct regulator *avdd_1v8;
     82	struct phy *phy;
     83};
     84
     85static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder)
     86{
     87	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
     88
     89	return container_of(rkencoder, struct rockchip_hdmi, encoder);
     90}
     91
     92static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
     93	{
     94		27000000, {
     95			{ 0x00b3, 0x0000},
     96			{ 0x2153, 0x0000},
     97			{ 0x40f3, 0x0000}
     98		},
     99	}, {
    100		36000000, {
    101			{ 0x00b3, 0x0000},
    102			{ 0x2153, 0x0000},
    103			{ 0x40f3, 0x0000}
    104		},
    105	}, {
    106		40000000, {
    107			{ 0x00b3, 0x0000},
    108			{ 0x2153, 0x0000},
    109			{ 0x40f3, 0x0000}
    110		},
    111	}, {
    112		54000000, {
    113			{ 0x0072, 0x0001},
    114			{ 0x2142, 0x0001},
    115			{ 0x40a2, 0x0001},
    116		},
    117	}, {
    118		65000000, {
    119			{ 0x0072, 0x0001},
    120			{ 0x2142, 0x0001},
    121			{ 0x40a2, 0x0001},
    122		},
    123	}, {
    124		66000000, {
    125			{ 0x013e, 0x0003},
    126			{ 0x217e, 0x0002},
    127			{ 0x4061, 0x0002}
    128		},
    129	}, {
    130		74250000, {
    131			{ 0x0072, 0x0001},
    132			{ 0x2145, 0x0002},
    133			{ 0x4061, 0x0002}
    134		},
    135	}, {
    136		83500000, {
    137			{ 0x0072, 0x0001},
    138		},
    139	}, {
    140		108000000, {
    141			{ 0x0051, 0x0002},
    142			{ 0x2145, 0x0002},
    143			{ 0x4061, 0x0002}
    144		},
    145	}, {
    146		106500000, {
    147			{ 0x0051, 0x0002},
    148			{ 0x2145, 0x0002},
    149			{ 0x4061, 0x0002}
    150		},
    151	}, {
    152		146250000, {
    153			{ 0x0051, 0x0002},
    154			{ 0x2145, 0x0002},
    155			{ 0x4061, 0x0002}
    156		},
    157	}, {
    158		148500000, {
    159			{ 0x0051, 0x0003},
    160			{ 0x214c, 0x0003},
    161			{ 0x4064, 0x0003}
    162		},
    163	}, {
    164		~0UL, {
    165			{ 0x00a0, 0x000a },
    166			{ 0x2001, 0x000f },
    167			{ 0x4002, 0x000f },
    168		},
    169	}
    170};
    171
    172static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
    173	/*      pixelclk    bpp8    bpp10   bpp12 */
    174	{
    175		40000000,  { 0x0018, 0x0018, 0x0018 },
    176	}, {
    177		65000000,  { 0x0028, 0x0028, 0x0028 },
    178	}, {
    179		66000000,  { 0x0038, 0x0038, 0x0038 },
    180	}, {
    181		74250000,  { 0x0028, 0x0038, 0x0038 },
    182	}, {
    183		83500000,  { 0x0028, 0x0038, 0x0038 },
    184	}, {
    185		146250000, { 0x0038, 0x0038, 0x0038 },
    186	}, {
    187		148500000, { 0x0000, 0x0038, 0x0038 },
    188	}, {
    189		~0UL,      { 0x0000, 0x0000, 0x0000},
    190	}
    191};
    192
    193static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
    194	/*pixelclk   symbol   term   vlev*/
    195	{ 74250000,  0x8009, 0x0004, 0x0272},
    196	{ 148500000, 0x802b, 0x0004, 0x028d},
    197	{ 297000000, 0x8039, 0x0005, 0x028d},
    198	{ ~0UL,	     0x0000, 0x0000, 0x0000}
    199};
    200
    201static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
    202{
    203	struct device_node *np = hdmi->dev->of_node;
    204
    205	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
    206	if (IS_ERR(hdmi->regmap)) {
    207		DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,grf\n");
    208		return PTR_ERR(hdmi->regmap);
    209	}
    210
    211	hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "ref");
    212	if (!hdmi->ref_clk)
    213		hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "vpll");
    214
    215	if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) {
    216		return -EPROBE_DEFER;
    217	} else if (IS_ERR(hdmi->ref_clk)) {
    218		DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n");
    219		return PTR_ERR(hdmi->ref_clk);
    220	}
    221
    222	hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
    223	if (PTR_ERR(hdmi->grf_clk) == -ENOENT) {
    224		hdmi->grf_clk = NULL;
    225	} else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) {
    226		return -EPROBE_DEFER;
    227	} else if (IS_ERR(hdmi->grf_clk)) {
    228		DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n");
    229		return PTR_ERR(hdmi->grf_clk);
    230	}
    231
    232	hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9");
    233	if (IS_ERR(hdmi->avdd_0v9))
    234		return PTR_ERR(hdmi->avdd_0v9);
    235
    236	hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8");
    237	if (IS_ERR(hdmi->avdd_1v8))
    238		return PTR_ERR(hdmi->avdd_1v8);
    239
    240	return 0;
    241}
    242
    243static enum drm_mode_status
    244dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data,
    245			    const struct drm_display_info *info,
    246			    const struct drm_display_mode *mode)
    247{
    248	const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
    249	int pclk = mode->clock * 1000;
    250	bool valid = false;
    251	int i;
    252
    253	for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
    254		if (pclk == mpll_cfg[i].mpixelclock) {
    255			valid = true;
    256			break;
    257		}
    258	}
    259
    260	return (valid) ? MODE_OK : MODE_BAD;
    261}
    262
    263static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
    264{
    265}
    266
    267static bool
    268dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
    269				    const struct drm_display_mode *mode,
    270				    struct drm_display_mode *adj_mode)
    271{
    272	return true;
    273}
    274
    275static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
    276					      struct drm_display_mode *mode,
    277					      struct drm_display_mode *adj_mode)
    278{
    279	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
    280
    281	clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
    282}
    283
    284static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
    285{
    286	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
    287	u32 val;
    288	int ret;
    289
    290	if (hdmi->chip_data->lcdsel_grf_reg < 0)
    291		return;
    292
    293	ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);
    294	if (ret)
    295		val = hdmi->chip_data->lcdsel_lit;
    296	else
    297		val = hdmi->chip_data->lcdsel_big;
    298
    299	ret = clk_prepare_enable(hdmi->grf_clk);
    300	if (ret < 0) {
    301		DRM_DEV_ERROR(hdmi->dev, "failed to enable grfclk %d\n", ret);
    302		return;
    303	}
    304
    305	ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val);
    306	if (ret != 0)
    307		DRM_DEV_ERROR(hdmi->dev, "Could not write to GRF: %d\n", ret);
    308
    309	clk_disable_unprepare(hdmi->grf_clk);
    310	DRM_DEV_DEBUG(hdmi->dev, "vop %s output to hdmi\n",
    311		      ret ? "LIT" : "BIG");
    312}
    313
    314static int
    315dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
    316				      struct drm_crtc_state *crtc_state,
    317				      struct drm_connector_state *conn_state)
    318{
    319	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
    320
    321	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
    322	s->output_type = DRM_MODE_CONNECTOR_HDMIA;
    323
    324	return 0;
    325}
    326
    327static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
    328	.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
    329	.mode_set   = dw_hdmi_rockchip_encoder_mode_set,
    330	.enable     = dw_hdmi_rockchip_encoder_enable,
    331	.disable    = dw_hdmi_rockchip_encoder_disable,
    332	.atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
    333};
    334
    335static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
    336					const struct drm_display_info *display,
    337					const struct drm_display_mode *mode)
    338{
    339	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
    340
    341	return phy_power_on(hdmi->phy);
    342}
    343
    344static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data)
    345{
    346	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
    347
    348	phy_power_off(hdmi->phy);
    349}
    350
    351static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
    352{
    353	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
    354
    355	dw_hdmi_phy_setup_hpd(dw_hdmi, data);
    356
    357	regmap_write(hdmi->regmap,
    358		RK3228_GRF_SOC_CON6,
    359		HIWORD_UPDATE(RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |
    360			      RK3228_HDMI_SCL_VSEL,
    361			      RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |
    362			      RK3228_HDMI_SCL_VSEL));
    363
    364	regmap_write(hdmi->regmap,
    365		RK3228_GRF_SOC_CON2,
    366		HIWORD_UPDATE(RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK,
    367			      RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK));
    368}
    369
    370static enum drm_connector_status
    371dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
    372{
    373	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
    374	enum drm_connector_status status;
    375
    376	status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
    377
    378	if (status == connector_status_connected)
    379		regmap_write(hdmi->regmap,
    380			RK3328_GRF_SOC_CON4,
    381			HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V,
    382				      RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V));
    383	else
    384		regmap_write(hdmi->regmap,
    385			RK3328_GRF_SOC_CON4,
    386			HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V |
    387					 RK3328_HDMI_SCL_5V));
    388	return status;
    389}
    390
    391static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)
    392{
    393	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
    394
    395	dw_hdmi_phy_setup_hpd(dw_hdmi, data);
    396
    397	/* Enable and map pins to 3V grf-controlled io-voltage */
    398	regmap_write(hdmi->regmap,
    399		RK3328_GRF_SOC_CON4,
    400		HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V |
    401				 RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V |
    402				 RK3328_HDMI_HPD_5V));
    403	regmap_write(hdmi->regmap,
    404		RK3328_GRF_SOC_CON3,
    405		HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF |
    406				 RK3328_HDMI_HPD5V_GRF |
    407				 RK3328_HDMI_CEC5V_GRF));
    408	regmap_write(hdmi->regmap,
    409		RK3328_GRF_SOC_CON2,
    410		HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK,
    411			      RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK |
    412			      RK3328_HDMI_HPD_IOE));
    413}
    414
    415static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = {
    416	.init		= dw_hdmi_rockchip_genphy_init,
    417	.disable	= dw_hdmi_rockchip_genphy_disable,
    418	.read_hpd	= dw_hdmi_phy_read_hpd,
    419	.update_hpd	= dw_hdmi_phy_update_hpd,
    420	.setup_hpd	= dw_hdmi_rk3228_setup_hpd,
    421};
    422
    423static struct rockchip_hdmi_chip_data rk3228_chip_data = {
    424	.lcdsel_grf_reg = -1,
    425};
    426
    427static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
    428	.mode_valid = dw_hdmi_rockchip_mode_valid,
    429	.mpll_cfg = rockchip_mpll_cfg,
    430	.cur_ctr = rockchip_cur_ctr,
    431	.phy_config = rockchip_phy_config,
    432	.phy_data = &rk3228_chip_data,
    433	.phy_ops = &rk3228_hdmi_phy_ops,
    434	.phy_name = "inno_dw_hdmi_phy2",
    435	.phy_force_vendor = true,
    436};
    437
    438static struct rockchip_hdmi_chip_data rk3288_chip_data = {
    439	.lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
    440	.lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL),
    441	.lcdsel_lit = HIWORD_UPDATE(RK3288_HDMI_LCDC_SEL, RK3288_HDMI_LCDC_SEL),
    442};
    443
    444static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
    445	.mode_valid = dw_hdmi_rockchip_mode_valid,
    446	.mpll_cfg   = rockchip_mpll_cfg,
    447	.cur_ctr    = rockchip_cur_ctr,
    448	.phy_config = rockchip_phy_config,
    449	.phy_data = &rk3288_chip_data,
    450};
    451
    452static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = {
    453	.init		= dw_hdmi_rockchip_genphy_init,
    454	.disable	= dw_hdmi_rockchip_genphy_disable,
    455	.read_hpd	= dw_hdmi_rk3328_read_hpd,
    456	.update_hpd	= dw_hdmi_phy_update_hpd,
    457	.setup_hpd	= dw_hdmi_rk3328_setup_hpd,
    458};
    459
    460static struct rockchip_hdmi_chip_data rk3328_chip_data = {
    461	.lcdsel_grf_reg = -1,
    462};
    463
    464static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
    465	.mode_valid = dw_hdmi_rockchip_mode_valid,
    466	.mpll_cfg = rockchip_mpll_cfg,
    467	.cur_ctr = rockchip_cur_ctr,
    468	.phy_config = rockchip_phy_config,
    469	.phy_data = &rk3328_chip_data,
    470	.phy_ops = &rk3328_hdmi_phy_ops,
    471	.phy_name = "inno_dw_hdmi_phy2",
    472	.phy_force_vendor = true,
    473	.use_drm_infoframe = true,
    474};
    475
    476static struct rockchip_hdmi_chip_data rk3399_chip_data = {
    477	.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
    478	.lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL),
    479	.lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL),
    480};
    481
    482static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
    483	.mode_valid = dw_hdmi_rockchip_mode_valid,
    484	.mpll_cfg   = rockchip_mpll_cfg,
    485	.cur_ctr    = rockchip_cur_ctr,
    486	.phy_config = rockchip_phy_config,
    487	.phy_data = &rk3399_chip_data,
    488	.use_drm_infoframe = true,
    489};
    490
    491static struct rockchip_hdmi_chip_data rk3568_chip_data = {
    492	.lcdsel_grf_reg = -1,
    493};
    494
    495static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
    496	.mode_valid = dw_hdmi_rockchip_mode_valid,
    497	.mpll_cfg   = rockchip_mpll_cfg,
    498	.cur_ctr    = rockchip_cur_ctr,
    499	.phy_config = rockchip_phy_config,
    500	.phy_data = &rk3568_chip_data,
    501	.use_drm_infoframe = true,
    502};
    503
    504static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
    505	{ .compatible = "rockchip,rk3228-dw-hdmi",
    506	  .data = &rk3228_hdmi_drv_data
    507	},
    508	{ .compatible = "rockchip,rk3288-dw-hdmi",
    509	  .data = &rk3288_hdmi_drv_data
    510	},
    511	{ .compatible = "rockchip,rk3328-dw-hdmi",
    512	  .data = &rk3328_hdmi_drv_data
    513	},
    514	{ .compatible = "rockchip,rk3399-dw-hdmi",
    515	  .data = &rk3399_hdmi_drv_data
    516	},
    517	{ .compatible = "rockchip,rk3568-dw-hdmi",
    518	  .data = &rk3568_hdmi_drv_data
    519	},
    520	{},
    521};
    522MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
    523
    524static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
    525				 void *data)
    526{
    527	struct platform_device *pdev = to_platform_device(dev);
    528	struct dw_hdmi_plat_data *plat_data;
    529	const struct of_device_id *match;
    530	struct drm_device *drm = data;
    531	struct drm_encoder *encoder;
    532	struct rockchip_hdmi *hdmi;
    533	int ret;
    534
    535	if (!pdev->dev.of_node)
    536		return -ENODEV;
    537
    538	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
    539	if (!hdmi)
    540		return -ENOMEM;
    541
    542	match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
    543	plat_data = devm_kmemdup(&pdev->dev, match->data,
    544					     sizeof(*plat_data), GFP_KERNEL);
    545	if (!plat_data)
    546		return -ENOMEM;
    547
    548	hdmi->dev = &pdev->dev;
    549	hdmi->chip_data = plat_data->phy_data;
    550	plat_data->phy_data = hdmi;
    551	encoder = &hdmi->encoder.encoder;
    552
    553	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
    554	rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,
    555						  dev->of_node, 0, 0);
    556
    557	/*
    558	 * If we failed to find the CRTC(s) which this encoder is
    559	 * supposed to be connected to, it's because the CRTC has
    560	 * not been registered yet.  Defer probing, and hope that
    561	 * the required CRTC is added later.
    562	 */
    563	if (encoder->possible_crtcs == 0)
    564		return -EPROBE_DEFER;
    565
    566	ret = rockchip_hdmi_parse_dt(hdmi);
    567	if (ret) {
    568		DRM_DEV_ERROR(hdmi->dev, "Unable to parse OF data\n");
    569		return ret;
    570	}
    571
    572	hdmi->phy = devm_phy_optional_get(dev, "hdmi");
    573	if (IS_ERR(hdmi->phy)) {
    574		ret = PTR_ERR(hdmi->phy);
    575		if (ret != -EPROBE_DEFER)
    576			DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n");
    577		return ret;
    578	}
    579
    580	ret = regulator_enable(hdmi->avdd_0v9);
    581	if (ret) {
    582		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret);
    583		goto err_avdd_0v9;
    584	}
    585
    586	ret = regulator_enable(hdmi->avdd_1v8);
    587	if (ret) {
    588		DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret);
    589		goto err_avdd_1v8;
    590	}
    591
    592	ret = clk_prepare_enable(hdmi->ref_clk);
    593	if (ret) {
    594		DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
    595			      ret);
    596		goto err_clk;
    597	}
    598
    599	if (hdmi->chip_data == &rk3568_chip_data) {
    600		regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
    601			     HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |
    602					   RK3568_HDMI_SCLIN_MSK,
    603					   RK3568_HDMI_SDAIN_MSK |
    604					   RK3568_HDMI_SCLIN_MSK));
    605	}
    606
    607	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
    608	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
    609
    610	platform_set_drvdata(pdev, hdmi);
    611
    612	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
    613
    614	/*
    615	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
    616	 * which would have called the encoder cleanup.  Do it manually.
    617	 */
    618	if (IS_ERR(hdmi->hdmi)) {
    619		ret = PTR_ERR(hdmi->hdmi);
    620		goto err_bind;
    621	}
    622
    623	return 0;
    624
    625err_bind:
    626	drm_encoder_cleanup(encoder);
    627	clk_disable_unprepare(hdmi->ref_clk);
    628err_clk:
    629	regulator_disable(hdmi->avdd_1v8);
    630err_avdd_1v8:
    631	regulator_disable(hdmi->avdd_0v9);
    632err_avdd_0v9:
    633	return ret;
    634}
    635
    636static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
    637				    void *data)
    638{
    639	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
    640
    641	dw_hdmi_unbind(hdmi->hdmi);
    642	clk_disable_unprepare(hdmi->ref_clk);
    643
    644	regulator_disable(hdmi->avdd_1v8);
    645	regulator_disable(hdmi->avdd_0v9);
    646}
    647
    648static const struct component_ops dw_hdmi_rockchip_ops = {
    649	.bind	= dw_hdmi_rockchip_bind,
    650	.unbind	= dw_hdmi_rockchip_unbind,
    651};
    652
    653static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
    654{
    655	return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
    656}
    657
    658static int dw_hdmi_rockchip_remove(struct platform_device *pdev)
    659{
    660	component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
    661
    662	return 0;
    663}
    664
    665static int __maybe_unused dw_hdmi_rockchip_resume(struct device *dev)
    666{
    667	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
    668
    669	dw_hdmi_resume(hdmi->hdmi);
    670
    671	return 0;
    672}
    673
    674static const struct dev_pm_ops dw_hdmi_rockchip_pm = {
    675	SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_rockchip_resume)
    676};
    677
    678struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
    679	.probe  = dw_hdmi_rockchip_probe,
    680	.remove = dw_hdmi_rockchip_remove,
    681	.driver = {
    682		.name = "dwhdmi-rockchip",
    683		.pm = &dw_hdmi_rockchip_pm,
    684		.of_match_table = dw_hdmi_rockchip_dt_ids,
    685	},
    686};