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