1 /* 2 * Copyright (C) 2014 Traphandler 3 * Copyright (C) 2014 Free Electrons 4 * Copyright (C) 2014 Atmel 5 * 6 * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com> 7 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License version 2 as published by 11 * the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 16 * more details. 17 * 18 * You should have received a copy of the GNU General Public License along with 19 * this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #include <linux/of_graph.h> 23 24 #include <drm/drmP.h> 25 #include <drm/drm_of.h> 26 #include <drm/drm_bridge.h> 27 28 #include "atmel_hlcdc_dc.h" 29 30 static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = { 31 .destroy = drm_encoder_cleanup, 32 }; 33 34 static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint) 35 { 36 struct drm_encoder *encoder; 37 struct drm_panel *panel; 38 struct drm_bridge *bridge; 39 int ret; 40 41 ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint, 42 &panel, &bridge); 43 if (ret) 44 return ret; 45 46 encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL); 47 if (!encoder) 48 return -EINVAL; 49 50 ret = drm_encoder_init(dev, encoder, 51 &atmel_hlcdc_panel_encoder_funcs, 52 DRM_MODE_ENCODER_NONE, NULL); 53 if (ret) 54 return ret; 55 56 encoder->possible_crtcs = 0x1; 57 58 if (panel) { 59 bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_Unknown); 60 if (IS_ERR(bridge)) 61 return PTR_ERR(bridge); 62 } 63 64 if (bridge) { 65 ret = drm_bridge_attach(encoder, bridge, NULL); 66 if (!ret) 67 return 0; 68 69 if (panel) 70 drm_panel_bridge_remove(bridge); 71 } 72 73 drm_encoder_cleanup(encoder); 74 75 return ret; 76 } 77 78 int atmel_hlcdc_create_outputs(struct drm_device *dev) 79 { 80 int endpoint, ret = 0; 81 82 for (endpoint = 0; !ret; endpoint++) 83 ret = atmel_hlcdc_attach_endpoint(dev, endpoint); 84 85 /* At least one device was successfully attached.*/ 86 if (ret == -ENODEV && endpoint) 87 return 0; 88 89 return ret; 90 } 91