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