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