2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4 * Mark Yao <mark.yao@rock-chips.com>
5 * Sandy Huang <hjc@rock-chips.com>
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <drm/drm_atomic_helper.h>
19 #include <drm/drm_crtc_helper.h>
20 #include <drm/drm_dp_helper.h>
21 #include <drm/drm_panel.h>
22 #include <drm/drm_of.h>
24 #include <linux/component.h>
25 #include <linux/clk.h>
26 #include <linux/mfd/syscon.h>
27 #include <linux/of_graph.h>
28 #include <linux/pinctrl/devinfo.h>
29 #include <linux/pm_runtime.h>
30 #include <linux/regmap.h>
31 #include <linux/reset.h>
33 #include "rockchip_drm_drv.h"
34 #include "rockchip_drm_vop.h"
35 #include "rockchip_lvds.h"
37 #define DISPLAY_OUTPUT_RGB 0
38 #define DISPLAY_OUTPUT_LVDS 1
39 #define DISPLAY_OUTPUT_DUAL_LVDS 2
41 #define connector_to_lvds(c) \
42 container_of(c, struct rockchip_lvds, connector)
44 #define encoder_to_lvds(c) \
45 container_of(c, struct rockchip_lvds, encoder)
48 * rockchip_lvds_soc_data - rockchip lvds Soc private data
49 * @ch1_offset: lvds channel 1 registe offset
50 * grf_soc_con6: general registe offset for LVDS contrl
51 * grf_soc_con7: general registe offset for LVDS contrl
52 * has_vop_sel: to indicate whether need to choose from different VOP.
54 struct rockchip_lvds_soc_data
{
61 struct rockchip_lvds
{
66 const struct rockchip_lvds_soc_data
*soc_data
;
67 int output
; /* rgb lvds or dual lvds output */
68 int format
; /* vesa or jeida format */
69 struct drm_device
*drm_dev
;
70 struct drm_panel
*panel
;
71 struct drm_bridge
*bridge
;
72 struct drm_connector connector
;
73 struct drm_encoder encoder
;
74 struct dev_pin_info
*pins
;
77 static inline void lvds_writel(struct rockchip_lvds
*lvds
, u32 offset
, u32 val
)
79 writel_relaxed(val
, lvds
->regs
+ offset
);
80 if (lvds
->output
== DISPLAY_OUTPUT_LVDS
)
82 writel_relaxed(val
, lvds
->regs
+ offset
+ lvds
->soc_data
->ch1_offset
);
85 static inline int lvds_name_to_format(const char *s
)
87 if (strncmp(s
, "jeida-18", 8) == 0)
89 else if (strncmp(s
, "jeida-24", 8) == 0)
91 else if (strncmp(s
, "vesa-24", 7) == 0)
97 static inline int lvds_name_to_output(const char *s
)
99 if (strncmp(s
, "rgb", 3) == 0)
100 return DISPLAY_OUTPUT_RGB
;
101 else if (strncmp(s
, "lvds", 4) == 0)
102 return DISPLAY_OUTPUT_LVDS
;
103 else if (strncmp(s
, "duallvds", 8) == 0)
104 return DISPLAY_OUTPUT_DUAL_LVDS
;
109 static int rockchip_lvds_poweron(struct rockchip_lvds
*lvds
)
114 ret
= clk_enable(lvds
->pclk
);
116 DRM_DEV_ERROR(lvds
->dev
, "failed to enable lvds pclk %d\n", ret
);
119 ret
= pm_runtime_get_sync(lvds
->dev
);
121 DRM_DEV_ERROR(lvds
->dev
, "failed to get pm runtime: %d\n", ret
);
122 clk_disable(lvds
->pclk
);
125 val
= RK3288_LVDS_CH0_REG0_LANE4_EN
| RK3288_LVDS_CH0_REG0_LANE3_EN
|
126 RK3288_LVDS_CH0_REG0_LANE2_EN
| RK3288_LVDS_CH0_REG0_LANE1_EN
|
127 RK3288_LVDS_CH0_REG0_LANE0_EN
;
128 if (lvds
->output
== DISPLAY_OUTPUT_RGB
) {
129 val
|= RK3288_LVDS_CH0_REG0_TTL_EN
|
130 RK3288_LVDS_CH0_REG0_LANECK_EN
;
131 lvds_writel(lvds
, RK3288_LVDS_CH0_REG0
, val
);
132 lvds_writel(lvds
, RK3288_LVDS_CH0_REG2
,
133 RK3288_LVDS_PLL_FBDIV_REG2(0x46));
134 lvds_writel(lvds
, RK3288_LVDS_CH0_REG4
,
135 RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE
|
136 RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE
|
137 RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE
|
138 RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE
|
139 RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE
|
140 RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE
);
141 lvds_writel(lvds
, RK3288_LVDS_CH0_REG5
,
142 RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA
|
143 RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA
|
144 RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA
|
145 RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA
|
146 RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA
|
147 RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA
);
149 val
|= RK3288_LVDS_CH0_REG0_LVDS_EN
|
150 RK3288_LVDS_CH0_REG0_LANECK_EN
;
151 lvds_writel(lvds
, RK3288_LVDS_CH0_REG0
, val
);
152 lvds_writel(lvds
, RK3288_LVDS_CH0_REG1
,
153 RK3288_LVDS_CH0_REG1_LANECK_BIAS
|
154 RK3288_LVDS_CH0_REG1_LANE4_BIAS
|
155 RK3288_LVDS_CH0_REG1_LANE3_BIAS
|
156 RK3288_LVDS_CH0_REG1_LANE2_BIAS
|
157 RK3288_LVDS_CH0_REG1_LANE1_BIAS
|
158 RK3288_LVDS_CH0_REG1_LANE0_BIAS
);
159 lvds_writel(lvds
, RK3288_LVDS_CH0_REG2
,
160 RK3288_LVDS_CH0_REG2_RESERVE_ON
|
161 RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE
|
162 RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE
|
163 RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE
|
164 RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE
|
165 RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE
|
166 RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE
|
167 RK3288_LVDS_PLL_FBDIV_REG2(0x46));
168 lvds_writel(lvds
, RK3288_LVDS_CH0_REG4
, 0x00);
169 lvds_writel(lvds
, RK3288_LVDS_CH0_REG5
, 0x00);
171 lvds_writel(lvds
, RK3288_LVDS_CH0_REG3
, RK3288_LVDS_PLL_FBDIV_REG3(0x46));
172 lvds_writel(lvds
, RK3288_LVDS_CH0_REGD
, RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
173 lvds_writel(lvds
, RK3288_LVDS_CH0_REG20
, RK3288_LVDS_CH0_REG20_LSB
);
175 lvds_writel(lvds
, RK3288_LVDS_CFG_REGC
, RK3288_LVDS_CFG_REGC_PLL_ENABLE
);
176 lvds_writel(lvds
, RK3288_LVDS_CFG_REG21
, RK3288_LVDS_CFG_REG21_TX_ENABLE
);
181 static void rockchip_lvds_poweroff(struct rockchip_lvds
*lvds
)
186 lvds_writel(lvds
, RK3288_LVDS_CFG_REG21
, RK3288_LVDS_CFG_REG21_TX_ENABLE
);
187 lvds_writel(lvds
, RK3288_LVDS_CFG_REGC
, RK3288_LVDS_CFG_REGC_PLL_ENABLE
);
188 val
= LVDS_DUAL
| LVDS_TTL_EN
| LVDS_CH0_EN
| LVDS_CH1_EN
| LVDS_PWRDN
;
190 ret
= regmap_write(lvds
->grf
, lvds
->soc_data
->grf_soc_con7
, val
);
192 DRM_DEV_ERROR(lvds
->dev
, "Could not write to GRF: %d\n", ret
);
194 pm_runtime_put(lvds
->dev
);
195 clk_disable(lvds
->pclk
);
198 static const struct drm_connector_funcs rockchip_lvds_connector_funcs
= {
199 .fill_modes
= drm_helper_probe_single_connector_modes
,
200 .destroy
= drm_connector_cleanup
,
201 .reset
= drm_atomic_helper_connector_reset
,
202 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
203 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
206 static int rockchip_lvds_connector_get_modes(struct drm_connector
*connector
)
208 struct rockchip_lvds
*lvds
= connector_to_lvds(connector
);
209 struct drm_panel
*panel
= lvds
->panel
;
211 return drm_panel_get_modes(panel
);
215 struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs
= {
216 .get_modes
= rockchip_lvds_connector_get_modes
,
219 static void rockchip_lvds_grf_config(struct drm_encoder
*encoder
,
220 struct drm_display_mode
*mode
)
222 struct rockchip_lvds
*lvds
= encoder_to_lvds(encoder
);
223 u8 pin_hsync
= (mode
->flags
& DRM_MODE_FLAG_PHSYNC
) ? 1 : 0;
224 u8 pin_dclk
= (mode
->flags
& DRM_MODE_FLAG_PCSYNC
) ? 1 : 0;
228 /* iomux to LCD data/sync mode */
229 if (lvds
->output
== DISPLAY_OUTPUT_RGB
)
230 if (lvds
->pins
&& !IS_ERR(lvds
->pins
->default_state
))
231 pinctrl_select_state(lvds
->pins
->p
,
232 lvds
->pins
->default_state
);
233 val
= lvds
->format
| LVDS_CH0_EN
;
234 if (lvds
->output
== DISPLAY_OUTPUT_RGB
)
235 val
|= LVDS_TTL_EN
| LVDS_CH1_EN
;
236 else if (lvds
->output
== DISPLAY_OUTPUT_DUAL_LVDS
)
237 val
|= LVDS_DUAL
| LVDS_CH1_EN
;
239 if ((mode
->htotal
- mode
->hsync_start
) & 0x01)
240 val
|= LVDS_START_PHASE_RST_1
;
242 val
|= (pin_dclk
<< 8) | (pin_hsync
<< 9);
243 val
|= (0xffff << 16);
244 ret
= regmap_write(lvds
->grf
, lvds
->soc_data
->grf_soc_con7
, val
);
246 DRM_DEV_ERROR(lvds
->dev
, "Could not write to GRF: %d\n", ret
);
251 static int rockchip_lvds_set_vop_source(struct rockchip_lvds
*lvds
,
252 struct drm_encoder
*encoder
)
257 if (!lvds
->soc_data
->has_vop_sel
)
260 ret
= drm_of_encoder_active_endpoint_id(lvds
->dev
->of_node
, encoder
);
264 val
= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT
<< 16;
266 val
|= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT
;
268 ret
= regmap_write(lvds
->grf
, lvds
->soc_data
->grf_soc_con6
, val
);
276 rockchip_lvds_encoder_atomic_check(struct drm_encoder
*encoder
,
277 struct drm_crtc_state
*crtc_state
,
278 struct drm_connector_state
*conn_state
)
280 struct rockchip_crtc_state
*s
= to_rockchip_crtc_state(crtc_state
);
282 s
->output_mode
= ROCKCHIP_OUT_MODE_P888
;
283 s
->output_type
= DRM_MODE_CONNECTOR_LVDS
;
288 static void rockchip_lvds_encoder_enable(struct drm_encoder
*encoder
)
290 struct rockchip_lvds
*lvds
= encoder_to_lvds(encoder
);
291 struct drm_display_mode
*mode
= &encoder
->crtc
->state
->adjusted_mode
;
294 drm_panel_prepare(lvds
->panel
);
295 ret
= rockchip_lvds_poweron(lvds
);
297 DRM_DEV_ERROR(lvds
->dev
, "failed to power on lvds: %d\n", ret
);
298 drm_panel_unprepare(lvds
->panel
);
300 rockchip_lvds_grf_config(encoder
, mode
);
301 rockchip_lvds_set_vop_source(lvds
, encoder
);
302 drm_panel_enable(lvds
->panel
);
305 static void rockchip_lvds_encoder_disable(struct drm_encoder
*encoder
)
307 struct rockchip_lvds
*lvds
= encoder_to_lvds(encoder
);
309 drm_panel_disable(lvds
->panel
);
310 rockchip_lvds_poweroff(lvds
);
311 drm_panel_unprepare(lvds
->panel
);
315 struct drm_encoder_helper_funcs rockchip_lvds_encoder_helper_funcs
= {
316 .enable
= rockchip_lvds_encoder_enable
,
317 .disable
= rockchip_lvds_encoder_disable
,
318 .atomic_check
= rockchip_lvds_encoder_atomic_check
,
321 static const struct drm_encoder_funcs rockchip_lvds_encoder_funcs
= {
322 .destroy
= drm_encoder_cleanup
,
325 static const struct rockchip_lvds_soc_data rk3288_lvds_data
= {
327 .grf_soc_con6
= 0x025c,
328 .grf_soc_con7
= 0x0260,
332 static const struct of_device_id rockchip_lvds_dt_ids
[] = {
334 .compatible
= "rockchip,rk3288-lvds",
335 .data
= &rk3288_lvds_data
339 MODULE_DEVICE_TABLE(of
, rockchip_lvds_dt_ids
);
341 static int rockchip_lvds_bind(struct device
*dev
, struct device
*master
,
344 struct rockchip_lvds
*lvds
= dev_get_drvdata(dev
);
345 struct drm_device
*drm_dev
= data
;
346 struct drm_encoder
*encoder
;
347 struct drm_connector
*connector
;
348 struct device_node
*remote
= NULL
;
349 struct device_node
*port
, *endpoint
;
350 int ret
= 0, child_count
= 0;
354 lvds
->drm_dev
= drm_dev
;
355 port
= of_graph_get_port_by_id(dev
->of_node
, 1);
358 "can't found port point, please init lvds panel port!\n");
361 for_each_child_of_node(port
, endpoint
) {
363 of_property_read_u32(endpoint
, "reg", &endpoint_id
);
364 ret
= drm_of_find_panel_or_bridge(dev
->of_node
, 1, endpoint_id
,
365 &lvds
->panel
, &lvds
->bridge
);
367 of_node_put(endpoint
);
372 DRM_DEV_ERROR(dev
, "lvds port does not have any children\n");
376 DRM_DEV_ERROR(dev
, "failed to find panel and bridge node\n");
381 remote
= lvds
->panel
->dev
->of_node
;
383 remote
= lvds
->bridge
->of_node
;
384 if (of_property_read_string(dev
->of_node
, "rockchip,output", &name
))
385 /* default set it as output rgb */
386 lvds
->output
= DISPLAY_OUTPUT_RGB
;
388 lvds
->output
= lvds_name_to_output(name
);
390 if (lvds
->output
< 0) {
391 DRM_DEV_ERROR(dev
, "invalid output type [%s]\n", name
);
396 if (of_property_read_string(remote
, "data-mapping", &name
))
397 /* default set it as format vesa 18 */
398 lvds
->format
= LVDS_VESA_18
;
400 lvds
->format
= lvds_name_to_format(name
);
402 if (lvds
->format
< 0) {
403 DRM_DEV_ERROR(dev
, "invalid data-mapping format [%s]\n", name
);
408 encoder
= &lvds
->encoder
;
409 encoder
->possible_crtcs
= drm_of_find_possible_crtcs(drm_dev
,
412 ret
= drm_encoder_init(drm_dev
, encoder
, &rockchip_lvds_encoder_funcs
,
413 DRM_MODE_ENCODER_LVDS
, NULL
);
415 DRM_DEV_ERROR(drm_dev
->dev
,
416 "failed to initialize encoder: %d\n", ret
);
420 drm_encoder_helper_add(encoder
, &rockchip_lvds_encoder_helper_funcs
);
423 connector
= &lvds
->connector
;
424 connector
->dpms
= DRM_MODE_DPMS_OFF
;
425 ret
= drm_connector_init(drm_dev
, connector
,
426 &rockchip_lvds_connector_funcs
,
427 DRM_MODE_CONNECTOR_LVDS
);
429 DRM_DEV_ERROR(drm_dev
->dev
,
430 "failed to initialize connector: %d\n", ret
);
431 goto err_free_encoder
;
434 drm_connector_helper_add(connector
,
435 &rockchip_lvds_connector_helper_funcs
);
437 ret
= drm_connector_attach_encoder(connector
, encoder
);
439 DRM_DEV_ERROR(drm_dev
->dev
,
440 "failed to attach encoder: %d\n", ret
);
441 goto err_free_connector
;
444 ret
= drm_panel_attach(lvds
->panel
, connector
);
446 DRM_DEV_ERROR(drm_dev
->dev
,
447 "failed to attach panel: %d\n", ret
);
448 goto err_free_connector
;
451 ret
= drm_bridge_attach(encoder
, lvds
->bridge
, NULL
);
453 DRM_DEV_ERROR(drm_dev
->dev
,
454 "failed to attach bridge: %d\n", ret
);
455 goto err_free_encoder
;
459 pm_runtime_enable(dev
);
466 drm_connector_cleanup(connector
);
468 drm_encoder_cleanup(encoder
);
477 static void rockchip_lvds_unbind(struct device
*dev
, struct device
*master
,
480 struct rockchip_lvds
*lvds
= dev_get_drvdata(dev
);
482 rockchip_lvds_encoder_disable(&lvds
->encoder
);
484 drm_panel_detach(lvds
->panel
);
485 pm_runtime_disable(dev
);
486 drm_connector_cleanup(&lvds
->connector
);
487 drm_encoder_cleanup(&lvds
->encoder
);
490 static const struct component_ops rockchip_lvds_component_ops
= {
491 .bind
= rockchip_lvds_bind
,
492 .unbind
= rockchip_lvds_unbind
,
495 static int rockchip_lvds_probe(struct platform_device
*pdev
)
497 struct device
*dev
= &pdev
->dev
;
498 struct rockchip_lvds
*lvds
;
499 const struct of_device_id
*match
;
500 struct resource
*res
;
506 lvds
= devm_kzalloc(&pdev
->dev
, sizeof(*lvds
), GFP_KERNEL
);
511 match
= of_match_node(rockchip_lvds_dt_ids
, dev
->of_node
);
514 lvds
->soc_data
= match
->data
;
516 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
517 lvds
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
518 if (IS_ERR(lvds
->regs
))
519 return PTR_ERR(lvds
->regs
);
521 lvds
->pclk
= devm_clk_get(&pdev
->dev
, "pclk_lvds");
522 if (IS_ERR(lvds
->pclk
)) {
523 DRM_DEV_ERROR(dev
, "could not get pclk_lvds\n");
524 return PTR_ERR(lvds
->pclk
);
527 lvds
->pins
= devm_kzalloc(lvds
->dev
, sizeof(*lvds
->pins
),
532 lvds
->pins
->p
= devm_pinctrl_get(lvds
->dev
);
533 if (IS_ERR(lvds
->pins
->p
)) {
534 DRM_DEV_ERROR(dev
, "no pinctrl handle\n");
535 devm_kfree(lvds
->dev
, lvds
->pins
);
538 lvds
->pins
->default_state
=
539 pinctrl_lookup_state(lvds
->pins
->p
, "lcdc");
540 if (IS_ERR(lvds
->pins
->default_state
)) {
541 DRM_DEV_ERROR(dev
, "no default pinctrl state\n");
542 devm_kfree(lvds
->dev
, lvds
->pins
);
547 lvds
->grf
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
549 if (IS_ERR(lvds
->grf
)) {
550 DRM_DEV_ERROR(dev
, "missing rockchip,grf property\n");
551 return PTR_ERR(lvds
->grf
);
554 dev_set_drvdata(dev
, lvds
);
556 ret
= clk_prepare(lvds
->pclk
);
558 DRM_DEV_ERROR(dev
, "failed to prepare pclk_lvds\n");
561 ret
= component_add(&pdev
->dev
, &rockchip_lvds_component_ops
);
563 DRM_DEV_ERROR(dev
, "failed to add component\n");
564 clk_unprepare(lvds
->pclk
);
570 static int rockchip_lvds_remove(struct platform_device
*pdev
)
572 struct rockchip_lvds
*lvds
= dev_get_drvdata(&pdev
->dev
);
574 component_del(&pdev
->dev
, &rockchip_lvds_component_ops
);
575 clk_unprepare(lvds
->pclk
);
580 struct platform_driver rockchip_lvds_driver
= {
581 .probe
= rockchip_lvds_probe
,
582 .remove
= rockchip_lvds_remove
,
584 .name
= "rockchip-lvds",
585 .of_match_table
= of_match_ptr(rockchip_lvds_dt_ids
),