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