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