1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4 * Author:
5 * Sandy Huang <hjc@rock-chips.com>
6 */
7
8 #include <linux/component.h>
9 #include <linux/of_device.h>
10 #include <linux/of_graph.h>
11 #include <linux/regmap.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/phy/phy.h>
14 #include <linux/pinctrl/consumer.h>
15
16 #include <drm/drm_atomic_helper.h>
17 #include <drm/drm_crtc_helper.h>
18 #include <drm/drm_dp_helper.h>
19 #include <drm/drm_of.h>
20 #include <drm/drm_panel.h>
21 #include <drm/drm_probe_helper.h>
22
23 #include <uapi/linux/videodev2.h>
24
25 #include "rockchip_drm_drv.h"
26 #include "rockchip_drm_vop.h"
27
28 #define HIWORD_UPDATE(v, l, h) (((v) << (l)) | (GENMASK(h, l) << 16))
29
30 #define PX30_GRF_PD_VO_CON1 0x0438
31 #define PX30_RGB_DATA_SYNC_BYPASS(v) HIWORD_UPDATE(v, 3, 3)
32 #define PX30_RGB_VOP_SEL(v) HIWORD_UPDATE(v, 2, 2)
33
34 #define RK1808_GRF_PD_VO_CON1 0x0444
35 #define RK1808_RGB_DATA_SYNC_BYPASS(v) HIWORD_UPDATE(v, 3, 3)
36
37 #define RV1126_GRF_IOFUNC_CON3 0x1026c
38 #define RV1126_LCDC_IO_BYPASS(v) HIWORD_UPDATE(v, 0, 0)
39
40 #define RK3288_GRF_SOC_CON6 0x025c
41 #define RK3288_LVDS_LCDC_SEL(x) HIWORD_UPDATE(x, 3, 3)
42 #define RK3288_GRF_SOC_CON7 0x0260
43 #define RK3288_LVDS_PWRDWN(x) HIWORD_UPDATE(x, 15, 15)
44 #define RK3288_LVDS_CON_ENABLE_2(x) HIWORD_UPDATE(x, 12, 12)
45 #define RK3288_LVDS_CON_ENABLE_1(x) HIWORD_UPDATE(x, 11, 11)
46 #define RK3288_LVDS_CON_CLKINV(x) HIWORD_UPDATE(x, 8, 8)
47 #define RK3288_LVDS_CON_TTL_EN(x) HIWORD_UPDATE(x, 6, 6)
48
49 #define RK3568_GRF_VO_CON1 0X0364
50 #define RK3568_RGB_DATA_BYPASS(v) HIWORD_UPDATE(v, 6, 6)
51
52 struct rockchip_rgb;
53
54 struct rockchip_rgb_funcs {
55 void (*enable)(struct rockchip_rgb *rgb);
56 void (*disable)(struct rockchip_rgb *rgb);
57 };
58
59 struct rockchip_rgb {
60 u8 id;
61 struct device *dev;
62 struct drm_panel *panel;
63 struct drm_bridge *bridge;
64 struct drm_connector connector;
65 struct drm_encoder encoder;
66 struct phy *phy;
67 struct regmap *grf;
68 bool data_sync_bypass;
69 const struct rockchip_rgb_funcs *funcs;
70 struct rockchip_drm_sub_dev sub_dev;
71 };
72
connector_to_rgb(struct drm_connector * c)73 static inline struct rockchip_rgb *connector_to_rgb(struct drm_connector *c)
74 {
75 return container_of(c, struct rockchip_rgb, connector);
76 }
77
encoder_to_rgb(struct drm_encoder * e)78 static inline struct rockchip_rgb *encoder_to_rgb(struct drm_encoder *e)
79 {
80 return container_of(e, struct rockchip_rgb, encoder);
81 }
82
rockchip_rgb_connector_detect(struct drm_connector * connector,bool force)83 static enum drm_connector_status rockchip_rgb_connector_detect(struct drm_connector *connector, bool force)
84 {
85 return connector_status_connected;
86 }
87
rockchip_rgb_atomic_connector_get_property(struct drm_connector * connector,const struct drm_connector_state * state,struct drm_property * property,uint64_t * val)88 static int rockchip_rgb_atomic_connector_get_property(struct drm_connector *connector,
89 const struct drm_connector_state *state,
90 struct drm_property *property, uint64_t *val)
91 {
92 struct rockchip_rgb *rgb = connector_to_rgb(connector);
93 struct rockchip_drm_private *private = connector->dev->dev_private;
94
95 if (property == private->connector_id_prop) {
96 *val = rgb->id;
97 return 0;
98 }
99
100 DRM_ERROR("failed to get rockchip RGB property\n");
101 return -EINVAL;
102 }
103
104 static const struct drm_connector_funcs rockchip_rgb_connector_funcs = {
105 .detect = rockchip_rgb_connector_detect,
106 .fill_modes = drm_helper_probe_single_connector_modes,
107 .destroy = drm_connector_cleanup,
108 .reset = drm_atomic_helper_connector_reset,
109 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
110 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
111 .atomic_get_property = rockchip_rgb_atomic_connector_get_property,
112 };
113
rockchip_rgb_connector_get_modes(struct drm_connector * connector)114 static int rockchip_rgb_connector_get_modes(struct drm_connector *connector)
115 {
116 struct rockchip_rgb *rgb = connector_to_rgb(connector);
117 struct drm_panel *panel = rgb->panel;
118
119 return drm_panel_get_modes(panel, connector);
120 }
121
rockchip_rgb_connector_best_encoder(struct drm_connector * connector)122 static struct drm_encoder *rockchip_rgb_connector_best_encoder(struct drm_connector *connector)
123 {
124 struct rockchip_rgb *rgb = connector_to_rgb(connector);
125
126 return &rgb->encoder;
127 }
128
129 static const struct drm_connector_helper_funcs rockchip_rgb_connector_helper_funcs = {
130 .get_modes = rockchip_rgb_connector_get_modes,
131 .best_encoder = rockchip_rgb_connector_best_encoder,
132 };
133
rockchip_rgb_encoder_enable(struct drm_encoder * encoder)134 static void rockchip_rgb_encoder_enable(struct drm_encoder *encoder)
135 {
136 struct rockchip_rgb *rgb = encoder_to_rgb(encoder);
137
138 pinctrl_pm_select_default_state(rgb->dev);
139
140 if (rgb->funcs && rgb->funcs->enable) {
141 rgb->funcs->enable(rgb);
142 }
143
144 if (rgb->phy) {
145 phy_power_on(rgb->phy);
146 }
147
148 if (rgb->panel) {
149 drm_panel_prepare(rgb->panel);
150 drm_panel_enable(rgb->panel);
151 }
152 }
153
rockchip_rgb_encoder_disable(struct drm_encoder * encoder)154 static void rockchip_rgb_encoder_disable(struct drm_encoder *encoder)
155 {
156 struct rockchip_rgb *rgb = encoder_to_rgb(encoder);
157
158 if (rgb->panel) {
159 drm_panel_disable(rgb->panel);
160 drm_panel_unprepare(rgb->panel);
161 }
162
163 if (rgb->phy) {
164 phy_power_off(rgb->phy);
165 }
166
167 if (rgb->funcs && rgb->funcs->disable) {
168 rgb->funcs->disable(rgb);
169 }
170
171 pinctrl_pm_select_sleep_state(rgb->dev);
172 }
173
rockchip_rgb_encoder_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)174 static int rockchip_rgb_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state,
175 struct drm_connector_state *conn_state)
176 {
177 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
178 struct drm_connector *connector = conn_state->connector;
179 struct drm_display_info *info = &connector->display_info;
180
181 if (info->num_bus_formats) {
182 s->bus_format = info->bus_formats[0];
183 } else {
184 s->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
185 }
186
187 switch (s->bus_format) {
188 case MEDIA_BUS_FMT_RGB666_1X18:
189 s->output_mode = ROCKCHIP_OUT_MODE_P666;
190 s->output_if = VOP_OUTPUT_IF_RGB;
191 break;
192 case MEDIA_BUS_FMT_RGB565_1X16:
193 s->output_mode = ROCKCHIP_OUT_MODE_P565;
194 s->output_if = VOP_OUTPUT_IF_RGB;
195 break;
196 case MEDIA_BUS_FMT_RGB888_3X8:
197 s->output_mode = ROCKCHIP_OUT_MODE_S888;
198 s->output_if = VOP_OUTPUT_IF_RGB;
199 break;
200 case MEDIA_BUS_FMT_RGB888_DUMMY_4X8:
201 s->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY;
202 s->output_if = VOP_OUTPUT_IF_RGB;
203 break;
204 case MEDIA_BUS_FMT_YUYV8_2X8:
205 case MEDIA_BUS_FMT_YVYU8_2X8:
206 case MEDIA_BUS_FMT_UYVY8_2X8:
207 case MEDIA_BUS_FMT_VYUY8_2X8:
208 s->output_mode = ROCKCHIP_OUT_MODE_BT656;
209 s->output_if = VOP_OUTPUT_IF_BT656;
210 break;
211 case MEDIA_BUS_FMT_YUYV8_1X16:
212 case MEDIA_BUS_FMT_YVYU8_1X16:
213 case MEDIA_BUS_FMT_UYVY8_1X16:
214 case MEDIA_BUS_FMT_VYUY8_1X16:
215 s->output_mode = ROCKCHIP_OUT_MODE_BT1120;
216 s->output_if = VOP_OUTPUT_IF_BT1120;
217 break;
218 case MEDIA_BUS_FMT_RGB888_1X24:
219 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
220 default:
221 s->output_mode = ROCKCHIP_OUT_MODE_P888;
222 s->output_if = VOP_OUTPUT_IF_RGB;
223 break;
224 }
225
226 s->output_type = DRM_MODE_CONNECTOR_DPI;
227 s->bus_flags = info->bus_flags;
228 s->tv_state = &conn_state->tv;
229 s->eotf = HDMI_EOTF_TRADITIONAL_GAMMA_SDR;
230 s->color_space = V4L2_COLORSPACE_DEFAULT;
231
232 return 0;
233 }
234
rockchip_rgb_encoder_loader_protect(struct drm_encoder * encoder,bool on)235 static void rockchip_rgb_encoder_loader_protect(struct drm_encoder *encoder, bool on)
236 {
237 struct rockchip_rgb *rgb = encoder_to_rgb(encoder);
238
239 if (rgb->panel) {
240 panel_simple_loader_protect(rgb->panel);
241 }
242 }
243
244 static const struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = {
245 .enable = rockchip_rgb_encoder_enable,
246 .disable = rockchip_rgb_encoder_disable,
247 .atomic_check = rockchip_rgb_encoder_atomic_check,
248 };
249
250 static const struct drm_encoder_funcs rockchip_rgb_encoder_funcs = {
251 .destroy = drm_encoder_cleanup,
252 };
253
rockchip_rgb_bind(struct device * dev,struct device * master,void * data)254 static int rockchip_rgb_bind(struct device *dev, struct device *master, void *data)
255 {
256 struct rockchip_rgb *rgb = dev_get_drvdata(dev);
257 struct drm_device *drm_dev = data;
258 struct drm_encoder *encoder = &rgb->encoder;
259 struct drm_connector *connector;
260 int ret;
261
262 ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, &rgb->panel, &rgb->bridge);
263 if (ret) {
264 DRM_DEV_ERROR(dev, "failed to find panel or bridge: %d\n", ret);
265 return ret;
266 }
267
268 encoder->possible_crtcs = rockchip_drm_of_find_possible_crtcs(drm_dev, dev->of_node);
269
270 ret = drm_encoder_init(drm_dev, encoder, &rockchip_rgb_encoder_funcs, DRM_MODE_ENCODER_DPI, NULL);
271 if (ret < 0) {
272 DRM_DEV_ERROR(dev, "failed to initialize encoder: %d\n", ret);
273 return ret;
274 }
275
276 drm_encoder_helper_add(encoder, &rockchip_rgb_encoder_helper_funcs);
277
278 if (rgb->panel) {
279 struct rockchip_drm_private *private = drm_dev->dev_private;
280
281 connector = &rgb->connector;
282 connector->interlace_allowed = true;
283 ret = drm_connector_init(drm_dev, connector, &rockchip_rgb_connector_funcs, DRM_MODE_CONNECTOR_DPI);
284 if (ret < 0) {
285 DRM_DEV_ERROR(dev, "failed to initialize connector: %d\n", ret);
286 goto err_free_encoder;
287 }
288
289 drm_connector_helper_add(connector, &rockchip_rgb_connector_helper_funcs);
290
291 ret = drm_connector_attach_encoder(connector, encoder);
292 if (ret < 0) {
293 DRM_DEV_ERROR(dev, "failed to attach encoder: %d\n", ret);
294 goto err_free_connector;
295 }
296 rgb->sub_dev.connector = &rgb->connector;
297 rgb->sub_dev.of_node = rgb->dev->of_node;
298 rgb->sub_dev.loader_protect = rockchip_rgb_encoder_loader_protect;
299 drm_object_attach_property(&connector->base, private->connector_id_prop, 0);
300 rockchip_drm_register_sub_dev(&rgb->sub_dev);
301 } else {
302 rgb->bridge->encoder = encoder;
303 ret = drm_bridge_attach(encoder, rgb->bridge, NULL, 0);
304 if (ret) {
305 DRM_DEV_ERROR(dev, "failed to attach bridge: %d\n", ret);
306 goto err_free_encoder;
307 }
308 }
309
310 return 0;
311
312 err_free_connector:
313 drm_connector_cleanup(connector);
314 err_free_encoder:
315 drm_encoder_cleanup(encoder);
316 return ret;
317 }
318
rockchip_rgb_unbind(struct device * dev,struct device * master,void * data)319 static void rockchip_rgb_unbind(struct device *dev, struct device *master, void *data)
320 {
321 struct rockchip_rgb *rgb = dev_get_drvdata(dev);
322
323 if (rgb->sub_dev.connector) {
324 rockchip_drm_register_sub_dev(&rgb->sub_dev);
325 }
326 if (rgb->panel) {
327 drm_connector_cleanup(&rgb->connector);
328 }
329
330 drm_encoder_cleanup(&rgb->encoder);
331 }
332
333 static const struct component_ops rockchip_rgb_component_ops = {
334 .bind = rockchip_rgb_bind,
335 .unbind = rockchip_rgb_unbind,
336 };
337
rockchip_rgb_probe(struct platform_device * pdev)338 static int rockchip_rgb_probe(struct platform_device *pdev)
339 {
340 struct device *dev = &pdev->dev;
341 struct rockchip_rgb *rgb;
342 int ret, id;
343
344 rgb = devm_kzalloc(&pdev->dev, sizeof(*rgb), GFP_KERNEL);
345 if (!rgb) {
346 return -ENOMEM;
347 }
348
349 id = of_alias_get_id(dev->of_node, "rgb");
350 if (id < 0) {
351 id = 0;
352 }
353
354 rgb->id = id;
355 rgb->dev = dev;
356 rgb->funcs = of_device_get_match_data(dev);
357 platform_set_drvdata(pdev, rgb);
358
359 rgb->data_sync_bypass = of_property_read_bool(dev->of_node, "rockchip,data-sync-bypass");
360
361 if (dev->parent && dev->parent->of_node) {
362 rgb->grf = syscon_node_to_regmap(dev->parent->of_node);
363 if (IS_ERR(rgb->grf)) {
364 ret = PTR_ERR(rgb->grf);
365 dev_err(dev, "Unable to get grf: %d\n", ret);
366 return ret;
367 }
368 }
369
370 rgb->phy = devm_phy_optional_get(dev, "phy");
371 if (IS_ERR(rgb->phy)) {
372 ret = PTR_ERR(rgb->phy);
373 dev_err(dev, "failed to get phy: %d\n", ret);
374 return ret;
375 }
376
377 return component_add(dev, &rockchip_rgb_component_ops);
378 }
379
rockchip_rgb_remove(struct platform_device * pdev)380 static int rockchip_rgb_remove(struct platform_device *pdev)
381 {
382 component_del(&pdev->dev, &rockchip_rgb_component_ops);
383
384 return 0;
385 }
386
px30_rgb_enable(struct rockchip_rgb * rgb)387 static void px30_rgb_enable(struct rockchip_rgb *rgb)
388 {
389 int pipe = drm_of_encoder_active_endpoint_id(rgb->dev->of_node, &rgb->encoder);
390
391 regmap_write(rgb->grf, PX30_GRF_PD_VO_CON1,
392 PX30_RGB_VOP_SEL(pipe) | PX30_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass));
393 }
394
395 static const struct rockchip_rgb_funcs px30_rgb_funcs = {
396 .enable = px30_rgb_enable,
397 };
398
rk1808_rgb_enable(struct rockchip_rgb * rgb)399 static void rk1808_rgb_enable(struct rockchip_rgb *rgb)
400 {
401 regmap_write(rgb->grf, RK1808_GRF_PD_VO_CON1, RK1808_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass));
402 }
403
404 static const struct rockchip_rgb_funcs rk1808_rgb_funcs = {
405 .enable = rk1808_rgb_enable,
406 };
407
rk3288_rgb_enable(struct rockchip_rgb * rgb)408 static void rk3288_rgb_enable(struct rockchip_rgb *rgb)
409 {
410 int pipe = drm_of_encoder_active_endpoint_id(rgb->dev->of_node, &rgb->encoder);
411
412 regmap_write(rgb->grf, RK3288_GRF_SOC_CON6, RK3288_LVDS_LCDC_SEL(pipe));
413 regmap_write(rgb->grf, RK3288_GRF_SOC_CON7,
414 RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_ENABLE_2(1) | RK3288_LVDS_CON_ENABLE_1(1) |
415 RK3288_LVDS_CON_CLKINV(0) | RK3288_LVDS_CON_TTL_EN(1));
416 }
417
rk3288_rgb_disable(struct rockchip_rgb * rgb)418 static void rk3288_rgb_disable(struct rockchip_rgb *rgb)
419 {
420 regmap_write(rgb->grf, RK3288_GRF_SOC_CON7,
421 RK3288_LVDS_PWRDWN(1) | RK3288_LVDS_CON_ENABLE_2(0) | RK3288_LVDS_CON_ENABLE_1(0) |
422 RK3288_LVDS_CON_TTL_EN(0));
423 }
424
425 static const struct rockchip_rgb_funcs rk3288_rgb_funcs = {
426 .enable = rk3288_rgb_enable,
427 .disable = rk3288_rgb_disable,
428 };
429
rk3568_rgb_enable(struct rockchip_rgb * rgb)430 static void rk3568_rgb_enable(struct rockchip_rgb *rgb)
431 {
432 regmap_write(rgb->grf, RK3568_GRF_VO_CON1, RK3568_RGB_DATA_BYPASS(rgb->data_sync_bypass));
433 }
434
435 static const struct rockchip_rgb_funcs rk3568_rgb_funcs = {
436 .enable = rk3568_rgb_enable,
437 };
438
rv1126_rgb_enable(struct rockchip_rgb * rgb)439 static void rv1126_rgb_enable(struct rockchip_rgb *rgb)
440 {
441 regmap_write(rgb->grf, RV1126_GRF_IOFUNC_CON3, RV1126_LCDC_IO_BYPASS(rgb->data_sync_bypass));
442 }
443
444 static const struct rockchip_rgb_funcs rv1126_rgb_funcs = {
445 .enable = rv1126_rgb_enable,
446 };
447
448 static const struct of_device_id rockchip_rgb_dt_ids[] = {
449 {.compatible = "rockchip,px30-rgb", .data = &px30_rgb_funcs},
450 {.compatible = "rockchip,rk1808-rgb", .data = &rk1808_rgb_funcs},
451 {
452 .compatible = "rockchip,rk3066-rgb",
453 },
454 {
455 .compatible = "rockchip,rk3128-rgb",
456 },
457 {.compatible = "rockchip,rk3288-rgb", .data = &rk3288_rgb_funcs},
458 {
459 .compatible = "rockchip,rk3308-rgb",
460 },
461 {
462 .compatible = "rockchip,rk3368-rgb",
463 },
464 {.compatible = "rockchip,rk3568-rgb", .data = &rk3568_rgb_funcs},
465 {
466 .compatible = "rockchip,rk3588-rgb",
467 },
468 {
469 .compatible = "rockchip,rv1108-rgb",
470 },
471 {.compatible = "rockchip,rv1126-rgb", .data = &rv1126_rgb_funcs},
472 {}};
473 MODULE_DEVICE_TABLE(of, rockchip_rgb_dt_ids);
474
475 struct platform_driver rockchip_rgb_driver = {
476 .probe = rockchip_rgb_probe,
477 .remove = rockchip_rgb_remove,
478 .driver =
479 {
480 .name = "rockchip-rgb",
481 .of_match_table = of_match_ptr(rockchip_rgb_dt_ids),
482 },
483 };
484