root/drivers/gpu/drm/vc4/vc4_dpi.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_vc4_dpi_encoder
  2. vc4_dpi_encoder_disable
  3. vc4_dpi_encoder_enable
  4. vc4_dpi_encoder_mode_valid
  5. vc4_dpi_init_bridge
  6. vc4_dpi_bind
  7. vc4_dpi_unbind
  8. vc4_dpi_dev_probe
  9. vc4_dpi_dev_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2016 Broadcom Limited
   4  */
   5 
   6 /**
   7  * DOC: VC4 DPI module
   8  *
   9  * The VC4 DPI hardware supports MIPI DPI type 4 and Nokia ViSSI
  10  * signals.  On BCM2835, these can be routed out to GPIO0-27 with the
  11  * ALT2 function.
  12  */
  13 
  14 #include <drm/drm_atomic_helper.h>
  15 #include <drm/drm_bridge.h>
  16 #include <drm/drm_edid.h>
  17 #include <drm/drm_of.h>
  18 #include <drm/drm_panel.h>
  19 #include <drm/drm_probe_helper.h>
  20 #include <linux/clk.h>
  21 #include <linux/component.h>
  22 #include <linux/of_graph.h>
  23 #include <linux/of_platform.h>
  24 #include "vc4_drv.h"
  25 #include "vc4_regs.h"
  26 
  27 #define DPI_C                   0x00
  28 # define DPI_OUTPUT_ENABLE_MODE         BIT(16)
  29 
  30 /* The order field takes the incoming 24 bit RGB from the pixel valve
  31  * and shuffles the 3 channels.
  32  */
  33 # define DPI_ORDER_MASK                 VC4_MASK(15, 14)
  34 # define DPI_ORDER_SHIFT                14
  35 # define DPI_ORDER_RGB                  0
  36 # define DPI_ORDER_BGR                  1
  37 # define DPI_ORDER_GRB                  2
  38 # define DPI_ORDER_BRG                  3
  39 
  40 /* The format field takes the ORDER-shuffled pixel valve data and
  41  * formats it onto the output lines.
  42  */
  43 # define DPI_FORMAT_MASK                VC4_MASK(13, 11)
  44 # define DPI_FORMAT_SHIFT               11
  45 /* This define is named in the hardware, but actually just outputs 0. */
  46 # define DPI_FORMAT_9BIT_666_RGB        0
  47 /* Outputs 00000000rrrrrggggggbbbbb */
  48 # define DPI_FORMAT_16BIT_565_RGB_1     1
  49 /* Outputs 000rrrrr00gggggg000bbbbb */
  50 # define DPI_FORMAT_16BIT_565_RGB_2     2
  51 /* Outputs 00rrrrr000gggggg00bbbbb0 */
  52 # define DPI_FORMAT_16BIT_565_RGB_3     3
  53 /* Outputs 000000rrrrrrggggggbbbbbb */
  54 # define DPI_FORMAT_18BIT_666_RGB_1     4
  55 /* Outputs 00rrrrrr00gggggg00bbbbbb */
  56 # define DPI_FORMAT_18BIT_666_RGB_2     5
  57 /* Outputs rrrrrrrrggggggggbbbbbbbb */
  58 # define DPI_FORMAT_24BIT_888_RGB       6
  59 
  60 /* Reverses the polarity of the corresponding signal */
  61 # define DPI_PIXEL_CLK_INVERT           BIT(10)
  62 # define DPI_HSYNC_INVERT               BIT(9)
  63 # define DPI_VSYNC_INVERT               BIT(8)
  64 # define DPI_OUTPUT_ENABLE_INVERT       BIT(7)
  65 
  66 /* Outputs the signal the falling clock edge instead of rising. */
  67 # define DPI_HSYNC_NEGATE               BIT(6)
  68 # define DPI_VSYNC_NEGATE               BIT(5)
  69 # define DPI_OUTPUT_ENABLE_NEGATE       BIT(4)
  70 
  71 /* Disables the signal */
  72 # define DPI_HSYNC_DISABLE              BIT(3)
  73 # define DPI_VSYNC_DISABLE              BIT(2)
  74 # define DPI_OUTPUT_ENABLE_DISABLE      BIT(1)
  75 
  76 /* Power gate to the device, full reset at 0 -> 1 transition */
  77 # define DPI_ENABLE                     BIT(0)
  78 
  79 /* All other registers besides DPI_C return the ID */
  80 #define DPI_ID                  0x04
  81 # define DPI_ID_VALUE           0x00647069
  82 
  83 /* General DPI hardware state. */
  84 struct vc4_dpi {
  85         struct platform_device *pdev;
  86 
  87         struct drm_encoder *encoder;
  88 
  89         void __iomem *regs;
  90 
  91         struct clk *pixel_clock;
  92         struct clk *core_clock;
  93 
  94         struct debugfs_regset32 regset;
  95 };
  96 
  97 #define DPI_READ(offset) readl(dpi->regs + (offset))
  98 #define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset))
  99 
 100 /* VC4 DPI encoder KMS struct */
 101 struct vc4_dpi_encoder {
 102         struct vc4_encoder base;
 103         struct vc4_dpi *dpi;
 104 };
 105 
 106 static inline struct vc4_dpi_encoder *
 107 to_vc4_dpi_encoder(struct drm_encoder *encoder)
 108 {
 109         return container_of(encoder, struct vc4_dpi_encoder, base.base);
 110 }
 111 
 112 static const struct debugfs_reg32 dpi_regs[] = {
 113         VC4_REG32(DPI_C),
 114         VC4_REG32(DPI_ID),
 115 };
 116 
 117 static const struct drm_encoder_funcs vc4_dpi_encoder_funcs = {
 118         .destroy = drm_encoder_cleanup,
 119 };
 120 
 121 static void vc4_dpi_encoder_disable(struct drm_encoder *encoder)
 122 {
 123         struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder);
 124         struct vc4_dpi *dpi = vc4_encoder->dpi;
 125 
 126         clk_disable_unprepare(dpi->pixel_clock);
 127 }
 128 
 129 static void vc4_dpi_encoder_enable(struct drm_encoder *encoder)
 130 {
 131         struct drm_device *dev = encoder->dev;
 132         struct drm_display_mode *mode = &encoder->crtc->mode;
 133         struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder);
 134         struct vc4_dpi *dpi = vc4_encoder->dpi;
 135         struct drm_connector_list_iter conn_iter;
 136         struct drm_connector *connector = NULL, *connector_scan;
 137         u32 dpi_c = DPI_ENABLE | DPI_OUTPUT_ENABLE_MODE;
 138         int ret;
 139 
 140         /* Look up the connector attached to DPI so we can get the
 141          * bus_format.  Ideally the bridge would tell us the
 142          * bus_format we want, but it doesn't yet, so assume that it's
 143          * uniform throughout the bridge chain.
 144          */
 145         drm_connector_list_iter_begin(dev, &conn_iter);
 146         drm_for_each_connector_iter(connector_scan, &conn_iter) {
 147                 if (connector_scan->encoder == encoder) {
 148                         connector = connector_scan;
 149                         break;
 150                 }
 151         }
 152         drm_connector_list_iter_end(&conn_iter);
 153 
 154         if (connector && connector->display_info.num_bus_formats) {
 155                 u32 bus_format = connector->display_info.bus_formats[0];
 156 
 157                 switch (bus_format) {
 158                 case MEDIA_BUS_FMT_RGB888_1X24:
 159                         dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB,
 160                                                DPI_FORMAT);
 161                         break;
 162                 case MEDIA_BUS_FMT_BGR888_1X24:
 163                         dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB,
 164                                                DPI_FORMAT);
 165                         dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER);
 166                         break;
 167                 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
 168                         dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2,
 169                                                DPI_FORMAT);
 170                         break;
 171                 case MEDIA_BUS_FMT_RGB666_1X18:
 172                         dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1,
 173                                                DPI_FORMAT);
 174                         break;
 175                 case MEDIA_BUS_FMT_RGB565_1X16:
 176                         dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3,
 177                                                DPI_FORMAT);
 178                         break;
 179                 default:
 180                         DRM_ERROR("Unknown media bus format %d\n", bus_format);
 181                         break;
 182                 }
 183         } else {
 184                 /* Default to 24bit if no connector found. */
 185                 dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, DPI_FORMAT);
 186         }
 187 
 188         if (mode->flags & DRM_MODE_FLAG_NHSYNC)
 189                 dpi_c |= DPI_HSYNC_INVERT;
 190         else if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
 191                 dpi_c |= DPI_HSYNC_DISABLE;
 192 
 193         if (mode->flags & DRM_MODE_FLAG_NVSYNC)
 194                 dpi_c |= DPI_VSYNC_INVERT;
 195         else if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
 196                 dpi_c |= DPI_VSYNC_DISABLE;
 197 
 198         DPI_WRITE(DPI_C, dpi_c);
 199 
 200         ret = clk_set_rate(dpi->pixel_clock, mode->clock * 1000);
 201         if (ret)
 202                 DRM_ERROR("Failed to set clock rate: %d\n", ret);
 203 
 204         ret = clk_prepare_enable(dpi->pixel_clock);
 205         if (ret)
 206                 DRM_ERROR("Failed to set clock rate: %d\n", ret);
 207 }
 208 
 209 static enum drm_mode_status vc4_dpi_encoder_mode_valid(struct drm_encoder *encoder,
 210                                                        const struct drm_display_mode *mode)
 211 {
 212         if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 213                 return MODE_NO_INTERLACE;
 214 
 215         return MODE_OK;
 216 }
 217 
 218 static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = {
 219         .disable = vc4_dpi_encoder_disable,
 220         .enable = vc4_dpi_encoder_enable,
 221         .mode_valid = vc4_dpi_encoder_mode_valid,
 222 };
 223 
 224 static const struct of_device_id vc4_dpi_dt_match[] = {
 225         { .compatible = "brcm,bcm2835-dpi", .data = NULL },
 226         {}
 227 };
 228 
 229 /* Sets up the next link in the display chain, whether it's a panel or
 230  * a bridge.
 231  */
 232 static int vc4_dpi_init_bridge(struct vc4_dpi *dpi)
 233 {
 234         struct device *dev = &dpi->pdev->dev;
 235         struct drm_panel *panel;
 236         struct drm_bridge *bridge;
 237         int ret;
 238 
 239         ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
 240                                           &panel, &bridge);
 241         if (ret) {
 242                 /* If nothing was connected in the DT, that's not an
 243                  * error.
 244                  */
 245                 if (ret == -ENODEV)
 246                         return 0;
 247                 else
 248                         return ret;
 249         }
 250 
 251         if (panel)
 252                 bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DPI);
 253 
 254         return drm_bridge_attach(dpi->encoder, bridge, NULL);
 255 }
 256 
 257 static int vc4_dpi_bind(struct device *dev, struct device *master, void *data)
 258 {
 259         struct platform_device *pdev = to_platform_device(dev);
 260         struct drm_device *drm = dev_get_drvdata(master);
 261         struct vc4_dev *vc4 = to_vc4_dev(drm);
 262         struct vc4_dpi *dpi;
 263         struct vc4_dpi_encoder *vc4_dpi_encoder;
 264         int ret;
 265 
 266         dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
 267         if (!dpi)
 268                 return -ENOMEM;
 269 
 270         vc4_dpi_encoder = devm_kzalloc(dev, sizeof(*vc4_dpi_encoder),
 271                                        GFP_KERNEL);
 272         if (!vc4_dpi_encoder)
 273                 return -ENOMEM;
 274         vc4_dpi_encoder->base.type = VC4_ENCODER_TYPE_DPI;
 275         vc4_dpi_encoder->dpi = dpi;
 276         dpi->encoder = &vc4_dpi_encoder->base.base;
 277 
 278         dpi->pdev = pdev;
 279         dpi->regs = vc4_ioremap_regs(pdev, 0);
 280         if (IS_ERR(dpi->regs))
 281                 return PTR_ERR(dpi->regs);
 282         dpi->regset.base = dpi->regs;
 283         dpi->regset.regs = dpi_regs;
 284         dpi->regset.nregs = ARRAY_SIZE(dpi_regs);
 285 
 286         if (DPI_READ(DPI_ID) != DPI_ID_VALUE) {
 287                 dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n",
 288                         DPI_READ(DPI_ID), DPI_ID_VALUE);
 289                 return -ENODEV;
 290         }
 291 
 292         dpi->core_clock = devm_clk_get(dev, "core");
 293         if (IS_ERR(dpi->core_clock)) {
 294                 ret = PTR_ERR(dpi->core_clock);
 295                 if (ret != -EPROBE_DEFER)
 296                         DRM_ERROR("Failed to get core clock: %d\n", ret);
 297                 return ret;
 298         }
 299         dpi->pixel_clock = devm_clk_get(dev, "pixel");
 300         if (IS_ERR(dpi->pixel_clock)) {
 301                 ret = PTR_ERR(dpi->pixel_clock);
 302                 if (ret != -EPROBE_DEFER)
 303                         DRM_ERROR("Failed to get pixel clock: %d\n", ret);
 304                 return ret;
 305         }
 306 
 307         ret = clk_prepare_enable(dpi->core_clock);
 308         if (ret)
 309                 DRM_ERROR("Failed to turn on core clock: %d\n", ret);
 310 
 311         drm_encoder_init(drm, dpi->encoder, &vc4_dpi_encoder_funcs,
 312                          DRM_MODE_ENCODER_DPI, NULL);
 313         drm_encoder_helper_add(dpi->encoder, &vc4_dpi_encoder_helper_funcs);
 314 
 315         ret = vc4_dpi_init_bridge(dpi);
 316         if (ret)
 317                 goto err_destroy_encoder;
 318 
 319         dev_set_drvdata(dev, dpi);
 320 
 321         vc4->dpi = dpi;
 322 
 323         vc4_debugfs_add_regset32(drm, "dpi_regs", &dpi->regset);
 324 
 325         return 0;
 326 
 327 err_destroy_encoder:
 328         drm_encoder_cleanup(dpi->encoder);
 329         clk_disable_unprepare(dpi->core_clock);
 330         return ret;
 331 }
 332 
 333 static void vc4_dpi_unbind(struct device *dev, struct device *master,
 334                            void *data)
 335 {
 336         struct drm_device *drm = dev_get_drvdata(master);
 337         struct vc4_dev *vc4 = to_vc4_dev(drm);
 338         struct vc4_dpi *dpi = dev_get_drvdata(dev);
 339 
 340         drm_of_panel_bridge_remove(dev->of_node, 0, 0);
 341 
 342         drm_encoder_cleanup(dpi->encoder);
 343 
 344         clk_disable_unprepare(dpi->core_clock);
 345 
 346         vc4->dpi = NULL;
 347 }
 348 
 349 static const struct component_ops vc4_dpi_ops = {
 350         .bind   = vc4_dpi_bind,
 351         .unbind = vc4_dpi_unbind,
 352 };
 353 
 354 static int vc4_dpi_dev_probe(struct platform_device *pdev)
 355 {
 356         return component_add(&pdev->dev, &vc4_dpi_ops);
 357 }
 358 
 359 static int vc4_dpi_dev_remove(struct platform_device *pdev)
 360 {
 361         component_del(&pdev->dev, &vc4_dpi_ops);
 362         return 0;
 363 }
 364 
 365 struct platform_driver vc4_dpi_driver = {
 366         .probe = vc4_dpi_dev_probe,
 367         .remove = vc4_dpi_dev_remove,
 368         .driver = {
 369                 .name = "vc4_dpi",
 370                 .of_match_table = vc4_dpi_dt_match,
 371         },
 372 };

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