brintos

brintos / linux-shallow public Read only

0
0
Text · 17.7 KiB · 240552e Raw
688 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd4 */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 22#define RK3228_GRF_SOC_CON2		0x040823#define RK3228_HDMI_SDAIN_MSK		BIT(14)24#define RK3228_HDMI_SCLIN_MSK		BIT(13)25#define RK3228_GRF_SOC_CON6		0x041826#define RK3228_HDMI_HPD_VSEL		BIT(6)27#define RK3228_HDMI_SDA_VSEL		BIT(5)28#define RK3228_HDMI_SCL_VSEL		BIT(4)29 30#define RK3288_GRF_SOC_CON6		0x025C31#define RK3288_HDMI_LCDC_SEL		BIT(4)32#define RK3328_GRF_SOC_CON2		0x040833 34#define RK3328_HDMI_SDAIN_MSK		BIT(11)35#define RK3328_HDMI_SCLIN_MSK		BIT(10)36#define RK3328_HDMI_HPD_IOE		BIT(2)37#define RK3328_GRF_SOC_CON3		0x040c38/* need to be unset if hdmi or i2c should control voltage */39#define RK3328_HDMI_SDA5V_GRF		BIT(15)40#define RK3328_HDMI_SCL5V_GRF		BIT(14)41#define RK3328_HDMI_HPD5V_GRF		BIT(13)42#define RK3328_HDMI_CEC5V_GRF		BIT(12)43#define RK3328_GRF_SOC_CON4		0x041044#define RK3328_HDMI_HPD_SARADC		BIT(13)45#define RK3328_HDMI_CEC_5V		BIT(11)46#define RK3328_HDMI_SDA_5V		BIT(10)47#define RK3328_HDMI_SCL_5V		BIT(9)48#define RK3328_HDMI_HPD_5V		BIT(8)49 50#define RK3399_GRF_SOC_CON20		0x625051#define RK3399_HDMI_LCDC_SEL		BIT(6)52 53#define RK3568_GRF_VO_CON1		0x036454#define RK3568_HDMI_SDAIN_MSK		BIT(15)55#define RK3568_HDMI_SCLIN_MSK		BIT(14)56 57#define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)58 59/**60 * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips61 * @lcdsel_grf_reg: grf register offset of lcdc select62 * @lcdsel_big: reg value of selecting vop big for HDMI63 * @lcdsel_lit: reg value of selecting vop little for HDMI64 * @max_tmds_clock: maximum TMDS clock rate supported65 */66struct rockchip_hdmi_chip_data {67	int	lcdsel_grf_reg;68	u32	lcdsel_big;69	u32	lcdsel_lit;70	int	max_tmds_clock;71};72 73struct rockchip_hdmi {74	struct device *dev;75	struct regmap *regmap;76	struct rockchip_encoder encoder;77	const struct rockchip_hdmi_chip_data *chip_data;78	const struct dw_hdmi_plat_data *plat_data;79	struct clk *ref_clk;80	struct clk *grf_clk;81	struct dw_hdmi *hdmi;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		340000000, {165			{ 0x0040, 0x0003 },166			{ 0x3b4c, 0x0003 },167			{ 0x5a64, 0x0003 },168		},169	}, {170		~0UL, {171			{ 0x00a0, 0x000a },172			{ 0x2001, 0x000f },173			{ 0x4002, 0x000f },174		},175	}176};177 178static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {179	/*      pixelclk    bpp8    bpp10   bpp12 */180	{181		40000000,  { 0x0018, 0x0018, 0x0018 },182	}, {183		65000000,  { 0x0028, 0x0028, 0x0028 },184	}, {185		66000000,  { 0x0038, 0x0038, 0x0038 },186	}, {187		74250000,  { 0x0028, 0x0038, 0x0038 },188	}, {189		83500000,  { 0x0028, 0x0038, 0x0038 },190	}, {191		146250000, { 0x0038, 0x0038, 0x0038 },192	}, {193		148500000, { 0x0000, 0x0038, 0x0038 },194	}, {195		600000000, { 0x0000, 0x0000, 0x0000 },196	}, {197		~0UL,      { 0x0000, 0x0000, 0x0000},198	}199};200 201static const struct dw_hdmi_phy_config rockchip_phy_config[] = {202	/*pixelclk   symbol   term   vlev*/203	{ 74250000,  0x8009, 0x0004, 0x0272},204	{ 148500000, 0x802b, 0x0004, 0x028d},205	{ 297000000, 0x8039, 0x0005, 0x028d},206	{ ~0UL,	     0x0000, 0x0000, 0x0000}207};208 209static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)210{211	struct device_node *np = hdmi->dev->of_node;212	int ret;213 214	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");215	if (IS_ERR(hdmi->regmap)) {216		drm_err(hdmi, "Unable to get rockchip,grf\n");217		return PTR_ERR(hdmi->regmap);218	}219 220	hdmi->ref_clk = devm_clk_get_optional_enabled(hdmi->dev, "ref");221	if (!hdmi->ref_clk)222		hdmi->ref_clk = devm_clk_get_optional_enabled(hdmi->dev, "vpll");223 224	if (IS_ERR(hdmi->ref_clk)) {225		ret = PTR_ERR(hdmi->ref_clk);226		if (ret != -EPROBE_DEFER)227			drm_err(hdmi, "failed to get reference clock\n");228		return ret;229	}230 231	hdmi->grf_clk = devm_clk_get_optional(hdmi->dev, "grf");232	if (IS_ERR(hdmi->grf_clk)) {233		ret = PTR_ERR(hdmi->grf_clk);234		if (ret != -EPROBE_DEFER)235			drm_err(hdmi, "failed to get grf clock\n");236		return ret;237	}238 239	ret = devm_regulator_get_enable(hdmi->dev, "avdd-0v9");240	if (ret)241		return ret;242 243	ret = devm_regulator_get_enable(hdmi->dev, "avdd-1v8");244 245	return ret;246}247 248static enum drm_mode_status249dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data,250			    const struct drm_display_info *info,251			    const struct drm_display_mode *mode)252{253	struct rockchip_hdmi *hdmi = data;254	const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;255	int pclk = mode->clock * 1000;256	bool exact_match = hdmi->plat_data->phy_force_vendor;257	int i;258 259	if (hdmi->chip_data->max_tmds_clock &&260	    mode->clock > hdmi->chip_data->max_tmds_clock)261		return MODE_CLOCK_HIGH;262 263	if (hdmi->ref_clk) {264		int rpclk = clk_round_rate(hdmi->ref_clk, pclk);265 266		if (abs(rpclk - pclk) > pclk / 1000)267			return MODE_NOCLOCK;268	}269 270	for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {271		/*272		 * For vendor specific phys force an exact match of the pixelclock273		 * to preserve the original behaviour of the driver.274		 */275		if (exact_match && pclk == mpll_cfg[i].mpixelclock)276			return MODE_OK;277		/*278		 * The Synopsys phy can work with pixelclocks up to the value given279		 * in the corresponding mpll_cfg entry.280		 */281		if (!exact_match && pclk <= mpll_cfg[i].mpixelclock)282			return MODE_OK;283	}284 285	return MODE_BAD;286}287 288static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)289{290}291 292static bool293dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,294				    const struct drm_display_mode *mode,295				    struct drm_display_mode *adj_mode)296{297	return true;298}299 300static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,301					      struct drm_display_mode *mode,302					      struct drm_display_mode *adj_mode)303{304	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);305 306	clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);307}308 309static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)310{311	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);312	u32 val;313	int ret;314 315	if (hdmi->chip_data->lcdsel_grf_reg < 0)316		return;317 318	ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder);319	if (ret)320		val = hdmi->chip_data->lcdsel_lit;321	else322		val = hdmi->chip_data->lcdsel_big;323 324	ret = clk_prepare_enable(hdmi->grf_clk);325	if (ret < 0) {326		drm_err(hdmi, "failed to enable grfclk %d\n", ret);327		return;328	}329 330	ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val);331	if (ret != 0)332		drm_err(hdmi, "Could not write to GRF: %d\n", ret);333 334	clk_disable_unprepare(hdmi->grf_clk);335	drm_dbg(hdmi, "vop %s output to hdmi\n", ret ? "LIT" : "BIG");336}337 338static int339dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,340				      struct drm_crtc_state *crtc_state,341				      struct drm_connector_state *conn_state)342{343	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);344 345	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;346	s->output_type = DRM_MODE_CONNECTOR_HDMIA;347 348	return 0;349}350 351static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {352	.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,353	.mode_set   = dw_hdmi_rockchip_encoder_mode_set,354	.enable     = dw_hdmi_rockchip_encoder_enable,355	.disable    = dw_hdmi_rockchip_encoder_disable,356	.atomic_check = dw_hdmi_rockchip_encoder_atomic_check,357};358 359static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,360					const struct drm_display_info *display,361					const struct drm_display_mode *mode)362{363	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;364 365	dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi, display);366 367	return phy_power_on(hdmi->phy);368}369 370static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data)371{372	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;373 374	phy_power_off(hdmi->phy);375}376 377static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)378{379	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;380 381	dw_hdmi_phy_setup_hpd(dw_hdmi, data);382 383	regmap_write(hdmi->regmap,384		RK3228_GRF_SOC_CON6,385		HIWORD_UPDATE(RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |386			      RK3228_HDMI_SCL_VSEL,387			      RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL |388			      RK3228_HDMI_SCL_VSEL));389 390	regmap_write(hdmi->regmap,391		RK3228_GRF_SOC_CON2,392		HIWORD_UPDATE(RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK,393			      RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK));394}395 396static enum drm_connector_status397dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data)398{399	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;400	enum drm_connector_status status;401 402	status = dw_hdmi_phy_read_hpd(dw_hdmi, data);403 404	if (status == connector_status_connected)405		regmap_write(hdmi->regmap,406			RK3328_GRF_SOC_CON4,407			HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V,408				      RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V));409	else410		regmap_write(hdmi->regmap,411			RK3328_GRF_SOC_CON4,412			HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V |413					 RK3328_HDMI_SCL_5V));414	return status;415}416 417static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data)418{419	struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;420 421	dw_hdmi_phy_setup_hpd(dw_hdmi, data);422 423	/* Enable and map pins to 3V grf-controlled io-voltage */424	regmap_write(hdmi->regmap,425		RK3328_GRF_SOC_CON4,426		HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V |427				 RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V |428				 RK3328_HDMI_HPD_5V));429	regmap_write(hdmi->regmap,430		RK3328_GRF_SOC_CON3,431		HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF |432				 RK3328_HDMI_HPD5V_GRF |433				 RK3328_HDMI_CEC5V_GRF));434	regmap_write(hdmi->regmap,435		RK3328_GRF_SOC_CON2,436		HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK,437			      RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK |438			      RK3328_HDMI_HPD_IOE));439 440	dw_hdmi_rk3328_read_hpd(dw_hdmi, data);441}442 443static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = {444	.init		= dw_hdmi_rockchip_genphy_init,445	.disable	= dw_hdmi_rockchip_genphy_disable,446	.read_hpd	= dw_hdmi_phy_read_hpd,447	.update_hpd	= dw_hdmi_phy_update_hpd,448	.setup_hpd	= dw_hdmi_rk3228_setup_hpd,449};450 451static struct rockchip_hdmi_chip_data rk3228_chip_data = {452	.lcdsel_grf_reg = -1,453	.max_tmds_clock = 594000,454};455 456static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {457	.mode_valid = dw_hdmi_rockchip_mode_valid,458	.phy_data = &rk3228_chip_data,459	.phy_ops = &rk3228_hdmi_phy_ops,460	.phy_name = "inno_dw_hdmi_phy2",461	.phy_force_vendor = true,462};463 464static struct rockchip_hdmi_chip_data rk3288_chip_data = {465	.lcdsel_grf_reg = RK3288_GRF_SOC_CON6,466	.lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL),467	.lcdsel_lit = HIWORD_UPDATE(RK3288_HDMI_LCDC_SEL, RK3288_HDMI_LCDC_SEL),468	.max_tmds_clock = 340000,469};470 471static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {472	.mode_valid = dw_hdmi_rockchip_mode_valid,473	.mpll_cfg   = rockchip_mpll_cfg,474	.cur_ctr    = rockchip_cur_ctr,475	.phy_config = rockchip_phy_config,476	.phy_data = &rk3288_chip_data,477};478 479static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = {480	.init		= dw_hdmi_rockchip_genphy_init,481	.disable	= dw_hdmi_rockchip_genphy_disable,482	.read_hpd	= dw_hdmi_rk3328_read_hpd,483	.update_hpd	= dw_hdmi_phy_update_hpd,484	.setup_hpd	= dw_hdmi_rk3328_setup_hpd,485};486 487static struct rockchip_hdmi_chip_data rk3328_chip_data = {488	.lcdsel_grf_reg = -1,489	.max_tmds_clock = 594000,490};491 492static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {493	.mode_valid = dw_hdmi_rockchip_mode_valid,494	.phy_data = &rk3328_chip_data,495	.phy_ops = &rk3328_hdmi_phy_ops,496	.phy_name = "inno_dw_hdmi_phy2",497	.phy_force_vendor = true,498	.use_drm_infoframe = true,499};500 501static struct rockchip_hdmi_chip_data rk3399_chip_data = {502	.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,503	.lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL),504	.lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL),505	.max_tmds_clock = 340000,506};507 508static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {509	.mode_valid = dw_hdmi_rockchip_mode_valid,510	.mpll_cfg   = rockchip_mpll_cfg,511	.cur_ctr    = rockchip_cur_ctr,512	.phy_config = rockchip_phy_config,513	.phy_data = &rk3399_chip_data,514	.use_drm_infoframe = true,515};516 517static struct rockchip_hdmi_chip_data rk3568_chip_data = {518	.lcdsel_grf_reg = -1,519	.max_tmds_clock = 340000,520};521 522static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {523	.mode_valid = dw_hdmi_rockchip_mode_valid,524	.mpll_cfg   = rockchip_mpll_cfg,525	.cur_ctr    = rockchip_cur_ctr,526	.phy_config = rockchip_phy_config,527	.phy_data = &rk3568_chip_data,528	.use_drm_infoframe = true,529};530 531static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {532	{ .compatible = "rockchip,rk3228-dw-hdmi",533	  .data = &rk3228_hdmi_drv_data534	},535	{ .compatible = "rockchip,rk3288-dw-hdmi",536	  .data = &rk3288_hdmi_drv_data537	},538	{ .compatible = "rockchip,rk3328-dw-hdmi",539	  .data = &rk3328_hdmi_drv_data540	},541	{ .compatible = "rockchip,rk3399-dw-hdmi",542	  .data = &rk3399_hdmi_drv_data543	},544	{ .compatible = "rockchip,rk3568-dw-hdmi",545	  .data = &rk3568_hdmi_drv_data546	},547	{},548};549MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);550 551static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,552				 void *data)553{554	struct platform_device *pdev = to_platform_device(dev);555	struct dw_hdmi_plat_data *plat_data;556	const struct of_device_id *match;557	struct drm_device *drm = data;558	struct drm_encoder *encoder;559	struct rockchip_hdmi *hdmi;560	int ret;561 562	if (!pdev->dev.of_node)563		return -ENODEV;564 565	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);566	if (!hdmi)567		return -ENOMEM;568 569	match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);570	plat_data = devm_kmemdup(&pdev->dev, match->data,571					     sizeof(*plat_data), GFP_KERNEL);572	if (!plat_data)573		return -ENOMEM;574 575	hdmi->dev = &pdev->dev;576	hdmi->plat_data = plat_data;577	hdmi->chip_data = plat_data->phy_data;578	plat_data->phy_data = hdmi;579	plat_data->priv_data = hdmi;580	encoder = &hdmi->encoder.encoder;581 582	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);583	rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,584						  dev->of_node, 0, 0);585 586	/*587	 * If we failed to find the CRTC(s) which this encoder is588	 * supposed to be connected to, it's because the CRTC has589	 * not been registered yet.  Defer probing, and hope that590	 * the required CRTC is added later.591	 */592	if (encoder->possible_crtcs == 0)593		return -EPROBE_DEFER;594 595	ret = rockchip_hdmi_parse_dt(hdmi);596	if (ret) {597		if (ret != -EPROBE_DEFER)598			drm_err(hdmi, "Unable to parse OF data\n");599		return ret;600	}601 602	hdmi->phy = devm_phy_optional_get(dev, "hdmi");603	if (IS_ERR(hdmi->phy)) {604		ret = PTR_ERR(hdmi->phy);605		if (ret != -EPROBE_DEFER)606			drm_err(hdmi, "failed to get phy\n");607		return ret;608	}609 610	if (hdmi->chip_data == &rk3568_chip_data) {611		regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,612			     HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |613					   RK3568_HDMI_SCLIN_MSK,614					   RK3568_HDMI_SDAIN_MSK |615					   RK3568_HDMI_SCLIN_MSK));616	}617 618	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);619	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);620 621	platform_set_drvdata(pdev, hdmi);622 623	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);624 625	/*626	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),627	 * which would have called the encoder cleanup.  Do it manually.628	 */629	if (IS_ERR(hdmi->hdmi)) {630		ret = PTR_ERR(hdmi->hdmi);631		goto err_bind;632	}633 634	return 0;635 636err_bind:637	drm_encoder_cleanup(encoder);638 639	return ret;640}641 642static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,643				    void *data)644{645	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);646 647	dw_hdmi_unbind(hdmi->hdmi);648	drm_encoder_cleanup(&hdmi->encoder.encoder);649}650 651static const struct component_ops dw_hdmi_rockchip_ops = {652	.bind	= dw_hdmi_rockchip_bind,653	.unbind	= dw_hdmi_rockchip_unbind,654};655 656static int dw_hdmi_rockchip_probe(struct platform_device *pdev)657{658	return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);659}660 661static void dw_hdmi_rockchip_remove(struct platform_device *pdev)662{663	component_del(&pdev->dev, &dw_hdmi_rockchip_ops);664}665 666static int __maybe_unused dw_hdmi_rockchip_resume(struct device *dev)667{668	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);669 670	dw_hdmi_resume(hdmi->hdmi);671 672	return 0;673}674 675static const struct dev_pm_ops dw_hdmi_rockchip_pm = {676	SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_rockchip_resume)677};678 679struct platform_driver dw_hdmi_rockchip_pltfm_driver = {680	.probe  = dw_hdmi_rockchip_probe,681	.remove_new = dw_hdmi_rockchip_remove,682	.driver = {683		.name = "dwhdmi-rockchip",684		.pm = &dw_hdmi_rockchip_pm,685		.of_match_table = dw_hdmi_rockchip_dt_ids,686	},687};688