2 * Copyright 2016 Rockchip Inc.
4 * SPDX-License-Identifier: GPL-2.0+
16 #include <asm/arch/clock.h>
17 #include <asm/arch/lvds_rk3288.h>
18 #include <asm/arch/grf_rk3288.h>
19 #include <dt-bindings/clock/rk3288-cru.h>
20 #include <dt-bindings/video/rk3288.h>
22 DECLARE_GLOBAL_DATA_PTR
;
25 * struct rk_lvds_priv - private rockchip lvds display driver info
27 * @reg: LVDS register address
29 * @panel: Panel device that is used in driver
31 * @output: Output mode, decided single or double channel,
33 * @format: Data format that RGB data will packing as
37 struct rk3288_grf
*grf
;
38 struct udevice
*panel
;
44 static inline void lvds_writel(struct rk_lvds_priv
*lvds
, u32 offset
, u32 val
)
46 writel(val
, lvds
->regs
+ offset
);
48 writel(val
, lvds
->regs
+ offset
+ 0x100);
51 int rk_lvds_enable(struct udevice
*dev
, int panel_bpp
,
52 const struct display_timing
*edid
)
54 struct rk_lvds_priv
*priv
= dev_get_priv(dev
);
55 struct display_plat
*uc_plat
= dev_get_uclass_platdata(dev
);
59 ret
= panel_enable_backlight(priv
->panel
);
61 debug("%s: backlight error: %d\n", __func__
, ret
);
65 /* Select the video source */
66 if (uc_plat
->source_id
)
67 val
= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT
|
68 (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT
<< 16);
70 val
= RK3288_LVDS_SOC_CON6_SEL_VOP_LIT
<< 16;
71 rk_setreg(&priv
->grf
->soc_con6
, val
);
73 /* Select data transfer format */
75 if (priv
->output
== LVDS_OUTPUT_DUAL
)
76 val
|= LVDS_DUAL
| LVDS_CH0_EN
| LVDS_CH1_EN
;
77 else if (priv
->output
== LVDS_OUTPUT_SINGLE
)
79 else if (priv
->output
== LVDS_OUTPUT_RGB
)
80 val
|= LVDS_TTL_EN
| LVDS_CH0_EN
| LVDS_CH1_EN
;
81 val
|= (0xffff << 16);
82 rk_setreg(&priv
->grf
->soc_con7
, val
);
85 if (priv
->output
== LVDS_OUTPUT_RGB
) {
86 lvds_writel(priv
, RK3288_LVDS_CH0_REG0
,
87 RK3288_LVDS_CH0_REG0_TTL_EN
|
88 RK3288_LVDS_CH0_REG0_LANECK_EN
|
89 RK3288_LVDS_CH0_REG0_LANE4_EN
|
90 RK3288_LVDS_CH0_REG0_LANE3_EN
|
91 RK3288_LVDS_CH0_REG0_LANE2_EN
|
92 RK3288_LVDS_CH0_REG0_LANE1_EN
|
93 RK3288_LVDS_CH0_REG0_LANE0_EN
);
94 lvds_writel(priv
, RK3288_LVDS_CH0_REG2
,
95 RK3288_LVDS_PLL_FBDIV_REG2(0x46));
97 lvds_writel(priv
, RK3288_LVDS_CH0_REG3
,
98 RK3288_LVDS_PLL_FBDIV_REG3(0x46));
99 lvds_writel(priv
, RK3288_LVDS_CH0_REG4
,
100 RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE
|
101 RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE
|
102 RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE
|
103 RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE
|
104 RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE
|
105 RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE
);
106 lvds_writel(priv
, RK3288_LVDS_CH0_REG5
,
107 RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA
|
108 RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA
|
109 RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA
|
110 RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA
|
111 RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA
|
112 RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA
);
113 lvds_writel(priv
, RK3288_LVDS_CH0_REGD
,
114 RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
115 lvds_writel(priv
, RK3288_LVDS_CH0_REG20
,
116 RK3288_LVDS_CH0_REG20_LSB
);
118 lvds_writel(priv
, RK3288_LVDS_CH0_REG0
,
119 RK3288_LVDS_CH0_REG0_LVDS_EN
|
120 RK3288_LVDS_CH0_REG0_LANECK_EN
|
121 RK3288_LVDS_CH0_REG0_LANE4_EN
|
122 RK3288_LVDS_CH0_REG0_LANE3_EN
|
123 RK3288_LVDS_CH0_REG0_LANE2_EN
|
124 RK3288_LVDS_CH0_REG0_LANE1_EN
|
125 RK3288_LVDS_CH0_REG0_LANE0_EN
);
126 lvds_writel(priv
, RK3288_LVDS_CH0_REG1
,
127 RK3288_LVDS_CH0_REG1_LANECK_BIAS
|
128 RK3288_LVDS_CH0_REG1_LANE4_BIAS
|
129 RK3288_LVDS_CH0_REG1_LANE3_BIAS
|
130 RK3288_LVDS_CH0_REG1_LANE2_BIAS
|
131 RK3288_LVDS_CH0_REG1_LANE1_BIAS
|
132 RK3288_LVDS_CH0_REG1_LANE0_BIAS
);
133 lvds_writel(priv
, RK3288_LVDS_CH0_REG2
,
134 RK3288_LVDS_CH0_REG2_RESERVE_ON
|
135 RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE
|
136 RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE
|
137 RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE
|
138 RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE
|
139 RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE
|
140 RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE
|
141 RK3288_LVDS_PLL_FBDIV_REG2(0x46));
142 lvds_writel(priv
, RK3288_LVDS_CH0_REG3
,
143 RK3288_LVDS_PLL_FBDIV_REG3(0x46));
144 lvds_writel(priv
, RK3288_LVDS_CH0_REG4
, 0x00);
145 lvds_writel(priv
, RK3288_LVDS_CH0_REG5
, 0x00);
146 lvds_writel(priv
, RK3288_LVDS_CH0_REGD
,
147 RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
148 lvds_writel(priv
, RK3288_LVDS_CH0_REG20
,
149 RK3288_LVDS_CH0_REG20_LSB
);
153 writel(RK3288_LVDS_CFG_REGC_PLL_ENABLE
,
154 priv
->regs
+ RK3288_LVDS_CFG_REGC
);
156 writel(RK3288_LVDS_CFG_REG21_TX_ENABLE
,
157 priv
->regs
+ RK3288_LVDS_CFG_REG21
);
162 int rk_lvds_read_timing(struct udevice
*dev
, struct display_timing
*timing
)
164 if (fdtdec_decode_display_timing
165 (gd
->fdt_blob
, dev_of_offset(dev
), 0, timing
)) {
166 debug("%s: Failed to decode display timing\n", __func__
);
173 static int rk_lvds_ofdata_to_platdata(struct udevice
*dev
)
175 struct rk_lvds_priv
*priv
= dev_get_priv(dev
);
176 const void *blob
= gd
->fdt_blob
;
177 int node
= dev_of_offset(dev
);
179 priv
->regs
= (void *)dev_get_addr(dev
);
180 priv
->grf
= syscon_get_first_range(ROCKCHIP_SYSCON_GRF
);
182 ret
= fdtdec_get_int(blob
, node
, "rockchip,output", -1);
185 debug("LVDS output : %d\n", ret
);
187 /* default set it as output rgb */
188 priv
->output
= LVDS_OUTPUT_RGB
;
191 ret
= fdtdec_get_int(blob
, node
, "rockchip,data-mapping", -1);
194 debug("LVDS data-mapping : %d\n", ret
);
196 /* default set it as format jeida */
197 priv
->format
= LVDS_FORMAT_JEIDA
;
200 ret
= fdtdec_get_int(blob
, node
, "rockchip,data-width", -1);
202 debug("LVDS data-width : %d\n", ret
);
204 priv
->format
|= LVDS_24BIT
;
205 } else if (ret
== 18) {
206 priv
->format
|= LVDS_18BIT
;
208 debug("rockchip-lvds unsupport data-width[%d]\n", ret
);
213 priv
->format
|= LVDS_24BIT
;
219 int rk_lvds_probe(struct udevice
*dev
)
221 struct rk_lvds_priv
*priv
= dev_get_priv(dev
);
224 ret
= uclass_get_device_by_phandle(UCLASS_PANEL
, dev
, "rockchip,panel",
227 debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__
,
235 static const struct dm_display_ops lvds_rockchip_ops
= {
236 .read_timing
= rk_lvds_read_timing
,
237 .enable
= rk_lvds_enable
,
240 static const struct udevice_id rockchip_lvds_ids
[] = {
241 {.compatible
= "rockchip,rk3288-lvds"},
245 U_BOOT_DRIVER(lvds_rockchip
) = {
246 .name
= "lvds_rockchip",
247 .id
= UCLASS_DISPLAY
,
248 .of_match
= rockchip_lvds_ids
,
249 .ops
= &lvds_rockchip_ops
,
250 .ofdata_to_platdata
= rk_lvds_ofdata_to_platdata
,
251 .probe
= rk_lvds_probe
,
252 .priv_auto_alloc_size
= sizeof(struct rk_lvds_priv
),