11a396789SBoris Brezillon /* 21a396789SBoris Brezillon * Copyright (C) 2014 Traphandler 31a396789SBoris Brezillon * Copyright (C) 2014 Free Electrons 41a396789SBoris Brezillon * Copyright (C) 2014 Atmel 51a396789SBoris Brezillon * 61a396789SBoris Brezillon * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com> 71a396789SBoris Brezillon * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 81a396789SBoris Brezillon * 91a396789SBoris Brezillon * This program is free software; you can redistribute it and/or modify it 101a396789SBoris Brezillon * under the terms of the GNU General Public License version 2 as published by 111a396789SBoris Brezillon * the Free Software Foundation. 121a396789SBoris Brezillon * 131a396789SBoris Brezillon * This program is distributed in the hope that it will be useful, but WITHOUT 141a396789SBoris Brezillon * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 151a396789SBoris Brezillon * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 161a396789SBoris Brezillon * more details. 171a396789SBoris Brezillon * 181a396789SBoris Brezillon * You should have received a copy of the GNU General Public License along with 191a396789SBoris Brezillon * this program. If not, see <http://www.gnu.org/licenses/>. 201a396789SBoris Brezillon */ 211a396789SBoris Brezillon 221a396789SBoris Brezillon #include <linux/of_graph.h> 231a396789SBoris Brezillon 241a396789SBoris Brezillon #include <drm/drmP.h> 251a396789SBoris Brezillon #include <drm/drm_panel.h> 261a396789SBoris Brezillon 271a396789SBoris Brezillon #include "atmel_hlcdc_dc.h" 281a396789SBoris Brezillon 291a396789SBoris Brezillon /** 301a396789SBoris Brezillon * Atmel HLCDC RGB output mode 311a396789SBoris Brezillon */ 321a396789SBoris Brezillon enum atmel_hlcdc_connector_rgb_mode { 331a396789SBoris Brezillon ATMEL_HLCDC_CONNECTOR_RGB444, 341a396789SBoris Brezillon ATMEL_HLCDC_CONNECTOR_RGB565, 351a396789SBoris Brezillon ATMEL_HLCDC_CONNECTOR_RGB666, 361a396789SBoris Brezillon ATMEL_HLCDC_CONNECTOR_RGB888, 371a396789SBoris Brezillon }; 381a396789SBoris Brezillon 391a396789SBoris Brezillon /** 401a396789SBoris Brezillon * Atmel HLCDC RGB connector structure 411a396789SBoris Brezillon * 421a396789SBoris Brezillon * This structure stores RGB slave device information. 431a396789SBoris Brezillon * 441a396789SBoris Brezillon * @connector: DRM connector 451a396789SBoris Brezillon * @encoder: DRM encoder 461a396789SBoris Brezillon * @dc: pointer to the atmel_hlcdc_dc structure 471a396789SBoris Brezillon * @dpms: current DPMS mode 481a396789SBoris Brezillon */ 491a396789SBoris Brezillon struct atmel_hlcdc_rgb_output { 501a396789SBoris Brezillon struct drm_connector connector; 511a396789SBoris Brezillon struct drm_encoder encoder; 521a396789SBoris Brezillon struct atmel_hlcdc_dc *dc; 531a396789SBoris Brezillon int dpms; 541a396789SBoris Brezillon }; 551a396789SBoris Brezillon 561a396789SBoris Brezillon static inline struct atmel_hlcdc_rgb_output * 571a396789SBoris Brezillon drm_connector_to_atmel_hlcdc_rgb_output(struct drm_connector *connector) 581a396789SBoris Brezillon { 591a396789SBoris Brezillon return container_of(connector, struct atmel_hlcdc_rgb_output, 601a396789SBoris Brezillon connector); 611a396789SBoris Brezillon } 621a396789SBoris Brezillon 631a396789SBoris Brezillon static inline struct atmel_hlcdc_rgb_output * 641a396789SBoris Brezillon drm_encoder_to_atmel_hlcdc_rgb_output(struct drm_encoder *encoder) 651a396789SBoris Brezillon { 661a396789SBoris Brezillon return container_of(encoder, struct atmel_hlcdc_rgb_output, encoder); 671a396789SBoris Brezillon } 681a396789SBoris Brezillon 691a396789SBoris Brezillon /** 701a396789SBoris Brezillon * Atmel HLCDC Panel device structure 711a396789SBoris Brezillon * 721a396789SBoris Brezillon * This structure is specialization of the slave device structure to 731a396789SBoris Brezillon * interface with drm panels. 741a396789SBoris Brezillon * 751a396789SBoris Brezillon * @base: base slave device fields 761a396789SBoris Brezillon * @panel: drm panel attached to this slave device 771a396789SBoris Brezillon */ 781a396789SBoris Brezillon struct atmel_hlcdc_panel { 791a396789SBoris Brezillon struct atmel_hlcdc_rgb_output base; 801a396789SBoris Brezillon struct drm_panel *panel; 811a396789SBoris Brezillon }; 821a396789SBoris Brezillon 831a396789SBoris Brezillon static inline struct atmel_hlcdc_panel * 841a396789SBoris Brezillon atmel_hlcdc_rgb_output_to_panel(struct atmel_hlcdc_rgb_output *output) 851a396789SBoris Brezillon { 861a396789SBoris Brezillon return container_of(output, struct atmel_hlcdc_panel, base); 871a396789SBoris Brezillon } 881a396789SBoris Brezillon 892389fc13SBoris Brezillon static void atmel_hlcdc_panel_encoder_enable(struct drm_encoder *encoder) 901a396789SBoris Brezillon { 911a396789SBoris Brezillon struct atmel_hlcdc_rgb_output *rgb = 921a396789SBoris Brezillon drm_encoder_to_atmel_hlcdc_rgb_output(encoder); 931a396789SBoris Brezillon struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb); 941a396789SBoris Brezillon 951a396789SBoris Brezillon drm_panel_enable(panel->panel); 962389fc13SBoris Brezillon } 971a396789SBoris Brezillon 982389fc13SBoris Brezillon static void atmel_hlcdc_panel_encoder_disable(struct drm_encoder *encoder) 992389fc13SBoris Brezillon { 1002389fc13SBoris Brezillon struct atmel_hlcdc_rgb_output *rgb = 1012389fc13SBoris Brezillon drm_encoder_to_atmel_hlcdc_rgb_output(encoder); 1022389fc13SBoris Brezillon struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb); 1032389fc13SBoris Brezillon 1042389fc13SBoris Brezillon drm_panel_disable(panel->panel); 1051a396789SBoris Brezillon } 1061a396789SBoris Brezillon 1071a396789SBoris Brezillon static bool 1081a396789SBoris Brezillon atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder, 1091a396789SBoris Brezillon const struct drm_display_mode *mode, 1101a396789SBoris Brezillon struct drm_display_mode *adjusted) 1111a396789SBoris Brezillon { 1121a396789SBoris Brezillon return true; 1131a396789SBoris Brezillon } 1141a396789SBoris Brezillon 1151a396789SBoris Brezillon static void 1161a396789SBoris Brezillon atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder, 1171a396789SBoris Brezillon struct drm_display_mode *mode, 1181a396789SBoris Brezillon struct drm_display_mode *adjusted) 1191a396789SBoris Brezillon { 1201a396789SBoris Brezillon struct atmel_hlcdc_rgb_output *rgb = 1211a396789SBoris Brezillon drm_encoder_to_atmel_hlcdc_rgb_output(encoder); 1221a396789SBoris Brezillon struct drm_display_info *info = &rgb->connector.display_info; 1231a396789SBoris Brezillon unsigned int cfg; 1241a396789SBoris Brezillon 1251a396789SBoris Brezillon cfg = 0; 1261a396789SBoris Brezillon 1271a396789SBoris Brezillon if (info->num_bus_formats) { 1281a396789SBoris Brezillon switch (info->bus_formats[0]) { 129923f8698SBoris Brezillon case MEDIA_BUS_FMT_RGB565_1X16: 130923f8698SBoris Brezillon cfg |= ATMEL_HLCDC_CONNECTOR_RGB565 << 8; 131923f8698SBoris Brezillon break; 1321a396789SBoris Brezillon case MEDIA_BUS_FMT_RGB666_1X18: 1331a396789SBoris Brezillon cfg |= ATMEL_HLCDC_CONNECTOR_RGB666 << 8; 1341a396789SBoris Brezillon break; 1351a396789SBoris Brezillon case MEDIA_BUS_FMT_RGB888_1X24: 1361a396789SBoris Brezillon cfg |= ATMEL_HLCDC_CONNECTOR_RGB888 << 8; 1371a396789SBoris Brezillon break; 138923f8698SBoris Brezillon case MEDIA_BUS_FMT_RGB444_1X12: 1391a396789SBoris Brezillon default: 1401a396789SBoris Brezillon break; 1411a396789SBoris Brezillon } 1421a396789SBoris Brezillon } 1431a396789SBoris Brezillon 1441a396789SBoris Brezillon regmap_update_bits(rgb->dc->hlcdc->regmap, ATMEL_HLCDC_CFG(5), 1451a396789SBoris Brezillon ATMEL_HLCDC_MODE_MASK, 1461a396789SBoris Brezillon cfg); 1471a396789SBoris Brezillon } 1481a396789SBoris Brezillon 149e9becd46SVille Syrjälä static const struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = { 1501a396789SBoris Brezillon .mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup, 1511a396789SBoris Brezillon .mode_set = atmel_hlcdc_rgb_encoder_mode_set, 1522389fc13SBoris Brezillon .disable = atmel_hlcdc_panel_encoder_disable, 1532389fc13SBoris Brezillon .enable = atmel_hlcdc_panel_encoder_enable, 1541a396789SBoris Brezillon }; 1551a396789SBoris Brezillon 1561a396789SBoris Brezillon static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder) 1571a396789SBoris Brezillon { 1581a396789SBoris Brezillon drm_encoder_cleanup(encoder); 1591a396789SBoris Brezillon memset(encoder, 0, sizeof(*encoder)); 1601a396789SBoris Brezillon } 1611a396789SBoris Brezillon 1621a396789SBoris Brezillon static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = { 1631a396789SBoris Brezillon .destroy = atmel_hlcdc_rgb_encoder_destroy, 1641a396789SBoris Brezillon }; 1651a396789SBoris Brezillon 1661a396789SBoris Brezillon static int atmel_hlcdc_panel_get_modes(struct drm_connector *connector) 1671a396789SBoris Brezillon { 1681a396789SBoris Brezillon struct atmel_hlcdc_rgb_output *rgb = 1691a396789SBoris Brezillon drm_connector_to_atmel_hlcdc_rgb_output(connector); 1701a396789SBoris Brezillon struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb); 1711a396789SBoris Brezillon 1721a396789SBoris Brezillon return panel->panel->funcs->get_modes(panel->panel); 1731a396789SBoris Brezillon } 1741a396789SBoris Brezillon 1751a396789SBoris Brezillon static int atmel_hlcdc_rgb_mode_valid(struct drm_connector *connector, 1761a396789SBoris Brezillon struct drm_display_mode *mode) 1771a396789SBoris Brezillon { 1781a396789SBoris Brezillon struct atmel_hlcdc_rgb_output *rgb = 1791a396789SBoris Brezillon drm_connector_to_atmel_hlcdc_rgb_output(connector); 1801a396789SBoris Brezillon 1811a396789SBoris Brezillon return atmel_hlcdc_dc_mode_valid(rgb->dc, mode); 1821a396789SBoris Brezillon } 1831a396789SBoris Brezillon 1841a396789SBoris Brezillon 1851a396789SBoris Brezillon 1861a396789SBoris Brezillon static struct drm_encoder * 1871a396789SBoris Brezillon atmel_hlcdc_rgb_best_encoder(struct drm_connector *connector) 1881a396789SBoris Brezillon { 1891a396789SBoris Brezillon struct atmel_hlcdc_rgb_output *rgb = 1901a396789SBoris Brezillon drm_connector_to_atmel_hlcdc_rgb_output(connector); 1911a396789SBoris Brezillon 1921a396789SBoris Brezillon return &rgb->encoder; 1931a396789SBoris Brezillon } 1941a396789SBoris Brezillon 195e9becd46SVille Syrjälä static const struct drm_connector_helper_funcs atmel_hlcdc_panel_connector_helper_funcs = { 1961a396789SBoris Brezillon .get_modes = atmel_hlcdc_panel_get_modes, 1971a396789SBoris Brezillon .mode_valid = atmel_hlcdc_rgb_mode_valid, 1981a396789SBoris Brezillon .best_encoder = atmel_hlcdc_rgb_best_encoder, 1991a396789SBoris Brezillon }; 2001a396789SBoris Brezillon 2011a396789SBoris Brezillon static enum drm_connector_status 2021a396789SBoris Brezillon atmel_hlcdc_panel_connector_detect(struct drm_connector *connector, bool force) 2031a396789SBoris Brezillon { 2041a396789SBoris Brezillon return connector_status_connected; 2051a396789SBoris Brezillon } 2061a396789SBoris Brezillon 2071a396789SBoris Brezillon static void 2081a396789SBoris Brezillon atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector) 2091a396789SBoris Brezillon { 2101a396789SBoris Brezillon struct atmel_hlcdc_rgb_output *rgb = 2111a396789SBoris Brezillon drm_connector_to_atmel_hlcdc_rgb_output(connector); 2121a396789SBoris Brezillon struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb); 2131a396789SBoris Brezillon 2141a396789SBoris Brezillon drm_panel_detach(panel->panel); 2151a396789SBoris Brezillon drm_connector_cleanup(connector); 2161a396789SBoris Brezillon } 2171a396789SBoris Brezillon 2181a396789SBoris Brezillon static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = { 2192389fc13SBoris Brezillon .dpms = drm_atomic_helper_connector_dpms, 2201a396789SBoris Brezillon .detect = atmel_hlcdc_panel_connector_detect, 2211a396789SBoris Brezillon .fill_modes = drm_helper_probe_single_connector_modes, 2221a396789SBoris Brezillon .destroy = atmel_hlcdc_panel_connector_destroy, 2232389fc13SBoris Brezillon .reset = drm_atomic_helper_connector_reset, 2242389fc13SBoris Brezillon .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 2252389fc13SBoris Brezillon .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 2261a396789SBoris Brezillon }; 2271a396789SBoris Brezillon 2281a396789SBoris Brezillon static int atmel_hlcdc_create_panel_output(struct drm_device *dev, 2291a396789SBoris Brezillon struct of_endpoint *ep) 2301a396789SBoris Brezillon { 2311a396789SBoris Brezillon struct atmel_hlcdc_dc *dc = dev->dev_private; 2321a396789SBoris Brezillon struct device_node *np; 2331a396789SBoris Brezillon struct drm_panel *p = NULL; 2341a396789SBoris Brezillon struct atmel_hlcdc_panel *panel; 2351a396789SBoris Brezillon int ret; 2361a396789SBoris Brezillon 2371a396789SBoris Brezillon np = of_graph_get_remote_port_parent(ep->local_node); 2381a396789SBoris Brezillon if (!np) 2391a396789SBoris Brezillon return -EINVAL; 2401a396789SBoris Brezillon 2411a396789SBoris Brezillon p = of_drm_find_panel(np); 2421a396789SBoris Brezillon of_node_put(np); 2431a396789SBoris Brezillon 2441a396789SBoris Brezillon if (!p) 2451a396789SBoris Brezillon return -EPROBE_DEFER; 2461a396789SBoris Brezillon 2471a396789SBoris Brezillon panel = devm_kzalloc(dev->dev, sizeof(*panel), GFP_KERNEL); 2481a396789SBoris Brezillon if (!panel) 2491a396789SBoris Brezillon return -EINVAL; 2501a396789SBoris Brezillon 2511a396789SBoris Brezillon panel->base.dpms = DRM_MODE_DPMS_OFF; 2521a396789SBoris Brezillon 2531a396789SBoris Brezillon panel->base.dc = dc; 2541a396789SBoris Brezillon 2551a396789SBoris Brezillon drm_encoder_helper_add(&panel->base.encoder, 2561a396789SBoris Brezillon &atmel_hlcdc_panel_encoder_helper_funcs); 2571a396789SBoris Brezillon ret = drm_encoder_init(dev, &panel->base.encoder, 2581a396789SBoris Brezillon &atmel_hlcdc_panel_encoder_funcs, 259*abfc936eSBoris Brezillon DRM_MODE_ENCODER_NONE, NULL); 2601a396789SBoris Brezillon if (ret) 2611a396789SBoris Brezillon return ret; 2621a396789SBoris Brezillon 2631a396789SBoris Brezillon panel->base.connector.dpms = DRM_MODE_DPMS_OFF; 2641a396789SBoris Brezillon panel->base.connector.polled = DRM_CONNECTOR_POLL_CONNECT; 2651a396789SBoris Brezillon drm_connector_helper_add(&panel->base.connector, 2661a396789SBoris Brezillon &atmel_hlcdc_panel_connector_helper_funcs); 2671a396789SBoris Brezillon ret = drm_connector_init(dev, &panel->base.connector, 2681a396789SBoris Brezillon &atmel_hlcdc_panel_connector_funcs, 269*abfc936eSBoris Brezillon DRM_MODE_CONNECTOR_Unknown); 2701a396789SBoris Brezillon if (ret) 2711a396789SBoris Brezillon goto err_encoder_cleanup; 2721a396789SBoris Brezillon 2731a396789SBoris Brezillon drm_mode_connector_attach_encoder(&panel->base.connector, 2741a396789SBoris Brezillon &panel->base.encoder); 2751a396789SBoris Brezillon panel->base.encoder.possible_crtcs = 0x1; 2761a396789SBoris Brezillon 2771a396789SBoris Brezillon drm_panel_attach(p, &panel->base.connector); 2781a396789SBoris Brezillon panel->panel = p; 2791a396789SBoris Brezillon 2801a396789SBoris Brezillon return 0; 2811a396789SBoris Brezillon 2821a396789SBoris Brezillon err_encoder_cleanup: 2831a396789SBoris Brezillon drm_encoder_cleanup(&panel->base.encoder); 2841a396789SBoris Brezillon 2851a396789SBoris Brezillon return ret; 2861a396789SBoris Brezillon } 2871a396789SBoris Brezillon 2881a396789SBoris Brezillon int atmel_hlcdc_create_outputs(struct drm_device *dev) 2891a396789SBoris Brezillon { 2901a396789SBoris Brezillon struct device_node *port_np, *np; 2911a396789SBoris Brezillon struct of_endpoint ep; 2921a396789SBoris Brezillon int ret; 2931a396789SBoris Brezillon 2941a396789SBoris Brezillon port_np = of_get_child_by_name(dev->dev->of_node, "port"); 2951a396789SBoris Brezillon if (!port_np) 2961a396789SBoris Brezillon return -EINVAL; 2971a396789SBoris Brezillon 2981a396789SBoris Brezillon np = of_get_child_by_name(port_np, "endpoint"); 2991a396789SBoris Brezillon of_node_put(port_np); 3001a396789SBoris Brezillon 3011a396789SBoris Brezillon if (!np) 3021a396789SBoris Brezillon return -EINVAL; 3031a396789SBoris Brezillon 3041a396789SBoris Brezillon ret = of_graph_parse_endpoint(np, &ep); 3051a396789SBoris Brezillon of_node_put(port_np); 3061a396789SBoris Brezillon 3071a396789SBoris Brezillon if (ret) 3081a396789SBoris Brezillon return ret; 3091a396789SBoris Brezillon 3101a396789SBoris Brezillon /* We currently only support panel output */ 3111a396789SBoris Brezillon return atmel_hlcdc_create_panel_output(dev, &ep); 3121a396789SBoris Brezillon } 313