Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
0004  * Author:
0005  *      Sandy Huang <hjc@rock-chips.com>
0006  */
0007 
0008 #include <linux/component.h>
0009 #include <linux/media-bus-format.h>
0010 #include <linux/of_graph.h>
0011 
0012 #include <drm/display/drm_dp_helper.h>
0013 #include <drm/drm_atomic_helper.h>
0014 #include <drm/drm_bridge.h>
0015 #include <drm/drm_bridge_connector.h>
0016 #include <drm/drm_of.h>
0017 #include <drm/drm_panel.h>
0018 #include <drm/drm_probe_helper.h>
0019 #include <drm/drm_simple_kms_helper.h>
0020 
0021 #include "rockchip_drm_drv.h"
0022 #include "rockchip_drm_vop.h"
0023 #include "rockchip_rgb.h"
0024 
0025 #define encoder_to_rgb(c) container_of(c, struct rockchip_rgb, encoder)
0026 
0027 struct rockchip_rgb {
0028     struct device *dev;
0029     struct drm_device *drm_dev;
0030     struct drm_bridge *bridge;
0031     struct drm_encoder encoder;
0032     struct drm_connector connector;
0033     int output_mode;
0034 };
0035 
0036 static int
0037 rockchip_rgb_encoder_atomic_check(struct drm_encoder *encoder,
0038                    struct drm_crtc_state *crtc_state,
0039                    struct drm_connector_state *conn_state)
0040 {
0041     struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
0042     struct drm_connector *connector = conn_state->connector;
0043     struct drm_display_info *info = &connector->display_info;
0044     u32 bus_format;
0045 
0046     if (info->num_bus_formats)
0047         bus_format = info->bus_formats[0];
0048     else
0049         bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0050 
0051     switch (bus_format) {
0052     case MEDIA_BUS_FMT_RGB666_1X18:
0053         s->output_mode = ROCKCHIP_OUT_MODE_P666;
0054         break;
0055     case MEDIA_BUS_FMT_RGB565_1X16:
0056         s->output_mode = ROCKCHIP_OUT_MODE_P565;
0057         break;
0058     case MEDIA_BUS_FMT_RGB888_1X24:
0059     case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
0060     default:
0061         s->output_mode = ROCKCHIP_OUT_MODE_P888;
0062         break;
0063     }
0064 
0065     s->output_type = DRM_MODE_CONNECTOR_LVDS;
0066 
0067     return 0;
0068 }
0069 
0070 static const
0071 struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = {
0072     .atomic_check = rockchip_rgb_encoder_atomic_check,
0073 };
0074 
0075 struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
0076                        struct drm_crtc *crtc,
0077                        struct drm_device *drm_dev)
0078 {
0079     struct rockchip_rgb *rgb;
0080     struct drm_encoder *encoder;
0081     struct device_node *port, *endpoint;
0082     u32 endpoint_id;
0083     int ret = 0, child_count = 0;
0084     struct drm_panel *panel;
0085     struct drm_bridge *bridge;
0086     struct drm_connector *connector;
0087 
0088     rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL);
0089     if (!rgb)
0090         return ERR_PTR(-ENOMEM);
0091 
0092     rgb->dev = dev;
0093     rgb->drm_dev = drm_dev;
0094 
0095     port = of_graph_get_port_by_id(dev->of_node, 0);
0096     if (!port)
0097         return ERR_PTR(-EINVAL);
0098 
0099     for_each_child_of_node(port, endpoint) {
0100         if (of_property_read_u32(endpoint, "reg", &endpoint_id))
0101             endpoint_id = 0;
0102 
0103         /* if subdriver (> 0) or error case (< 0), ignore entry */
0104         if (rockchip_drm_endpoint_is_subdriver(endpoint) != 0)
0105             continue;
0106 
0107         child_count++;
0108         ret = drm_of_find_panel_or_bridge(dev->of_node, 0, endpoint_id,
0109                           &panel, &bridge);
0110         if (!ret) {
0111             of_node_put(endpoint);
0112             break;
0113         }
0114     }
0115 
0116     of_node_put(port);
0117 
0118     /* if the rgb output is not connected to anything, just return */
0119     if (!child_count)
0120         return NULL;
0121 
0122     if (ret < 0) {
0123         if (ret != -EPROBE_DEFER)
0124             DRM_DEV_ERROR(dev, "failed to find panel or bridge %d\n", ret);
0125         return ERR_PTR(ret);
0126     }
0127 
0128     encoder = &rgb->encoder;
0129     encoder->possible_crtcs = drm_crtc_mask(crtc);
0130 
0131     ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_NONE);
0132     if (ret < 0) {
0133         DRM_DEV_ERROR(drm_dev->dev,
0134                   "failed to initialize encoder: %d\n", ret);
0135         return ERR_PTR(ret);
0136     }
0137 
0138     drm_encoder_helper_add(encoder, &rockchip_rgb_encoder_helper_funcs);
0139 
0140     if (panel) {
0141         bridge = drm_panel_bridge_add_typed(panel,
0142                             DRM_MODE_CONNECTOR_LVDS);
0143         if (IS_ERR(bridge))
0144             return ERR_CAST(bridge);
0145     }
0146 
0147     rgb->bridge = bridge;
0148 
0149     ret = drm_bridge_attach(encoder, rgb->bridge, NULL,
0150                 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
0151     if (ret)
0152         goto err_free_encoder;
0153 
0154     connector = &rgb->connector;
0155     connector = drm_bridge_connector_init(rgb->drm_dev, encoder);
0156     if (IS_ERR(connector)) {
0157         DRM_DEV_ERROR(drm_dev->dev,
0158                   "failed to initialize bridge connector: %pe\n",
0159                   connector);
0160         ret = PTR_ERR(connector);
0161         goto err_free_encoder;
0162     }
0163 
0164     ret = drm_connector_attach_encoder(connector, encoder);
0165     if (ret < 0) {
0166         DRM_DEV_ERROR(drm_dev->dev,
0167                   "failed to attach encoder: %d\n", ret);
0168         goto err_free_connector;
0169     }
0170 
0171     return rgb;
0172 
0173 err_free_connector:
0174     drm_connector_cleanup(connector);
0175 err_free_encoder:
0176     drm_encoder_cleanup(encoder);
0177     return ERR_PTR(ret);
0178 }
0179 EXPORT_SYMBOL_GPL(rockchip_rgb_init);
0180 
0181 void rockchip_rgb_fini(struct rockchip_rgb *rgb)
0182 {
0183     drm_panel_bridge_remove(rgb->bridge);
0184     drm_connector_cleanup(&rgb->connector);
0185     drm_encoder_cleanup(&rgb->encoder);
0186 }
0187 EXPORT_SYMBOL_GPL(rockchip_rgb_fini);