• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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