Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2015 Texas Instruments
0004  * Author: Jyri Sarha <jsarha@ti.com>
0005  */
0006 
0007 #include <linux/component.h>
0008 #include <linux/of_graph.h>
0009 
0010 #include <drm/drm_atomic_helper.h>
0011 #include <drm/drm_bridge.h>
0012 #include <drm/drm_of.h>
0013 #include <drm/drm_simple_kms_helper.h>
0014 
0015 #include "tilcdc_drv.h"
0016 #include "tilcdc_external.h"
0017 
0018 static const struct tilcdc_panel_info panel_info_tda998x = {
0019         .ac_bias                = 255,
0020         .ac_bias_intrpt         = 0,
0021         .dma_burst_sz           = 16,
0022         .bpp                    = 16,
0023         .fdd                    = 0x80,
0024         .tft_alt_mode           = 0,
0025         .invert_pxl_clk     = 1,
0026         .sync_edge              = 1,
0027         .sync_ctrl              = 1,
0028         .raster_order           = 0,
0029 };
0030 
0031 static const struct tilcdc_panel_info panel_info_default = {
0032         .ac_bias                = 255,
0033         .ac_bias_intrpt         = 0,
0034         .dma_burst_sz           = 16,
0035         .bpp                    = 16,
0036         .fdd                    = 0x80,
0037         .tft_alt_mode           = 0,
0038         .sync_edge              = 0,
0039         .sync_ctrl              = 1,
0040         .raster_order           = 0,
0041 };
0042 
0043 static
0044 struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev,
0045                             struct drm_encoder *encoder)
0046 {
0047     struct drm_connector *connector;
0048 
0049     list_for_each_entry(connector, &ddev->mode_config.connector_list, head) {
0050         if (drm_connector_has_possible_encoder(connector, encoder))
0051             return connector;
0052     }
0053 
0054     dev_err(ddev->dev, "No connector found for %s encoder (id %d)\n",
0055         encoder->name, encoder->base.id);
0056 
0057     return NULL;
0058 }
0059 
0060 int tilcdc_add_component_encoder(struct drm_device *ddev)
0061 {
0062     struct tilcdc_drm_private *priv = ddev->dev_private;
0063     struct drm_encoder *encoder = NULL, *iter;
0064 
0065     list_for_each_entry(iter, &ddev->mode_config.encoder_list, head)
0066         if (iter->possible_crtcs & (1 << priv->crtc->index)) {
0067             encoder = iter;
0068             break;
0069         }
0070 
0071     if (!encoder) {
0072         dev_err(ddev->dev, "%s: No suitable encoder found\n", __func__);
0073         return -ENODEV;
0074     }
0075 
0076     priv->external_connector =
0077         tilcdc_encoder_find_connector(ddev, encoder);
0078 
0079     if (!priv->external_connector)
0080         return -ENODEV;
0081 
0082     /* Only tda998x is supported at the moment. */
0083     tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true);
0084     tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
0085 
0086     return 0;
0087 }
0088 
0089 static
0090 int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
0091 {
0092     struct tilcdc_drm_private *priv = ddev->dev_private;
0093     int ret;
0094 
0095     priv->external_encoder->possible_crtcs = BIT(0);
0096 
0097     ret = drm_bridge_attach(priv->external_encoder, bridge, NULL, 0);
0098     if (ret)
0099         return ret;
0100 
0101     tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_default);
0102 
0103     priv->external_connector =
0104         tilcdc_encoder_find_connector(ddev, priv->external_encoder);
0105     if (!priv->external_connector)
0106         return -ENODEV;
0107 
0108     return 0;
0109 }
0110 
0111 int tilcdc_attach_external_device(struct drm_device *ddev)
0112 {
0113     struct tilcdc_drm_private *priv = ddev->dev_private;
0114     struct drm_bridge *bridge;
0115     struct drm_panel *panel;
0116     int ret;
0117 
0118     ret = drm_of_find_panel_or_bridge(ddev->dev->of_node, 0, 0,
0119                       &panel, &bridge);
0120     if (ret == -ENODEV)
0121         return 0;
0122     else if (ret)
0123         return ret;
0124 
0125     priv->external_encoder = devm_kzalloc(ddev->dev,
0126                           sizeof(*priv->external_encoder),
0127                           GFP_KERNEL);
0128     if (!priv->external_encoder)
0129         return -ENOMEM;
0130 
0131     ret = drm_simple_encoder_init(ddev, priv->external_encoder,
0132                       DRM_MODE_ENCODER_NONE);
0133     if (ret) {
0134         dev_err(ddev->dev, "drm_encoder_init() failed %d\n", ret);
0135         return ret;
0136     }
0137 
0138     if (panel) {
0139         bridge = devm_drm_panel_bridge_add_typed(ddev->dev, panel,
0140                              DRM_MODE_CONNECTOR_DPI);
0141         if (IS_ERR(bridge)) {
0142             ret = PTR_ERR(bridge);
0143             goto err_encoder_cleanup;
0144         }
0145     }
0146 
0147     ret = tilcdc_attach_bridge(ddev, bridge);
0148     if (ret)
0149         goto err_encoder_cleanup;
0150 
0151     return 0;
0152 
0153 err_encoder_cleanup:
0154     drm_encoder_cleanup(priv->external_encoder);
0155     return ret;
0156 }
0157 
0158 static int dev_match_of(struct device *dev, void *data)
0159 {
0160     return dev->of_node == data;
0161 }
0162 
0163 int tilcdc_get_external_components(struct device *dev,
0164                    struct component_match **match)
0165 {
0166     struct device_node *node;
0167 
0168     node = of_graph_get_remote_node(dev->of_node, 0, 0);
0169 
0170     if (!of_device_is_compatible(node, "nxp,tda998x")) {
0171         of_node_put(node);
0172         return 0;
0173     }
0174 
0175     if (match)
0176         drm_of_component_match_add(dev, match, dev_match_of, node);
0177     of_node_put(node);
0178     return 1;
0179 }