12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29e32e16eSYakir Yang /*
39e32e16eSYakir Yang  * Rockchip SoC DP (Display Port) interface driver.
49e32e16eSYakir Yang  *
59e32e16eSYakir Yang  * Copyright (C) Fuzhou Rockchip Electronics Co., Ltd.
69e32e16eSYakir Yang  * Author: Andy Yan <andy.yan@rock-chips.com>
79e32e16eSYakir Yang  *         Yakir Yang <ykk@rock-chips.com>
89e32e16eSYakir Yang  *         Jeff Chen <jeff.chen@rock-chips.com>
99e32e16eSYakir Yang  */
109e32e16eSYakir Yang 
119e32e16eSYakir Yang #include <linux/component.h>
129e32e16eSYakir Yang #include <linux/mfd/syscon.h>
13*722d4f06SRob Herring #include <linux/of.h>
149e32e16eSYakir Yang #include <linux/of_graph.h>
15*722d4f06SRob Herring #include <linux/platform_device.h>
169e32e16eSYakir Yang #include <linux/regmap.h>
179e32e16eSYakir Yang #include <linux/reset.h>
189e32e16eSYakir Yang #include <linux/clk.h>
199e32e16eSYakir Yang 
209e32e16eSYakir Yang #include <video/of_videomode.h>
219e32e16eSYakir Yang #include <video/videomode.h>
229e32e16eSYakir Yang 
23da68386dSThomas Zimmermann #include <drm/display/drm_dp_helper.h>
246c836d96SSean Paul #include <drm/drm_atomic.h>
256c836d96SSean Paul #include <drm/drm_atomic_helper.h>
269e32e16eSYakir Yang #include <drm/bridge/analogix_dp.h>
279e32e16eSYakir Yang #include <drm/drm_of.h>
289e32e16eSYakir Yang #include <drm/drm_panel.h>
299e32e16eSYakir Yang #include <drm/drm_probe_helper.h>
300dbd7354SThomas Zimmermann #include <drm/drm_simple_kms_helper.h>
319e32e16eSYakir Yang 
329e32e16eSYakir Yang #include "rockchip_drm_drv.h"
339e32e16eSYakir Yang #include "rockchip_drm_vop.h"
349e32e16eSYakir Yang 
35d9c900b0SYakir Yang #define RK3288_GRF_SOC_CON6		0x25c
36d9c900b0SYakir Yang #define RK3288_EDP_LCDC_SEL		BIT(5)
3782872e42SYakir Yang #define RK3399_GRF_SOC_CON20		0x6250
3882872e42SYakir Yang #define RK3399_EDP_LCDC_SEL		BIT(5)
39d9c900b0SYakir Yang 
40d9c900b0SYakir Yang #define HIWORD_UPDATE(val, mask)	(val | (mask) << 16)
41d9c900b0SYakir Yang 
428f0ac5c4SYakir Yang #define PSR_WAIT_LINE_FLAG_TIMEOUT_MS	100
438f0ac5c4SYakir Yang 
44d9c900b0SYakir Yang /**
45d9c900b0SYakir Yang  * struct rockchip_dp_chip_data - splite the grf setting of kind of chips
46d9c900b0SYakir Yang  * @lcdsel_grf_reg: grf register offset of lcdc select
47d9c900b0SYakir Yang  * @lcdsel_big: reg value of selecting vop big for eDP
48d9c900b0SYakir Yang  * @lcdsel_lit: reg value of selecting vop little for eDP
49d9c900b0SYakir Yang  * @chip_type: specific chip type
50d9c900b0SYakir Yang  */
51d9c900b0SYakir Yang struct rockchip_dp_chip_data {
52d9c900b0SYakir Yang 	u32	lcdsel_grf_reg;
53d9c900b0SYakir Yang 	u32	lcdsel_big;
54d9c900b0SYakir Yang 	u32	lcdsel_lit;
55d9c900b0SYakir Yang 	u32	chip_type;
56d9c900b0SYakir Yang };
579e32e16eSYakir Yang 
589e32e16eSYakir Yang struct rockchip_dp_device {
599e32e16eSYakir Yang 	struct drm_device        *drm_dev;
609e32e16eSYakir Yang 	struct device            *dev;
61540b8f27SSascha Hauer 	struct rockchip_encoder  encoder;
629e32e16eSYakir Yang 	struct drm_display_mode  mode;
639e32e16eSYakir Yang 
649e32e16eSYakir Yang 	struct clk               *pclk;
65dc1c93beSYakir Yang 	struct clk               *grfclk;
669e32e16eSYakir Yang 	struct regmap            *grf;
679e32e16eSYakir Yang 	struct reset_control     *rst;
689e32e16eSYakir Yang 
69d9c900b0SYakir Yang 	const struct rockchip_dp_chip_data *data;
70d9c900b0SYakir Yang 
716b2d8fd9SJeffy Chen 	struct analogix_dp_device *adp;
729e32e16eSYakir Yang 	struct analogix_dp_plat_data plat_data;
739e32e16eSYakir Yang };
749e32e16eSYakir Yang 
encoder_to_dp(struct drm_encoder * encoder)75540b8f27SSascha Hauer static struct rockchip_dp_device *encoder_to_dp(struct drm_encoder *encoder)
76540b8f27SSascha Hauer {
77540b8f27SSascha Hauer 	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
78540b8f27SSascha Hauer 
79540b8f27SSascha Hauer 	return container_of(rkencoder, struct rockchip_dp_device, encoder);
80540b8f27SSascha Hauer }
81540b8f27SSascha Hauer 
pdata_encoder_to_dp(struct analogix_dp_plat_data * plat_data)82540b8f27SSascha Hauer static struct rockchip_dp_device *pdata_encoder_to_dp(struct analogix_dp_plat_data *plat_data)
83540b8f27SSascha Hauer {
84540b8f27SSascha Hauer 	return container_of(plat_data, struct rockchip_dp_device, plat_data);
85540b8f27SSascha Hauer }
86540b8f27SSascha Hauer 
rockchip_dp_pre_init(struct rockchip_dp_device * dp)879e32e16eSYakir Yang static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
889e32e16eSYakir Yang {
899e32e16eSYakir Yang 	reset_control_assert(dp->rst);
909e32e16eSYakir Yang 	usleep_range(10, 20);
919e32e16eSYakir Yang 	reset_control_deassert(dp->rst);
929e32e16eSYakir Yang 
939e32e16eSYakir Yang 	return 0;
949e32e16eSYakir Yang }
959e32e16eSYakir Yang 
rockchip_dp_poweron_start(struct analogix_dp_plat_data * plat_data)967bb3bb4dSDouglas Anderson static int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data)
979e32e16eSYakir Yang {
98540b8f27SSascha Hauer 	struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
999e32e16eSYakir Yang 	int ret;
1009e32e16eSYakir Yang 
1019e32e16eSYakir Yang 	ret = clk_prepare_enable(dp->pclk);
1029e32e16eSYakir Yang 	if (ret < 0) {
103d8dd6804SHaneen Mohammed 		DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret);
1049e32e16eSYakir Yang 		return ret;
1059e32e16eSYakir Yang 	}
1069e32e16eSYakir Yang 
1079e32e16eSYakir Yang 	ret = rockchip_dp_pre_init(dp);
1089e32e16eSYakir Yang 	if (ret < 0) {
109d8dd6804SHaneen Mohammed 		DRM_DEV_ERROR(dp->dev, "failed to dp pre init %d\n", ret);
1103694c5c3SWei Yongjun 		clk_disable_unprepare(dp->pclk);
1119e32e16eSYakir Yang 		return ret;
1129e32e16eSYakir Yang 	}
1139e32e16eSYakir Yang 
1147bb3bb4dSDouglas Anderson 	return ret;
1157bb3bb4dSDouglas Anderson }
1167bb3bb4dSDouglas Anderson 
rockchip_dp_powerdown(struct analogix_dp_plat_data * plat_data)1179e32e16eSYakir Yang static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
1189e32e16eSYakir Yang {
119540b8f27SSascha Hauer 	struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
1209e32e16eSYakir Yang 
1219e32e16eSYakir Yang 	clk_disable_unprepare(dp->pclk);
1229e32e16eSYakir Yang 
1239e32e16eSYakir Yang 	return 0;
1249e32e16eSYakir Yang }
1259e32e16eSYakir Yang 
rockchip_dp_get_modes(struct analogix_dp_plat_data * plat_data,struct drm_connector * connector)126db8a9aedSYakir Yang static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data,
127db8a9aedSYakir Yang 				 struct drm_connector *connector)
128db8a9aedSYakir Yang {
129db8a9aedSYakir Yang 	struct drm_display_info *di = &connector->display_info;
130db8a9aedSYakir Yang 	/* VOP couldn't output YUV video format for eDP rightly */
131c03d0b52SMaxime Ripard 	u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422;
132db8a9aedSYakir Yang 
133db8a9aedSYakir Yang 	if ((di->color_formats & mask)) {
134db8a9aedSYakir Yang 		DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n");
135db8a9aedSYakir Yang 		di->color_formats &= ~mask;
136db8a9aedSYakir Yang 		di->color_formats |= DRM_COLOR_FORMAT_RGB444;
137db8a9aedSYakir Yang 		di->bpc = 8;
138db8a9aedSYakir Yang 	}
139db8a9aedSYakir Yang 
140db8a9aedSYakir Yang 	return 0;
141db8a9aedSYakir Yang }
142db8a9aedSYakir Yang 
1439e32e16eSYakir Yang static bool
rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)1449e32e16eSYakir Yang rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder,
1459e32e16eSYakir Yang 				   const struct drm_display_mode *mode,
1469e32e16eSYakir Yang 				   struct drm_display_mode *adjusted_mode)
1479e32e16eSYakir Yang {
1489e32e16eSYakir Yang 	/* do nothing */
1499e32e16eSYakir Yang 	return true;
1509e32e16eSYakir Yang }
1519e32e16eSYakir Yang 
rockchip_dp_drm_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted)1529e32e16eSYakir Yang static void rockchip_dp_drm_encoder_mode_set(struct drm_encoder *encoder,
1539e32e16eSYakir Yang 					     struct drm_display_mode *mode,
1549e32e16eSYakir Yang 					     struct drm_display_mode *adjusted)
1559e32e16eSYakir Yang {
1569e32e16eSYakir Yang 	/* do nothing */
1579e32e16eSYakir Yang }
1589e32e16eSYakir Yang 
1596c836d96SSean Paul static
rockchip_dp_drm_get_new_crtc(struct drm_encoder * encoder,struct drm_atomic_state * state)1606c836d96SSean Paul struct drm_crtc *rockchip_dp_drm_get_new_crtc(struct drm_encoder *encoder,
1616c836d96SSean Paul 					      struct drm_atomic_state *state)
1626c836d96SSean Paul {
1636c836d96SSean Paul 	struct drm_connector *connector;
1646c836d96SSean Paul 	struct drm_connector_state *conn_state;
1656c836d96SSean Paul 
1666c836d96SSean Paul 	connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
1676c836d96SSean Paul 	if (!connector)
1686c836d96SSean Paul 		return NULL;
1696c836d96SSean Paul 
1706c836d96SSean Paul 	conn_state = drm_atomic_get_new_connector_state(state, connector);
1716c836d96SSean Paul 	if (!conn_state)
1726c836d96SSean Paul 		return NULL;
1736c836d96SSean Paul 
1746c836d96SSean Paul 	return conn_state->crtc;
1756c836d96SSean Paul }
1766c836d96SSean Paul 
rockchip_dp_drm_encoder_enable(struct drm_encoder * encoder,struct drm_atomic_state * state)1776c836d96SSean Paul static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder,
1786c836d96SSean Paul 					   struct drm_atomic_state *state)
1799e32e16eSYakir Yang {
180540b8f27SSascha Hauer 	struct rockchip_dp_device *dp = encoder_to_dp(encoder);
1816c836d96SSean Paul 	struct drm_crtc *crtc;
1826c836d96SSean Paul 	struct drm_crtc_state *old_crtc_state;
1839e32e16eSYakir Yang 	int ret;
1849e32e16eSYakir Yang 	u32 val;
1859e32e16eSYakir Yang 
1866c836d96SSean Paul 	crtc = rockchip_dp_drm_get_new_crtc(encoder, state);
1876c836d96SSean Paul 	if (!crtc)
1886c836d96SSean Paul 		return;
1896c836d96SSean Paul 
1906c836d96SSean Paul 	old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
1916c836d96SSean Paul 	/* Coming back from self refresh, nothing to do */
1926c836d96SSean Paul 	if (old_crtc_state && old_crtc_state->self_refresh_active)
1936c836d96SSean Paul 		return;
1946c836d96SSean Paul 
1959e32e16eSYakir Yang 	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
1969e32e16eSYakir Yang 	if (ret < 0)
1979e32e16eSYakir Yang 		return;
1989e32e16eSYakir Yang 
1999e32e16eSYakir Yang 	if (ret)
200d9c900b0SYakir Yang 		val = dp->data->lcdsel_lit;
2019e32e16eSYakir Yang 	else
202d9c900b0SYakir Yang 		val = dp->data->lcdsel_big;
2039e32e16eSYakir Yang 
204d8dd6804SHaneen Mohammed 	DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
2059e32e16eSYakir Yang 
206dc1c93beSYakir Yang 	ret = clk_prepare_enable(dp->grfclk);
207dc1c93beSYakir Yang 	if (ret < 0) {
208d8dd6804SHaneen Mohammed 		DRM_DEV_ERROR(dp->dev, "failed to enable grfclk %d\n", ret);
2099e32e16eSYakir Yang 		return;
2109e32e16eSYakir Yang 	}
211dc1c93beSYakir Yang 
212dc1c93beSYakir Yang 	ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val);
213dc1c93beSYakir Yang 	if (ret != 0)
214d8dd6804SHaneen Mohammed 		DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret);
215dc1c93beSYakir Yang 
216dc1c93beSYakir Yang 	clk_disable_unprepare(dp->grfclk);
2179e32e16eSYakir Yang }
2189e32e16eSYakir Yang 
rockchip_dp_drm_encoder_disable(struct drm_encoder * encoder,struct drm_atomic_state * state)2196c836d96SSean Paul static void rockchip_dp_drm_encoder_disable(struct drm_encoder *encoder,
2206c836d96SSean Paul 					    struct drm_atomic_state *state)
2219e32e16eSYakir Yang {
222540b8f27SSascha Hauer 	struct rockchip_dp_device *dp = encoder_to_dp(encoder);
2236c836d96SSean Paul 	struct drm_crtc *crtc;
2246c836d96SSean Paul 	struct drm_crtc_state *new_crtc_state = NULL;
2256c836d96SSean Paul 	int ret;
2266c836d96SSean Paul 
2276c836d96SSean Paul 	crtc = rockchip_dp_drm_get_new_crtc(encoder, state);
2286c836d96SSean Paul 	/* No crtc means we're doing a full shutdown */
2296c836d96SSean Paul 	if (!crtc)
2306c836d96SSean Paul 		return;
2316c836d96SSean Paul 
2326c836d96SSean Paul 	new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
2336c836d96SSean Paul 	/* If we're not entering self-refresh, no need to wait for vact */
2346c836d96SSean Paul 	if (!new_crtc_state || !new_crtc_state->self_refresh_active)
2356c836d96SSean Paul 		return;
2366c836d96SSean Paul 
2376c836d96SSean Paul 	ret = rockchip_drm_wait_vact_end(crtc, PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
2386c836d96SSean Paul 	if (ret)
2396c836d96SSean Paul 		DRM_DEV_ERROR(dp->dev, "line flag irq timed out\n");
2409e32e16eSYakir Yang }
2419e32e16eSYakir Yang 
2424e257d9eSMark Yao static int
rockchip_dp_drm_encoder_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)2434e257d9eSMark Yao rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
2444e257d9eSMark Yao 				      struct drm_crtc_state *crtc_state,
2454e257d9eSMark Yao 				      struct drm_connector_state *conn_state)
2464e257d9eSMark Yao {
2474e257d9eSMark Yao 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
2486bda8112SMark Yao 	struct drm_display_info *di = &conn_state->connector->display_info;
2494e257d9eSMark Yao 
2504e257d9eSMark Yao 	/*
251d698f0ebSYakir Yang 	 * The hardware IC designed that VOP must output the RGB10 video
252d698f0ebSYakir Yang 	 * format to eDP controller, and if eDP panel only support RGB8,
253d698f0ebSYakir Yang 	 * then eDP controller should cut down the video data, not via VOP
254d698f0ebSYakir Yang 	 * controller, that's why we need to hardcode the VOP output mode
255d698f0ebSYakir Yang 	 * to RGA10 here.
2564e257d9eSMark Yao 	 */
25782872e42SYakir Yang 
2584e257d9eSMark Yao 	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
2594e257d9eSMark Yao 	s->output_type = DRM_MODE_CONNECTOR_eDP;
2606bda8112SMark Yao 	s->output_bpc = di->bpc;
2614e257d9eSMark Yao 
2624e257d9eSMark Yao 	return 0;
2634e257d9eSMark Yao }
2644e257d9eSMark Yao 
2659e32e16eSYakir Yang static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = {
2669e32e16eSYakir Yang 	.mode_fixup = rockchip_dp_drm_encoder_mode_fixup,
2679e32e16eSYakir Yang 	.mode_set = rockchip_dp_drm_encoder_mode_set,
2686c836d96SSean Paul 	.atomic_enable = rockchip_dp_drm_encoder_enable,
2696c836d96SSean Paul 	.atomic_disable = rockchip_dp_drm_encoder_disable,
2704e257d9eSMark Yao 	.atomic_check = rockchip_dp_drm_encoder_atomic_check,
2719e32e16eSYakir Yang };
2729e32e16eSYakir Yang 
rockchip_dp_of_probe(struct rockchip_dp_device * dp)273102712a3SJeffy Chen static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
2749e32e16eSYakir Yang {
2759e32e16eSYakir Yang 	struct device *dev = dp->dev;
2769e32e16eSYakir Yang 	struct device_node *np = dev->of_node;
2779e32e16eSYakir Yang 
2789e32e16eSYakir Yang 	dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
2799e32e16eSYakir Yang 	if (IS_ERR(dp->grf)) {
280d8dd6804SHaneen Mohammed 		DRM_DEV_ERROR(dev, "failed to get rockchip,grf property\n");
2819e32e16eSYakir Yang 		return PTR_ERR(dp->grf);
2829e32e16eSYakir Yang 	}
2839e32e16eSYakir Yang 
284dc1c93beSYakir Yang 	dp->grfclk = devm_clk_get(dev, "grf");
285dc1c93beSYakir Yang 	if (PTR_ERR(dp->grfclk) == -ENOENT) {
286dc1c93beSYakir Yang 		dp->grfclk = NULL;
287dc1c93beSYakir Yang 	} else if (PTR_ERR(dp->grfclk) == -EPROBE_DEFER) {
288dc1c93beSYakir Yang 		return -EPROBE_DEFER;
289dc1c93beSYakir Yang 	} else if (IS_ERR(dp->grfclk)) {
290d8dd6804SHaneen Mohammed 		DRM_DEV_ERROR(dev, "failed to get grf clock\n");
291dc1c93beSYakir Yang 		return PTR_ERR(dp->grfclk);
292dc1c93beSYakir Yang 	}
293dc1c93beSYakir Yang 
2949e32e16eSYakir Yang 	dp->pclk = devm_clk_get(dev, "pclk");
2959e32e16eSYakir Yang 	if (IS_ERR(dp->pclk)) {
296d8dd6804SHaneen Mohammed 		DRM_DEV_ERROR(dev, "failed to get pclk property\n");
2979e32e16eSYakir Yang 		return PTR_ERR(dp->pclk);
2989e32e16eSYakir Yang 	}
2999e32e16eSYakir Yang 
3009e32e16eSYakir Yang 	dp->rst = devm_reset_control_get(dev, "dp");
3019e32e16eSYakir Yang 	if (IS_ERR(dp->rst)) {
302d8dd6804SHaneen Mohammed 		DRM_DEV_ERROR(dev, "failed to get dp reset control\n");
3039e32e16eSYakir Yang 		return PTR_ERR(dp->rst);
3049e32e16eSYakir Yang 	}
3059e32e16eSYakir Yang 
3069e32e16eSYakir Yang 	return 0;
3079e32e16eSYakir Yang }
3089e32e16eSYakir Yang 
rockchip_dp_drm_create_encoder(struct rockchip_dp_device * dp)3099e32e16eSYakir Yang static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp)
3109e32e16eSYakir Yang {
311540b8f27SSascha Hauer 	struct drm_encoder *encoder = &dp->encoder.encoder;
3129e32e16eSYakir Yang 	struct drm_device *drm_dev = dp->drm_dev;
3139e32e16eSYakir Yang 	struct device *dev = dp->dev;
3149e32e16eSYakir Yang 	int ret;
3159e32e16eSYakir Yang 
3169e32e16eSYakir Yang 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
3179e32e16eSYakir Yang 							     dev->of_node);
3189e32e16eSYakir Yang 	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
3199e32e16eSYakir Yang 
3200dbd7354SThomas Zimmermann 	ret = drm_simple_encoder_init(drm_dev, encoder,
3210dbd7354SThomas Zimmermann 				      DRM_MODE_ENCODER_TMDS);
3229e32e16eSYakir Yang 	if (ret) {
3239e32e16eSYakir Yang 		DRM_ERROR("failed to initialize encoder with drm\n");
3249e32e16eSYakir Yang 		return ret;
3259e32e16eSYakir Yang 	}
3269e32e16eSYakir Yang 
3279e32e16eSYakir Yang 	drm_encoder_helper_add(encoder, &rockchip_dp_encoder_helper_funcs);
3289e32e16eSYakir Yang 
3299e32e16eSYakir Yang 	return 0;
3309e32e16eSYakir Yang }
3319e32e16eSYakir Yang 
rockchip_dp_bind(struct device * dev,struct device * master,void * data)3329e32e16eSYakir Yang static int rockchip_dp_bind(struct device *dev, struct device *master,
3339e32e16eSYakir Yang 			    void *data)
3349e32e16eSYakir Yang {
3359e32e16eSYakir Yang 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
3369e32e16eSYakir Yang 	struct drm_device *drm_dev = data;
3379e32e16eSYakir Yang 	int ret;
3389e32e16eSYakir Yang 
3399e32e16eSYakir Yang 	dp->drm_dev = drm_dev;
3409e32e16eSYakir Yang 
3419e32e16eSYakir Yang 	ret = rockchip_dp_drm_create_encoder(dp);
3429e32e16eSYakir Yang 	if (ret) {
3439e32e16eSYakir Yang 		DRM_ERROR("failed to create drm encoder\n");
3449e32e16eSYakir Yang 		return ret;
3459e32e16eSYakir Yang 	}
3469e32e16eSYakir Yang 
347540b8f27SSascha Hauer 	dp->plat_data.encoder = &dp->encoder.encoder;
3489e32e16eSYakir Yang 
349152cce00SMarek Szyprowski 	ret = analogix_dp_bind(dp->adp, drm_dev);
350152cce00SMarek Szyprowski 	if (ret)
3516c836d96SSean Paul 		goto err_cleanup_encoder;
3526b2d8fd9SJeffy Chen 
3536b2d8fd9SJeffy Chen 	return 0;
354c8c04514SJeffy Chen err_cleanup_encoder:
355540b8f27SSascha Hauer 	dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder);
356c8c04514SJeffy Chen 	return ret;
3579e32e16eSYakir Yang }
3589e32e16eSYakir Yang 
rockchip_dp_unbind(struct device * dev,struct device * master,void * data)3599e32e16eSYakir Yang static void rockchip_dp_unbind(struct device *dev, struct device *master,
3609e32e16eSYakir Yang 			       void *data)
3619e32e16eSYakir Yang {
3628f0ac5c4SYakir Yang 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
3638f0ac5c4SYakir Yang 
3646b2d8fd9SJeffy Chen 	analogix_dp_unbind(dp->adp);
365540b8f27SSascha Hauer 	dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder);
3669e32e16eSYakir Yang }
3679e32e16eSYakir Yang 
3689e32e16eSYakir Yang static const struct component_ops rockchip_dp_component_ops = {
3699e32e16eSYakir Yang 	.bind = rockchip_dp_bind,
3709e32e16eSYakir Yang 	.unbind = rockchip_dp_unbind,
3719e32e16eSYakir Yang };
3729e32e16eSYakir Yang 
rockchip_dp_probe(struct platform_device * pdev)3739e32e16eSYakir Yang static int rockchip_dp_probe(struct platform_device *pdev)
3749e32e16eSYakir Yang {
3759e32e16eSYakir Yang 	struct device *dev = &pdev->dev;
376152cce00SMarek Szyprowski 	const struct rockchip_dp_chip_data *dp_data;
377eb87c91cSYakir Yang 	struct drm_panel *panel = NULL;
3789e32e16eSYakir Yang 	struct rockchip_dp_device *dp;
379ebc94461SRob Herring 	int ret;
3809e32e16eSYakir Yang 
381152cce00SMarek Szyprowski 	dp_data = of_device_get_match_data(dev);
382152cce00SMarek Szyprowski 	if (!dp_data)
383152cce00SMarek Szyprowski 		return -ENODEV;
384152cce00SMarek Szyprowski 
385ebc94461SRob Herring 	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
386102712a3SJeffy Chen 	if (ret < 0)
387ebc94461SRob Herring 		return ret;
3889e32e16eSYakir Yang 
3899e32e16eSYakir Yang 	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
3909e32e16eSYakir Yang 	if (!dp)
3919e32e16eSYakir Yang 		return -ENOMEM;
3929e32e16eSYakir Yang 
3939e32e16eSYakir Yang 	dp->dev = dev;
394a4169609STomasz Figa 	dp->adp = ERR_PTR(-ENODEV);
395152cce00SMarek Szyprowski 	dp->data = dp_data;
3969e32e16eSYakir Yang 	dp->plat_data.panel = panel;
397152cce00SMarek Szyprowski 	dp->plat_data.dev_type = dp->data->chip_type;
398152cce00SMarek Szyprowski 	dp->plat_data.power_on_start = rockchip_dp_poweron_start;
399152cce00SMarek Szyprowski 	dp->plat_data.power_off = rockchip_dp_powerdown;
400152cce00SMarek Szyprowski 	dp->plat_data.get_modes = rockchip_dp_get_modes;
4019e32e16eSYakir Yang 
402102712a3SJeffy Chen 	ret = rockchip_dp_of_probe(dp);
403102712a3SJeffy Chen 	if (ret < 0)
404102712a3SJeffy Chen 		return ret;
405102712a3SJeffy Chen 
4069e32e16eSYakir Yang 	platform_set_drvdata(pdev, dp);
4079e32e16eSYakir Yang 
408152cce00SMarek Szyprowski 	dp->adp = analogix_dp_probe(dev, &dp->plat_data);
409152cce00SMarek Szyprowski 	if (IS_ERR(dp->adp))
410152cce00SMarek Szyprowski 		return PTR_ERR(dp->adp);
411152cce00SMarek Szyprowski 
41250743768SChristophe JAILLET 	ret = component_add(dev, &rockchip_dp_component_ops);
41350743768SChristophe JAILLET 	if (ret)
41450743768SChristophe JAILLET 		goto err_dp_remove;
41550743768SChristophe JAILLET 
41650743768SChristophe JAILLET 	return 0;
41750743768SChristophe JAILLET 
41850743768SChristophe JAILLET err_dp_remove:
41950743768SChristophe JAILLET 	analogix_dp_remove(dp->adp);
42050743768SChristophe JAILLET 	return ret;
4219e32e16eSYakir Yang }
4229e32e16eSYakir Yang 
rockchip_dp_remove(struct platform_device * pdev)4233c855610SUwe Kleine-König static void rockchip_dp_remove(struct platform_device *pdev)
4249e32e16eSYakir Yang {
425152cce00SMarek Szyprowski 	struct rockchip_dp_device *dp = platform_get_drvdata(pdev);
426152cce00SMarek Szyprowski 
4279e32e16eSYakir Yang 	component_del(&pdev->dev, &rockchip_dp_component_ops);
428152cce00SMarek Szyprowski 	analogix_dp_remove(dp->adp);
4299e32e16eSYakir Yang }
4309e32e16eSYakir Yang 
4316b2d8fd9SJeffy Chen #ifdef CONFIG_PM_SLEEP
rockchip_dp_suspend(struct device * dev)4326b2d8fd9SJeffy Chen static int rockchip_dp_suspend(struct device *dev)
4336b2d8fd9SJeffy Chen {
4346b2d8fd9SJeffy Chen 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
4356b2d8fd9SJeffy Chen 
436a4169609STomasz Figa 	if (IS_ERR(dp->adp))
437a4169609STomasz Figa 		return 0;
438a4169609STomasz Figa 
4396b2d8fd9SJeffy Chen 	return analogix_dp_suspend(dp->adp);
4406b2d8fd9SJeffy Chen }
4416b2d8fd9SJeffy Chen 
rockchip_dp_resume(struct device * dev)4426b2d8fd9SJeffy Chen static int rockchip_dp_resume(struct device *dev)
4436b2d8fd9SJeffy Chen {
4446b2d8fd9SJeffy Chen 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
4456b2d8fd9SJeffy Chen 
446a4169609STomasz Figa 	if (IS_ERR(dp->adp))
447a4169609STomasz Figa 		return 0;
448a4169609STomasz Figa 
4496b2d8fd9SJeffy Chen 	return analogix_dp_resume(dp->adp);
4506b2d8fd9SJeffy Chen }
4516b2d8fd9SJeffy Chen #endif
4526b2d8fd9SJeffy Chen 
4539e32e16eSYakir Yang static const struct dev_pm_ops rockchip_dp_pm_ops = {
454fe64ba5cSTomeu Vizoso #ifdef CONFIG_PM_SLEEP
455f7ccbed6SDouglas Anderson 	.suspend_late = rockchip_dp_suspend,
4566b2d8fd9SJeffy Chen 	.resume_early = rockchip_dp_resume,
457fe64ba5cSTomeu Vizoso #endif
4589e32e16eSYakir Yang };
4599e32e16eSYakir Yang 
46082872e42SYakir Yang static const struct rockchip_dp_chip_data rk3399_edp = {
46182872e42SYakir Yang 	.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
46282872e42SYakir Yang 	.lcdsel_big = HIWORD_UPDATE(0, RK3399_EDP_LCDC_SEL),
46382872e42SYakir Yang 	.lcdsel_lit = HIWORD_UPDATE(RK3399_EDP_LCDC_SEL, RK3399_EDP_LCDC_SEL),
46482872e42SYakir Yang 	.chip_type = RK3399_EDP,
46582872e42SYakir Yang };
46682872e42SYakir Yang 
467d9c900b0SYakir Yang static const struct rockchip_dp_chip_data rk3288_dp = {
468d9c900b0SYakir Yang 	.lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
469d9c900b0SYakir Yang 	.lcdsel_big = HIWORD_UPDATE(0, RK3288_EDP_LCDC_SEL),
470d9c900b0SYakir Yang 	.lcdsel_lit = HIWORD_UPDATE(RK3288_EDP_LCDC_SEL, RK3288_EDP_LCDC_SEL),
471d9c900b0SYakir Yang 	.chip_type = RK3288_DP,
472d9c900b0SYakir Yang };
473d9c900b0SYakir Yang 
4749e32e16eSYakir Yang static const struct of_device_id rockchip_dp_dt_ids[] = {
475d9c900b0SYakir Yang 	{.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp },
47682872e42SYakir Yang 	{.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp },
4779e32e16eSYakir Yang 	{}
4789e32e16eSYakir Yang };
4799e32e16eSYakir Yang MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids);
4809e32e16eSYakir Yang 
4818820b68bSJeffy Chen struct platform_driver rockchip_dp_driver = {
4829e32e16eSYakir Yang 	.probe = rockchip_dp_probe,
4833c855610SUwe Kleine-König 	.remove_new = rockchip_dp_remove,
4849e32e16eSYakir Yang 	.driver = {
4859e32e16eSYakir Yang 		   .name = "rockchip-dp",
4869e32e16eSYakir Yang 		   .pm = &rockchip_dp_pm_ops,
487f7fc7a79SSouptick Joarder 		   .of_match_table = rockchip_dp_dt_ids,
4889e32e16eSYakir Yang 	},
4899e32e16eSYakir Yang };
490