1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2015 Texas Instruments 4 * Author: Jyri Sarha <jsarha@ti.com> 5 */ 6 7 #include <linux/component.h> 8 #include <linux/of_graph.h> 9 10 #include <drm/drm_atomic_helper.h> 11 #include <drm/drm_of.h> 12 13 #include "tilcdc_drv.h" 14 #include "tilcdc_external.h" 15 16 static const struct tilcdc_panel_info panel_info_tda998x = { 17 .ac_bias = 255, 18 .ac_bias_intrpt = 0, 19 .dma_burst_sz = 16, 20 .bpp = 16, 21 .fdd = 0x80, 22 .tft_alt_mode = 0, 23 .invert_pxl_clk = 1, 24 .sync_edge = 1, 25 .sync_ctrl = 1, 26 .raster_order = 0, 27 }; 28 29 static const struct tilcdc_panel_info panel_info_default = { 30 .ac_bias = 255, 31 .ac_bias_intrpt = 0, 32 .dma_burst_sz = 16, 33 .bpp = 16, 34 .fdd = 0x80, 35 .tft_alt_mode = 0, 36 .sync_edge = 0, 37 .sync_ctrl = 1, 38 .raster_order = 0, 39 }; 40 41 static 42 struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev, 43 struct drm_encoder *encoder) 44 { 45 struct drm_connector *connector; 46 47 list_for_each_entry(connector, &ddev->mode_config.connector_list, head) { 48 if (drm_connector_has_possible_encoder(connector, encoder)) 49 return connector; 50 } 51 52 dev_err(ddev->dev, "No connector found for %s encoder (id %d)\n", 53 encoder->name, encoder->base.id); 54 55 return NULL; 56 } 57 58 int tilcdc_add_component_encoder(struct drm_device *ddev) 59 { 60 struct tilcdc_drm_private *priv = ddev->dev_private; 61 struct drm_encoder *encoder; 62 63 list_for_each_entry(encoder, &ddev->mode_config.encoder_list, head) 64 if (encoder->possible_crtcs & (1 << priv->crtc->index)) 65 break; 66 67 if (!encoder) { 68 dev_err(ddev->dev, "%s: No suitable encoder found\n", __func__); 69 return -ENODEV; 70 } 71 72 priv->external_connector = 73 tilcdc_encoder_find_connector(ddev, encoder); 74 75 if (!priv->external_connector) 76 return -ENODEV; 77 78 /* Only tda998x is supported at the moment. */ 79 tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true); 80 tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x); 81 82 return 0; 83 } 84 85 static const struct drm_encoder_funcs tilcdc_external_encoder_funcs = { 86 .destroy = drm_encoder_cleanup, 87 }; 88 89 static 90 int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge) 91 { 92 struct tilcdc_drm_private *priv = ddev->dev_private; 93 int ret; 94 95 priv->external_encoder->possible_crtcs = BIT(0); 96 97 ret = drm_bridge_attach(priv->external_encoder, bridge, NULL); 98 if (ret) { 99 dev_err(ddev->dev, "drm_bridge_attach() failed %d\n", ret); 100 return ret; 101 } 102 103 tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_default); 104 105 priv->external_connector = 106 tilcdc_encoder_find_connector(ddev, priv->external_encoder); 107 if (!priv->external_connector) 108 return -ENODEV; 109 110 return 0; 111 } 112 113 int tilcdc_attach_external_device(struct drm_device *ddev) 114 { 115 struct tilcdc_drm_private *priv = ddev->dev_private; 116 struct drm_bridge *bridge; 117 struct drm_panel *panel; 118 int ret; 119 120 ret = drm_of_find_panel_or_bridge(ddev->dev->of_node, 0, 0, 121 &panel, &bridge); 122 if (ret == -ENODEV) 123 return 0; 124 else if (ret) 125 return ret; 126 127 priv->external_encoder = devm_kzalloc(ddev->dev, 128 sizeof(*priv->external_encoder), 129 GFP_KERNEL); 130 if (!priv->external_encoder) 131 return -ENOMEM; 132 133 ret = drm_encoder_init(ddev, priv->external_encoder, 134 &tilcdc_external_encoder_funcs, 135 DRM_MODE_ENCODER_NONE, NULL); 136 if (ret) { 137 dev_err(ddev->dev, "drm_encoder_init() failed %d\n", ret); 138 return ret; 139 } 140 141 if (panel) { 142 bridge = devm_drm_panel_bridge_add(ddev->dev, panel, 143 DRM_MODE_CONNECTOR_DPI); 144 if (IS_ERR(bridge)) { 145 ret = PTR_ERR(bridge); 146 goto err_encoder_cleanup; 147 } 148 } 149 150 ret = tilcdc_attach_bridge(ddev, bridge); 151 if (ret) 152 goto err_encoder_cleanup; 153 154 return 0; 155 156 err_encoder_cleanup: 157 drm_encoder_cleanup(priv->external_encoder); 158 return ret; 159 } 160 161 static int dev_match_of(struct device *dev, void *data) 162 { 163 return dev->of_node == data; 164 } 165 166 int tilcdc_get_external_components(struct device *dev, 167 struct component_match **match) 168 { 169 struct device_node *node; 170 171 node = of_graph_get_remote_node(dev->of_node, 0, 0); 172 173 if (!of_device_is_compatible(node, "nxp,tda998x")) { 174 of_node_put(node); 175 return 0; 176 } 177 178 if (match) 179 drm_of_component_match_add(dev, match, dev_match_of, node); 180 of_node_put(node); 181 return 1; 182 } 183