1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 4 * Author: Archit Taneja <archit@ti.com> 5 */ 6 7#include <linux/kernel.h> 8#include <linux/module.h> 9#include <linux/platform_device.h> 10#include <linux/slab.h> 11#include <linux/of.h> 12#include <linux/of_graph.h> 13 14#include <drm/drm_bridge.h> 15#include <drm/drm_panel.h> 16 17#include "dss.h" 18#include "omapdss.h" 19 20int omapdss_device_init_output(struct omap_dss_device *out, 21 struct drm_bridge *local_bridge) 22{ 23 struct device_node *remote_node; 24 int ret; 25 26 remote_node = of_graph_get_remote_node(out->dev->of_node, 27 out->of_port, 0); 28 if (!remote_node) { 29 dev_dbg(out->dev, "failed to find video sink\n"); 30 return 0; 31 } 32 33 out->next = omapdss_find_device_by_node(remote_node); 34 out->bridge = of_drm_find_bridge(remote_node); 35 out->panel = of_drm_find_panel(remote_node); 36 if (IS_ERR(out->panel)) 37 out->panel = NULL; 38 39 of_node_put(remote_node); 40 41 if (out->next && out->type != out->next->type) { 42 dev_err(out->dev, "output type and display type don't match\n"); 43 ret = -EINVAL; 44 goto error; 45 } 46 47 if (out->panel) { 48 struct drm_bridge *bridge; 49 50 bridge = drm_panel_bridge_add(out->panel); 51 if (IS_ERR(bridge)) { 52 dev_err(out->dev, 53 "unable to create panel bridge (%ld)\n", 54 PTR_ERR(bridge)); 55 ret = PTR_ERR(bridge); 56 goto error; 57 } 58 59 out->bridge = bridge; 60 } 61 62 if (local_bridge) { 63 if (!out->bridge) { 64 ret = -EPROBE_DEFER; 65 goto error; 66 } 67 68 out->next_bridge = out->bridge; 69 out->bridge = local_bridge; 70 } 71 72 if (!out->next && !out->bridge) { 73 ret = -EPROBE_DEFER; 74 goto error; 75 } 76 77 return 0; 78 79error: 80 omapdss_device_cleanup_output(out); 81 out->next = NULL; 82 return ret; 83} 84EXPORT_SYMBOL(omapdss_device_init_output); 85 86void omapdss_device_cleanup_output(struct omap_dss_device *out) 87{ 88 if (out->bridge && out->panel) 89 drm_panel_bridge_remove(out->next_bridge ? 90 out->next_bridge : out->bridge); 91 92 if (out->next) 93 omapdss_device_put(out->next); 94} 95EXPORT_SYMBOL(omapdss_device_cleanup_output); 96 97int dss_install_mgr_ops(struct dss_device *dss, 98 const struct dss_mgr_ops *mgr_ops, 99 struct omap_drm_private *priv) 100{ 101 if (dss->mgr_ops) 102 return -EBUSY; 103 104 dss->mgr_ops = mgr_ops; 105 dss->mgr_ops_priv = priv; 106 107 return 0; 108} 109EXPORT_SYMBOL(dss_install_mgr_ops); 110 111void dss_uninstall_mgr_ops(struct dss_device *dss) 112{ 113 dss->mgr_ops = NULL; 114 dss->mgr_ops_priv = NULL; 115} 116EXPORT_SYMBOL(dss_uninstall_mgr_ops); 117 118void dss_mgr_set_timings(struct omap_dss_device *dssdev, 119 const struct videomode *vm) 120{ 121 dssdev->dss->mgr_ops->set_timings(dssdev->dss->mgr_ops_priv, 122 dssdev->dispc_channel, vm); 123} 124EXPORT_SYMBOL(dss_mgr_set_timings); 125 126void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, 127 const struct dss_lcd_mgr_config *config) 128{ 129 dssdev->dss->mgr_ops->set_lcd_config(dssdev->dss->mgr_ops_priv, 130 dssdev->dispc_channel, config); 131} 132EXPORT_SYMBOL(dss_mgr_set_lcd_config); 133 134int dss_mgr_enable(struct omap_dss_device *dssdev) 135{ 136 return dssdev->dss->mgr_ops->enable(dssdev->dss->mgr_ops_priv, 137 dssdev->dispc_channel); 138} 139EXPORT_SYMBOL(dss_mgr_enable); 140 141void dss_mgr_disable(struct omap_dss_device *dssdev) 142{ 143 dssdev->dss->mgr_ops->disable(dssdev->dss->mgr_ops_priv, 144 dssdev->dispc_channel); 145} 146EXPORT_SYMBOL(dss_mgr_disable); 147 148void dss_mgr_start_update(struct omap_dss_device *dssdev) 149{ 150 dssdev->dss->mgr_ops->start_update(dssdev->dss->mgr_ops_priv, 151 dssdev->dispc_channel); 152} 153EXPORT_SYMBOL(dss_mgr_start_update); 154 155int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, 156 void (*handler)(void *), void *data) 157{ 158 struct dss_device *dss = dssdev->dss; 159 160 return dss->mgr_ops->register_framedone_handler(dss->mgr_ops_priv, 161 dssdev->dispc_channel, 162 handler, data); 163} 164EXPORT_SYMBOL(dss_mgr_register_framedone_handler); 165 166void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, 167 void (*handler)(void *), void *data) 168{ 169 struct dss_device *dss = dssdev->dss; 170 171 dss->mgr_ops->unregister_framedone_handler(dss->mgr_ops_priv, 172 dssdev->dispc_channel, 173 handler, data); 174} 175EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); 176