1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Samsung SoC DP (Display Port) interface driver.
5 * Copyright (C) 2012 Samsung Electronics Co., Ltd.
6 * Author: Jingoo Han <jg1.han@samsung.com>
10 #include <linux/component.h>
11 #include <linux/err.h>
12 #include <linux/module.h>
13 #include <linux/of_graph.h>
14 #include <linux/platform_device.h>
15 #include <linux/pm_runtime.h>
16 #include <video/of_display_timing.h>
17 #include <video/of_videomode.h>
18 #include <video/videomode.h>
20 #include <drm/bridge/analogix_dp.h>
21 #include <drm/drm_atomic_helper.h>
22 #include <drm/drm_bridge.h>
23 #include <drm/drm_crtc.h>
24 #include <drm/drm_of.h>
25 #include <drm/drm_panel.h>
26 #include <drm/drm_print.h>
27 #include <drm/drm_probe_helper.h>
28 #include <drm/drm_simple_kms_helper.h>
29 #include <drm/exynos_drm.h>
31 #include "exynos_drm_crtc.h"
33 #define to_dp(nm) container_of(nm, struct exynos_dp_device, nm)
35 struct exynos_dp_device
{
36 struct drm_encoder encoder
;
37 struct drm_connector
*connector
;
38 struct drm_bridge
*ptn_bridge
;
39 struct drm_device
*drm_dev
;
43 struct analogix_dp_device
*adp
;
44 struct analogix_dp_plat_data plat_data
;
47 static int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data
*plat_data
,
50 struct exynos_dp_device
*dp
= to_dp(plat_data
);
51 struct drm_encoder
*encoder
= &dp
->encoder
;
56 exynos_drm_pipe_clk_enable(to_exynos_crtc(encoder
->crtc
), enable
);
61 static int exynos_dp_poweron(struct analogix_dp_plat_data
*plat_data
)
63 return exynos_dp_crtc_clock_enable(plat_data
, true);
66 static int exynos_dp_poweroff(struct analogix_dp_plat_data
*plat_data
)
68 return exynos_dp_crtc_clock_enable(plat_data
, false);
71 static int exynos_dp_get_modes(struct analogix_dp_plat_data
*plat_data
,
72 struct drm_connector
*connector
)
74 struct exynos_dp_device
*dp
= to_dp(plat_data
);
75 struct drm_display_mode
*mode
;
78 if (dp
->plat_data
.panel
)
81 mode
= drm_mode_create(connector
->dev
);
83 DRM_DEV_ERROR(dp
->dev
,
84 "failed to create a new display mode.\n");
88 drm_display_mode_from_videomode(&dp
->vm
, mode
);
89 connector
->display_info
.width_mm
= mode
->width_mm
;
90 connector
->display_info
.height_mm
= mode
->height_mm
;
92 mode
->type
= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
;
93 drm_mode_set_name(mode
);
94 drm_mode_probed_add(connector
, mode
);
99 static int exynos_dp_bridge_attach(struct analogix_dp_plat_data
*plat_data
,
100 struct drm_bridge
*bridge
,
101 struct drm_connector
*connector
)
103 struct exynos_dp_device
*dp
= to_dp(plat_data
);
106 dp
->connector
= connector
;
108 /* Pre-empt DP connector creation if there's a bridge */
109 if (dp
->ptn_bridge
) {
110 ret
= drm_bridge_attach(&dp
->encoder
, dp
->ptn_bridge
, bridge
,
113 DRM_DEV_ERROR(dp
->dev
,
114 "Failed to attach bridge to drm\n");
122 static void exynos_dp_mode_set(struct drm_encoder
*encoder
,
123 struct drm_display_mode
*mode
,
124 struct drm_display_mode
*adjusted_mode
)
128 static void exynos_dp_nop(struct drm_encoder
*encoder
)
133 static const struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs
= {
134 .mode_set
= exynos_dp_mode_set
,
135 .enable
= exynos_dp_nop
,
136 .disable
= exynos_dp_nop
,
139 static int exynos_dp_dt_parse_panel(struct exynos_dp_device
*dp
)
143 ret
= of_get_videomode(dp
->dev
->of_node
, &dp
->vm
, OF_USE_NATIVE_MODE
);
145 DRM_DEV_ERROR(dp
->dev
,
146 "failed: of_get_videomode() : %d\n", ret
);
152 static int exynos_dp_bind(struct device
*dev
, struct device
*master
, void *data
)
154 struct exynos_dp_device
*dp
= dev_get_drvdata(dev
);
155 struct drm_encoder
*encoder
= &dp
->encoder
;
156 struct drm_device
*drm_dev
= data
;
159 dp
->drm_dev
= drm_dev
;
161 if (!dp
->plat_data
.panel
&& !dp
->ptn_bridge
) {
162 ret
= exynos_dp_dt_parse_panel(dp
);
167 drm_simple_encoder_init(drm_dev
, encoder
, DRM_MODE_ENCODER_TMDS
);
169 drm_encoder_helper_add(encoder
, &exynos_dp_encoder_helper_funcs
);
171 ret
= exynos_drm_set_possible_crtcs(encoder
, EXYNOS_DISPLAY_TYPE_LCD
);
175 dp
->plat_data
.encoder
= encoder
;
177 ret
= analogix_dp_bind(dp
->adp
, dp
->drm_dev
);
179 dp
->encoder
.funcs
->destroy(&dp
->encoder
);
184 static void exynos_dp_unbind(struct device
*dev
, struct device
*master
,
187 struct exynos_dp_device
*dp
= dev_get_drvdata(dev
);
189 analogix_dp_unbind(dp
->adp
);
190 dp
->encoder
.funcs
->destroy(&dp
->encoder
);
193 static const struct component_ops exynos_dp_ops
= {
194 .bind
= exynos_dp_bind
,
195 .unbind
= exynos_dp_unbind
,
198 static int exynos_dp_probe(struct platform_device
*pdev
)
200 struct device
*dev
= &pdev
->dev
;
201 struct device_node
*np
;
202 struct exynos_dp_device
*dp
;
203 struct drm_panel
*panel
;
204 struct drm_bridge
*bridge
;
207 dp
= devm_kzalloc(&pdev
->dev
, sizeof(struct exynos_dp_device
),
214 * We just use the drvdata until driver run into component
215 * add function, and then we would set drvdata to null, so
216 * that analogix dp driver would take charge of the drvdata.
218 platform_set_drvdata(pdev
, dp
);
220 /* This is for the backward compatibility. */
221 np
= of_parse_phandle(dev
->of_node
, "panel", 0);
223 dp
->plat_data
.panel
= of_drm_find_panel(np
);
226 if (IS_ERR(dp
->plat_data
.panel
))
227 return PTR_ERR(dp
->plat_data
.panel
);
232 ret
= drm_of_find_panel_or_bridge(dev
->of_node
, 0, 0, &panel
, &bridge
);
236 /* The remote port can be either a panel or a bridge */
237 dp
->plat_data
.panel
= panel
;
238 dp
->plat_data
.dev_type
= EXYNOS_DP
;
239 dp
->plat_data
.power_on_start
= exynos_dp_poweron
;
240 dp
->plat_data
.power_off
= exynos_dp_poweroff
;
241 dp
->plat_data
.attach
= exynos_dp_bridge_attach
;
242 dp
->plat_data
.get_modes
= exynos_dp_get_modes
;
243 dp
->plat_data
.skip_connector
= !!bridge
;
245 dp
->ptn_bridge
= bridge
;
248 dp
->adp
= analogix_dp_probe(dev
, &dp
->plat_data
);
250 return PTR_ERR(dp
->adp
);
252 return component_add(&pdev
->dev
, &exynos_dp_ops
);
255 static int exynos_dp_remove(struct platform_device
*pdev
)
257 struct exynos_dp_device
*dp
= platform_get_drvdata(pdev
);
259 component_del(&pdev
->dev
, &exynos_dp_ops
);
260 analogix_dp_remove(dp
->adp
);
266 static int exynos_dp_suspend(struct device
*dev
)
268 struct exynos_dp_device
*dp
= dev_get_drvdata(dev
);
270 return analogix_dp_suspend(dp
->adp
);
273 static int exynos_dp_resume(struct device
*dev
)
275 struct exynos_dp_device
*dp
= dev_get_drvdata(dev
);
277 return analogix_dp_resume(dp
->adp
);
281 static const struct dev_pm_ops exynos_dp_pm_ops
= {
282 SET_RUNTIME_PM_OPS(exynos_dp_suspend
, exynos_dp_resume
, NULL
)
283 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend
,
284 pm_runtime_force_resume
)
287 static const struct of_device_id exynos_dp_match
[] = {
288 { .compatible
= "samsung,exynos5-dp" },
291 MODULE_DEVICE_TABLE(of
, exynos_dp_match
);
293 struct platform_driver dp_driver
= {
294 .probe
= exynos_dp_probe
,
295 .remove
= exynos_dp_remove
,
298 .owner
= THIS_MODULE
,
299 .pm
= &exynos_dp_pm_ops
,
300 .of_match_table
= exynos_dp_match
,
304 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
305 MODULE_DESCRIPTION("Samsung Specific Analogix-DP Driver Extension");
306 MODULE_LICENSE("GPL v2");