xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_rgb.c (revision 4e0fa9f6a6afd1c4db979a3d2e9f1e67d6e1f06f)
1 /*
2  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <dm/of_access.h>
9 #include <errno.h>
10 #include <syscon.h>
11 #include <regmap.h>
12 #include <dm/device.h>
13 #include <dm/read.h>
14 #include <dm/pinctrl.h>
15 #include <linux/media-bus-format.h>
16 
17 #include "rockchip_display.h"
18 #include "rockchip_crtc.h"
19 #include "rockchip_connector.h"
20 #include "rockchip_phy.h"
21 
22 #define HIWORD_UPDATE(v, h, l)		(((v) << (l)) | (GENMASK(h, l) << 16))
23 
24 #define PX30_GRF_PD_VO_CON1		0x0438
25 #define PX30_RGB_DATA_SYNC_BYPASS(v)	HIWORD_UPDATE(v, 3, 3)
26 #define PX30_RGB_VOP_SEL(v)		HIWORD_UPDATE(v, 2, 2)
27 
28 #define RK1808_GRF_PD_VO_CON1		0x0444
29 #define RK1808_RGB_DATA_SYNC_BYPASS(v)	HIWORD_UPDATE(v, 3, 3)
30 
31 #define RV1126_GRF_IOFUNC_CON3          0x1026c
32 #define RV1126_LCDC_IO_BYPASS(v)        HIWORD_UPDATE(v, 0, 0)
33 
34 #define RK3288_GRF_SOC_CON6		0x025c
35 #define RK3288_LVDS_LCDC_SEL(v)		HIWORD_UPDATE(v,  3,  3)
36 #define RK3288_GRF_SOC_CON7		0x0260
37 #define RK3288_LVDS_PWRDWN(v)		HIWORD_UPDATE(v, 15, 15)
38 #define RK3288_LVDS_CON_ENABLE_2(v)	HIWORD_UPDATE(v, 12, 12)
39 #define RK3288_LVDS_CON_ENABLE_1(v)	HIWORD_UPDATE(v, 11, 11)
40 #define RK3288_LVDS_CON_CLKINV(v)	HIWORD_UPDATE(v,  8,  8)
41 #define RK3288_LVDS_CON_TTL_EN(v)	HIWORD_UPDATE(v,  6,  6)
42 
43 #define RK3368_GRF_SOC_CON15		0x043c
44 #define RK3368_FORCE_JETAG(v)		HIWORD_UPDATE(v,  13,  13)
45 
46 #define RK3568_GRF_VO_CON1		0X0364
47 #define RK3568_RGB_DATA_BYPASS(v)	HIWORD_UPDATE(v, 6, 6)
48 
49 struct rockchip_rgb;
50 
51 struct rockchip_rgb_funcs {
52 	void (*prepare)(struct rockchip_rgb *rgb, int pipe);
53 	void (*unprepare)(struct rockchip_rgb *rgb);
54 };
55 
56 struct rockchip_rgb {
57 	int id;
58 	struct udevice *dev;
59 	struct regmap *grf;
60 	bool data_sync_bypass;
61 	struct rockchip_phy *phy;
62 	const struct rockchip_rgb_funcs *funcs;
63 };
64 
65 static inline struct rockchip_rgb *state_to_rgb(struct display_state *state)
66 {
67 	struct connector_state *conn_state = &state->conn_state;
68 
69 	return dev_get_priv(conn_state->dev);
70 }
71 
72 static int rockchip_rgb_connector_prepare(struct display_state *state)
73 {
74 	struct rockchip_rgb *rgb = state_to_rgb(state);
75 	struct crtc_state *crtc_state = &state->crtc_state;
76 	int pipe = crtc_state->crtc_id;
77 	int ret;
78 
79 	pinctrl_select_state(rgb->dev, "default");
80 
81 	if (rgb->funcs && rgb->funcs->prepare)
82 		rgb->funcs->prepare(rgb, pipe);
83 
84 	if (rgb->phy) {
85 		ret = rockchip_phy_set_mode(rgb->phy, PHY_MODE_VIDEO_TTL);
86 		if (ret) {
87 			dev_err(rgb->dev, "failed to set phy mode: %d\n", ret);
88 			return ret;
89 		}
90 
91 		rockchip_phy_power_on(rgb->phy);
92 	}
93 
94 	return 0;
95 }
96 
97 static void rockchip_rgb_connector_unprepare(struct display_state *state)
98 {
99 	struct rockchip_rgb *rgb = state_to_rgb(state);
100 
101 	if (rgb->phy)
102 		rockchip_phy_power_off(rgb->phy);
103 
104 	if (rgb->funcs && rgb->funcs->unprepare)
105 		rgb->funcs->unprepare(rgb);
106 
107 	pinctrl_select_state(rgb->dev, "sleep");
108 }
109 
110 static int rockchip_rgb_connector_pre_init(struct display_state *state)
111 {
112 	struct connector_state *conn_state = &state->conn_state;
113 
114 	conn_state->type = DRM_MODE_CONNECTOR_LVDS;
115 
116 	return 0;
117 }
118 
119 static int rockchip_rgb_connector_init(struct display_state *state)
120 {
121 	struct rockchip_rgb *rgb = state_to_rgb(state);
122 	struct connector_state *conn_state = &state->conn_state;
123 
124 	rgb->phy = conn_state->phy;
125 
126 	conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
127 	conn_state->disp_info  = rockchip_get_disp_info(conn_state->type, rgb->id);
128 
129 	switch (conn_state->bus_format) {
130 	case MEDIA_BUS_FMT_RGB666_1X18:
131 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P666;
132 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
133 		break;
134 	case MEDIA_BUS_FMT_RGB565_1X16:
135 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P565;
136 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
137 		break;
138 	case MEDIA_BUS_FMT_SRGB888_3X8:
139 	case MEDIA_BUS_FMT_SBGR888_3X8:
140 	case MEDIA_BUS_FMT_SRBG888_3X8:
141 		conn_state->output_mode = ROCKCHIP_OUT_MODE_S888;
142 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
143 		break;
144 	case MEDIA_BUS_FMT_SRGB888_DUMMY_4X8:
145 	case MEDIA_BUS_FMT_SBGR888_DUMMY_4X8:
146 	case MEDIA_BUS_FMT_SRBG888_DUMMY_4X8:
147 		conn_state->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY;
148 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
149 		break;
150 	case MEDIA_BUS_FMT_YUYV8_2X8:
151 	case MEDIA_BUS_FMT_YVYU8_2X8:
152 	case MEDIA_BUS_FMT_UYVY8_2X8:
153 	case MEDIA_BUS_FMT_VYUY8_2X8:
154 		conn_state->output_mode = ROCKCHIP_OUT_MODE_BT656;
155 		conn_state->output_if = VOP_OUTPUT_IF_BT656;
156 		break;
157 	case MEDIA_BUS_FMT_YUYV8_1X16:
158 	case MEDIA_BUS_FMT_YVYU8_1X16:
159 	case MEDIA_BUS_FMT_UYVY8_1X16:
160 	case MEDIA_BUS_FMT_VYUY8_1X16:
161 		conn_state->output_mode = ROCKCHIP_OUT_MODE_BT1120;
162 		conn_state->output_if = VOP_OUTPUT_IF_BT1120;
163 		break;
164 	case MEDIA_BUS_FMT_RGB888_1X24:
165 	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
166 	default:
167 		conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
168 		conn_state->output_if = VOP_OUTPUT_IF_RGB;
169 		break;
170 	}
171 
172 	return 0;
173 }
174 
175 static const struct rockchip_connector_funcs rockchip_rgb_connector_funcs = {
176 	.pre_init = rockchip_rgb_connector_pre_init,
177 	.init = rockchip_rgb_connector_init,
178 	.prepare = rockchip_rgb_connector_prepare,
179 	.unprepare = rockchip_rgb_connector_unprepare,
180 };
181 
182 static int rockchip_rgb_probe(struct udevice *dev)
183 {
184 	struct rockchip_rgb *rgb = dev_get_priv(dev);
185 	const struct rockchip_connector *connector =
186 		(const struct rockchip_connector *)dev_get_driver_data(dev);
187 
188 	rgb->dev = dev;
189 	rgb->funcs = connector->data;
190 	rgb->grf = syscon_get_regmap(dev_get_parent(dev));
191 	rgb->data_sync_bypass = dev_read_bool(dev, "rockchip,data-sync-bypass");
192 	rgb->id = of_alias_get_id(ofnode_to_np(dev->node), "rgb");
193 	if (rgb->id < 0)
194 		rgb->id = 0;
195 
196 	return 0;
197 }
198 
199 static void rv1126_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
200 {
201 	regmap_write(rgb->grf, RV1126_GRF_IOFUNC_CON3,
202 		     RV1126_LCDC_IO_BYPASS(rgb->data_sync_bypass));
203 }
204 
205 static const struct rockchip_rgb_funcs rv1126_rgb_funcs = {
206 	.prepare = rv1126_rgb_prepare,
207 };
208 
209 static const struct rockchip_connector rv1126_rgb_driver_data = {
210 	 .funcs = &rockchip_rgb_connector_funcs,
211 	 .data = &rv1126_rgb_funcs,
212 };
213 
214 static void px30_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
215 {
216 	regmap_write(rgb->grf, PX30_GRF_PD_VO_CON1, PX30_RGB_VOP_SEL(pipe) |
217 		     PX30_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass));
218 }
219 
220 static const struct rockchip_rgb_funcs px30_rgb_funcs = {
221 	.prepare = px30_rgb_prepare,
222 };
223 
224 static const struct rockchip_connector px30_rgb_driver_data = {
225 	 .funcs = &rockchip_rgb_connector_funcs,
226 	 .data = &px30_rgb_funcs,
227 };
228 
229 static void rk1808_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
230 {
231 	regmap_write(rgb->grf, RK1808_GRF_PD_VO_CON1,
232 		     RK1808_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass));
233 }
234 
235 static const struct rockchip_rgb_funcs rk1808_rgb_funcs = {
236 	.prepare = rk1808_rgb_prepare,
237 };
238 
239 static const struct rockchip_connector rk1808_rgb_driver_data = {
240 	.funcs = &rockchip_rgb_connector_funcs,
241 	.data = &rk1808_rgb_funcs,
242 };
243 
244 static void rk3288_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
245 {
246 	regmap_write(rgb->grf, RK3288_GRF_SOC_CON6, RK3288_LVDS_LCDC_SEL(pipe));
247 	regmap_write(rgb->grf, RK3288_GRF_SOC_CON7,
248 		     RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_ENABLE_2(1) |
249 		     RK3288_LVDS_CON_ENABLE_1(1) | RK3288_LVDS_CON_CLKINV(0) |
250 		     RK3288_LVDS_CON_TTL_EN(1));
251 }
252 
253 static void rk3288_rgb_unprepare(struct rockchip_rgb *rgb)
254 {
255 	regmap_write(rgb->grf, RK3288_GRF_SOC_CON7,
256 		     RK3288_LVDS_PWRDWN(1) | RK3288_LVDS_CON_ENABLE_2(0) |
257 		     RK3288_LVDS_CON_ENABLE_1(0) | RK3288_LVDS_CON_TTL_EN(0));
258 }
259 
260 static const struct rockchip_rgb_funcs rk3288_rgb_funcs = {
261 	.prepare = rk3288_rgb_prepare,
262 	.unprepare = rk3288_rgb_unprepare,
263 };
264 
265 static const struct rockchip_connector rk3288_rgb_driver_data = {
266 	.funcs = &rockchip_rgb_connector_funcs,
267 	.data = &rk3288_rgb_funcs,
268 };
269 
270 static void rk3368_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
271 {
272 	regmap_write(rgb->grf, RK3368_GRF_SOC_CON15, RK3368_FORCE_JETAG(0));
273 }
274 
275 static const struct rockchip_rgb_funcs rk3368_rgb_funcs = {
276 	.prepare = rk3368_rgb_prepare,
277 };
278 
279 static const struct rockchip_connector rk3368_rgb_driver_data = {
280 	.funcs = &rockchip_rgb_connector_funcs,
281 	.data = &rk3368_rgb_funcs,
282 };
283 
284 static void rk3568_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
285 {
286 	regmap_write(rgb->grf, RK3568_GRF_VO_CON1, RK3568_RGB_DATA_BYPASS(rgb->data_sync_bypass));
287 }
288 
289 static const struct rockchip_rgb_funcs rk3568_rgb_funcs = {
290 	.prepare = rk3568_rgb_prepare,
291 };
292 
293 static const struct rockchip_connector rk3568_rgb_driver_data = {
294 	.funcs = &rockchip_rgb_connector_funcs,
295 	.data = &rk3568_rgb_funcs,
296 };
297 
298 static const struct rockchip_connector rockchip_rgb_driver_data = {
299 	.funcs = &rockchip_rgb_connector_funcs,
300 };
301 
302 static const struct udevice_id rockchip_rgb_ids[] = {
303 	{
304 		.compatible = "rockchip,px30-rgb",
305 		.data = (ulong)&px30_rgb_driver_data,
306 	},
307 	{
308 		.compatible = "rockchip,rk1808-rgb",
309 		.data = (ulong)&rk1808_rgb_driver_data,
310 	},
311 	{
312 		.compatible = "rockchip,rk3066-rgb",
313 		.data = (ulong)&rockchip_rgb_driver_data,
314 	},
315 	{
316 		.compatible = "rockchip,rk3128-rgb",
317 		.data = (ulong)&rockchip_rgb_driver_data,
318 	},
319 	{
320 		.compatible = "rockchip,rk3288-rgb",
321 		.data = (ulong)&rk3288_rgb_driver_data,
322 	},
323 	{
324 		.compatible = "rockchip,rk3308-rgb",
325 		.data = (ulong)&rockchip_rgb_driver_data,
326 	},
327 	{
328 		.compatible = "rockchip,rk3368-rgb",
329 		.data = (ulong)&rk3368_rgb_driver_data,
330 	},
331 	{
332 		.compatible = "rockchip,rk3568-rgb",
333 		.data = (ulong)&rk3568_rgb_driver_data,
334 	},
335 	{
336 		.compatible = "rockchip,rv1108-rgb",
337 		.data = (ulong)&rockchip_rgb_driver_data,
338 	},
339 	{
340 		.compatible = "rockchip,rv1126-rgb",
341 		.data = (ulong)&rv1126_rgb_driver_data,
342 	},
343 	{}
344 };
345 
346 U_BOOT_DRIVER(rockchip_rgb) = {
347 	.name = "rockchip_rgb",
348 	.id = UCLASS_DISPLAY,
349 	.of_match = rockchip_rgb_ids,
350 	.probe = rockchip_rgb_probe,
351 	.priv_auto_alloc_size = sizeof(struct rockchip_rgb),
352 };
353