root/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. atmel_hlcdc_encoder_to_rgb_output
  2. atmel_hlcdc_encoder_get_bus_fmt
  3. atmel_hlcdc_of_bus_fmt
  4. atmel_hlcdc_attach_endpoint
  5. atmel_hlcdc_create_outputs

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2014 Traphandler
   4  * Copyright (C) 2014 Free Electrons
   5  * Copyright (C) 2014 Atmel
   6  *
   7  * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
   8  * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
   9  */
  10 
  11 #include <linux/media-bus-format.h>
  12 #include <linux/of_graph.h>
  13 
  14 #include <drm/drm_encoder.h>
  15 #include <drm/drm_of.h>
  16 #include <drm/drm_bridge.h>
  17 
  18 #include "atmel_hlcdc_dc.h"
  19 
  20 struct atmel_hlcdc_rgb_output {
  21         struct drm_encoder encoder;
  22         int bus_fmt;
  23 };
  24 
  25 static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = {
  26         .destroy = drm_encoder_cleanup,
  27 };
  28 
  29 static struct atmel_hlcdc_rgb_output *
  30 atmel_hlcdc_encoder_to_rgb_output(struct drm_encoder *encoder)
  31 {
  32         return container_of(encoder, struct atmel_hlcdc_rgb_output, encoder);
  33 }
  34 
  35 int atmel_hlcdc_encoder_get_bus_fmt(struct drm_encoder *encoder)
  36 {
  37         struct atmel_hlcdc_rgb_output *output;
  38 
  39         output = atmel_hlcdc_encoder_to_rgb_output(encoder);
  40 
  41         return output->bus_fmt;
  42 }
  43 
  44 static int atmel_hlcdc_of_bus_fmt(const struct device_node *ep)
  45 {
  46         u32 bus_width;
  47         int ret;
  48 
  49         ret = of_property_read_u32(ep, "bus-width", &bus_width);
  50         if (ret == -EINVAL)
  51                 return 0;
  52         if (ret)
  53                 return ret;
  54 
  55         switch (bus_width) {
  56         case 12:
  57                 return MEDIA_BUS_FMT_RGB444_1X12;
  58         case 16:
  59                 return MEDIA_BUS_FMT_RGB565_1X16;
  60         case 18:
  61                 return MEDIA_BUS_FMT_RGB666_1X18;
  62         case 24:
  63                 return MEDIA_BUS_FMT_RGB888_1X24;
  64         default:
  65                 return -EINVAL;
  66         }
  67 }
  68 
  69 static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
  70 {
  71         struct atmel_hlcdc_rgb_output *output;
  72         struct device_node *ep;
  73         struct drm_panel *panel;
  74         struct drm_bridge *bridge;
  75         int ret;
  76 
  77         ep = of_graph_get_endpoint_by_regs(dev->dev->of_node, 0, endpoint);
  78         if (!ep)
  79                 return -ENODEV;
  80 
  81         ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 0, endpoint,
  82                                           &panel, &bridge);
  83         if (ret) {
  84                 of_node_put(ep);
  85                 return ret;
  86         }
  87 
  88         output = devm_kzalloc(dev->dev, sizeof(*output), GFP_KERNEL);
  89         if (!output) {
  90                 of_node_put(ep);
  91                 return -ENOMEM;
  92         }
  93 
  94         output->bus_fmt = atmel_hlcdc_of_bus_fmt(ep);
  95         of_node_put(ep);
  96         if (output->bus_fmt < 0) {
  97                 dev_err(dev->dev, "endpoint %d: invalid bus width\n", endpoint);
  98                 return -EINVAL;
  99         }
 100 
 101         ret = drm_encoder_init(dev, &output->encoder,
 102                                &atmel_hlcdc_panel_encoder_funcs,
 103                                DRM_MODE_ENCODER_NONE, NULL);
 104         if (ret)
 105                 return ret;
 106 
 107         output->encoder.possible_crtcs = 0x1;
 108 
 109         if (panel) {
 110                 bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_Unknown);
 111                 if (IS_ERR(bridge))
 112                         return PTR_ERR(bridge);
 113         }
 114 
 115         if (bridge) {
 116                 ret = drm_bridge_attach(&output->encoder, bridge, NULL);
 117                 if (!ret)
 118                         return 0;
 119 
 120                 if (panel)
 121                         drm_panel_bridge_remove(bridge);
 122         }
 123 
 124         drm_encoder_cleanup(&output->encoder);
 125 
 126         return ret;
 127 }
 128 
 129 int atmel_hlcdc_create_outputs(struct drm_device *dev)
 130 {
 131         int endpoint, ret = 0;
 132         int attached = 0;
 133 
 134         /*
 135          * Always scan the first few endpoints even if we get -ENODEV,
 136          * but keep going after that as long as we keep getting hits.
 137          */
 138         for (endpoint = 0; !ret || endpoint < 4; endpoint++) {
 139                 ret = atmel_hlcdc_attach_endpoint(dev, endpoint);
 140                 if (ret == -ENODEV)
 141                         continue;
 142                 if (ret)
 143                         break;
 144                 attached++;
 145         }
 146 
 147         /* At least one device was successfully attached.*/
 148         if (ret == -ENODEV && attached)
 149                 return 0;
 150 
 151         return ret;
 152 }

/* [<][>][^][v][top][bottom][index][help] */