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