2 * Rockchip SoC DP (Display Port) interface driver.
4 * Copyright (C) Fuzhou Rockchip Electronics Co., Ltd.
5 * Author: Andy Yan <andy.yan@rock-chips.com>
6 * Yakir Yang <ykk@rock-chips.com>
7 * Jeff Chen <jeff.chen@rock-chips.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
15 #include <linux/component.h>
16 #include <linux/mfd/syscon.h>
17 #include <linux/of_graph.h>
18 #include <linux/regmap.h>
19 #include <linux/reset.h>
20 #include <linux/clk.h>
23 #include <drm/drm_crtc_helper.h>
24 #include <drm/drm_dp_helper.h>
25 #include <drm/drm_of.h>
26 #include <drm/drm_panel.h>
28 #include <video/of_videomode.h>
29 #include <video/videomode.h>
31 #include <drm/bridge/analogix_dp.h>
33 #include "rockchip_drm_drv.h"
34 #include "rockchip_drm_vop.h"
36 #define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm)
38 /* dp grf register offset */
39 #define GRF_SOC_CON6 0x025c
40 #define GRF_EDP_LCD_SEL_MASK BIT(5)
41 #define GRF_EDP_SEL_VOP_LIT BIT(5)
42 #define GRF_EDP_SEL_VOP_BIG 0
44 struct rockchip_dp_device
{
45 struct drm_device
*drm_dev
;
47 struct drm_encoder encoder
;
48 struct drm_display_mode mode
;
52 struct reset_control
*rst
;
54 struct analogix_dp_plat_data plat_data
;
57 static int rockchip_dp_pre_init(struct rockchip_dp_device
*dp
)
59 reset_control_assert(dp
->rst
);
61 reset_control_deassert(dp
->rst
);
66 static int rockchip_dp_poweron(struct analogix_dp_plat_data
*plat_data
)
68 struct rockchip_dp_device
*dp
= to_dp(plat_data
);
71 ret
= clk_prepare_enable(dp
->pclk
);
73 dev_err(dp
->dev
, "failed to enable pclk %d\n", ret
);
77 ret
= rockchip_dp_pre_init(dp
);
79 dev_err(dp
->dev
, "failed to dp pre init %d\n", ret
);
86 static int rockchip_dp_powerdown(struct analogix_dp_plat_data
*plat_data
)
88 struct rockchip_dp_device
*dp
= to_dp(plat_data
);
90 clk_disable_unprepare(dp
->pclk
);
96 rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder
*encoder
,
97 const struct drm_display_mode
*mode
,
98 struct drm_display_mode
*adjusted_mode
)
104 static void rockchip_dp_drm_encoder_mode_set(struct drm_encoder
*encoder
,
105 struct drm_display_mode
*mode
,
106 struct drm_display_mode
*adjusted
)
111 static void rockchip_dp_drm_encoder_enable(struct drm_encoder
*encoder
)
113 struct rockchip_dp_device
*dp
= to_dp(encoder
);
117 ret
= drm_of_encoder_active_endpoint_id(dp
->dev
->of_node
, encoder
);
122 val
= GRF_EDP_SEL_VOP_LIT
| (GRF_EDP_LCD_SEL_MASK
<< 16);
124 val
= GRF_EDP_SEL_VOP_BIG
| (GRF_EDP_LCD_SEL_MASK
<< 16);
126 dev_dbg(dp
->dev
, "vop %s output to dp\n", (ret
) ? "LIT" : "BIG");
128 ret
= regmap_write(dp
->grf
, GRF_SOC_CON6
, val
);
130 dev_err(dp
->dev
, "Could not write to GRF: %d\n", ret
);
135 static void rockchip_dp_drm_encoder_nop(struct drm_encoder
*encoder
)
141 rockchip_dp_drm_encoder_atomic_check(struct drm_encoder
*encoder
,
142 struct drm_crtc_state
*crtc_state
,
143 struct drm_connector_state
*conn_state
)
145 struct rockchip_crtc_state
*s
= to_rockchip_crtc_state(crtc_state
);
148 * FIXME(Yakir): driver should configure the CRTC output video
149 * mode with the display information which indicated the monitor
150 * support colorimetry.
152 * But don't know why the CRTC driver seems could only output the
153 * RGBaaa rightly. For example, if connect the "innolux,n116bge"
154 * eDP screen, EDID would indicated that screen only accepted the
155 * 6bpc mode. But if I configure CRTC to RGB666 output, then eDP
156 * screen would show a blue picture (RGB888 show a green picture).
157 * But if I configure CTRC to RGBaaa, and eDP driver still keep
158 * RGB666 input video mode, then screen would works prefect.
160 s
->output_mode
= ROCKCHIP_OUT_MODE_AAAA
;
161 s
->output_type
= DRM_MODE_CONNECTOR_eDP
;
166 static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs
= {
167 .mode_fixup
= rockchip_dp_drm_encoder_mode_fixup
,
168 .mode_set
= rockchip_dp_drm_encoder_mode_set
,
169 .enable
= rockchip_dp_drm_encoder_enable
,
170 .disable
= rockchip_dp_drm_encoder_nop
,
171 .atomic_check
= rockchip_dp_drm_encoder_atomic_check
,
174 static void rockchip_dp_drm_encoder_destroy(struct drm_encoder
*encoder
)
176 drm_encoder_cleanup(encoder
);
179 static struct drm_encoder_funcs rockchip_dp_encoder_funcs
= {
180 .destroy
= rockchip_dp_drm_encoder_destroy
,
183 static int rockchip_dp_init(struct rockchip_dp_device
*dp
)
185 struct device
*dev
= dp
->dev
;
186 struct device_node
*np
= dev
->of_node
;
189 dp
->grf
= syscon_regmap_lookup_by_phandle(np
, "rockchip,grf");
190 if (IS_ERR(dp
->grf
)) {
191 dev_err(dev
, "failed to get rockchip,grf property\n");
192 return PTR_ERR(dp
->grf
);
195 dp
->pclk
= devm_clk_get(dev
, "pclk");
196 if (IS_ERR(dp
->pclk
)) {
197 dev_err(dev
, "failed to get pclk property\n");
198 return PTR_ERR(dp
->pclk
);
201 dp
->rst
= devm_reset_control_get(dev
, "dp");
202 if (IS_ERR(dp
->rst
)) {
203 dev_err(dev
, "failed to get dp reset control\n");
204 return PTR_ERR(dp
->rst
);
207 ret
= clk_prepare_enable(dp
->pclk
);
209 dev_err(dp
->dev
, "failed to enable pclk %d\n", ret
);
213 ret
= rockchip_dp_pre_init(dp
);
215 dev_err(dp
->dev
, "failed to pre init %d\n", ret
);
222 static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device
*dp
)
224 struct drm_encoder
*encoder
= &dp
->encoder
;
225 struct drm_device
*drm_dev
= dp
->drm_dev
;
226 struct device
*dev
= dp
->dev
;
229 encoder
->possible_crtcs
= drm_of_find_possible_crtcs(drm_dev
,
231 DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder
->possible_crtcs
);
233 ret
= drm_encoder_init(drm_dev
, encoder
, &rockchip_dp_encoder_funcs
,
234 DRM_MODE_ENCODER_TMDS
, NULL
);
236 DRM_ERROR("failed to initialize encoder with drm\n");
240 drm_encoder_helper_add(encoder
, &rockchip_dp_encoder_helper_funcs
);
245 static int rockchip_dp_bind(struct device
*dev
, struct device
*master
,
248 struct rockchip_dp_device
*dp
= dev_get_drvdata(dev
);
249 struct drm_device
*drm_dev
= data
;
253 * Just like the probe function said, we don't need the
254 * device drvrate anymore, we should leave the charge to
255 * analogix dp driver, set the device drvdata to NULL.
257 dev_set_drvdata(dev
, NULL
);
259 ret
= rockchip_dp_init(dp
);
263 dp
->drm_dev
= drm_dev
;
265 ret
= rockchip_dp_drm_create_encoder(dp
);
267 DRM_ERROR("failed to create drm encoder\n");
271 dp
->plat_data
.encoder
= &dp
->encoder
;
273 dp
->plat_data
.dev_type
= RK3288_DP
;
274 dp
->plat_data
.power_on
= rockchip_dp_poweron
;
275 dp
->plat_data
.power_off
= rockchip_dp_powerdown
;
277 return analogix_dp_bind(dev
, dp
->drm_dev
, &dp
->plat_data
);
280 static void rockchip_dp_unbind(struct device
*dev
, struct device
*master
,
283 return analogix_dp_unbind(dev
, master
, data
);
286 static const struct component_ops rockchip_dp_component_ops
= {
287 .bind
= rockchip_dp_bind
,
288 .unbind
= rockchip_dp_unbind
,
291 static int rockchip_dp_probe(struct platform_device
*pdev
)
293 struct device
*dev
= &pdev
->dev
;
294 struct device_node
*panel_node
, *port
, *endpoint
;
295 struct rockchip_dp_device
*dp
;
296 struct drm_panel
*panel
;
298 port
= of_graph_get_port_by_id(dev
->of_node
, 1);
300 dev_err(dev
, "can't find output port\n");
304 endpoint
= of_get_child_by_name(port
, "endpoint");
307 dev_err(dev
, "no output endpoint found\n");
311 panel_node
= of_graph_get_remote_port_parent(endpoint
);
312 of_node_put(endpoint
);
314 dev_err(dev
, "no output node found\n");
318 panel
= of_drm_find_panel(panel_node
);
320 DRM_ERROR("failed to find panel\n");
321 of_node_put(panel_node
);
322 return -EPROBE_DEFER
;
325 of_node_put(panel_node
);
327 dp
= devm_kzalloc(dev
, sizeof(*dp
), GFP_KERNEL
);
333 dp
->plat_data
.panel
= panel
;
336 * We just use the drvdata until driver run into component
337 * add function, and then we would set drvdata to null, so
338 * that analogix dp driver could take charge of the drvdata.
340 platform_set_drvdata(pdev
, dp
);
342 return component_add(dev
, &rockchip_dp_component_ops
);
345 static int rockchip_dp_remove(struct platform_device
*pdev
)
347 component_del(&pdev
->dev
, &rockchip_dp_component_ops
);
352 #ifdef CONFIG_PM_SLEEP
353 static int rockchip_dp_suspend(struct device
*dev
)
355 return analogix_dp_suspend(dev
);
358 static int rockchip_dp_resume(struct device
*dev
)
360 return analogix_dp_resume(dev
);
364 static const struct dev_pm_ops rockchip_dp_pm_ops
= {
365 SET_SYSTEM_SLEEP_PM_OPS(rockchip_dp_suspend
, rockchip_dp_resume
)
368 static const struct of_device_id rockchip_dp_dt_ids
[] = {
369 {.compatible
= "rockchip,rk3288-dp",},
372 MODULE_DEVICE_TABLE(of
, rockchip_dp_dt_ids
);
374 static struct platform_driver rockchip_dp_driver
= {
375 .probe
= rockchip_dp_probe
,
376 .remove
= rockchip_dp_remove
,
378 .name
= "rockchip-dp",
379 .owner
= THIS_MODULE
,
380 .pm
= &rockchip_dp_pm_ops
,
381 .of_match_table
= of_match_ptr(rockchip_dp_dt_ids
),
385 module_platform_driver(rockchip_dp_driver
);
387 MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
388 MODULE_AUTHOR("Jeff chen <jeff.chen@rock-chips.com>");
389 MODULE_DESCRIPTION("Rockchip Specific Analogix-DP Driver Extension");
390 MODULE_LICENSE("GPL v2");