linux/drivers/gpu/drm/pl111/pl111_drv.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
   4 *
   5 * Parts of this file were based on sources as follows:
   6 *
   7 * Copyright (c) 2006-2008 Intel Corporation
   8 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
   9 * Copyright (C) 2011 Texas Instruments
  10 */
  11
  12/**
  13 * DOC: ARM PrimeCell PL110 and PL111 CLCD Driver
  14 *
  15 * The PL110/PL111 is a simple LCD controller that can support TFT
  16 * and STN displays. This driver exposes a standard KMS interface
  17 * for them.
  18 *
  19 * The driver currently doesn't expose the cursor.  The DRM API for
  20 * cursors requires support for 64x64 ARGB8888 cursor images, while
  21 * the hardware can only support 64x64 monochrome with masking
  22 * cursors.  While one could imagine trying to hack something together
  23 * to look at the ARGB8888 and program reasonable in monochrome, we
  24 * just don't expose the cursor at all instead, and leave cursor
  25 * support to the application software cursor layer.
  26 *
  27 * TODO:
  28 *
  29 * - Fix race between setting plane base address and getting IRQ for
  30 *   vsync firing the pageflip completion.
  31 *
  32 * - Read back hardware state at boot to skip reprogramming the
  33 *   hardware when doing a no-op modeset.
  34 *
  35 * - Use the CLKSEL bit to support switching between the two external
  36 *   clock parents.
  37 */
  38
  39#include <linux/amba/bus.h>
  40#include <linux/dma-buf.h>
  41#include <linux/module.h>
  42#include <linux/of.h>
  43#include <linux/of_graph.h>
  44#include <linux/of_reserved_mem.h>
  45#include <linux/shmem_fs.h>
  46#include <linux/slab.h>
  47
  48#include <drm/drm_atomic_helper.h>
  49#include <drm/drm_bridge.h>
  50#include <drm/drm_drv.h>
  51#include <drm/drm_fb_cma_helper.h>
  52#include <drm/drm_fb_helper.h>
  53#include <drm/drm_gem_cma_helper.h>
  54#include <drm/drm_gem_framebuffer_helper.h>
  55#include <drm/drm_of.h>
  56#include <drm/drm_panel.h>
  57#include <drm/drm_probe_helper.h>
  58#include <drm/drm_vblank.h>
  59
  60#include "pl111_drm.h"
  61#include "pl111_versatile.h"
  62#include "pl111_nomadik.h"
  63
  64#define DRIVER_DESC      "DRM module for PL111"
  65
  66static const struct drm_mode_config_funcs mode_config_funcs = {
  67        .fb_create = drm_gem_fb_create,
  68        .atomic_check = drm_atomic_helper_check,
  69        .atomic_commit = drm_atomic_helper_commit,
  70};
  71
  72static int pl111_modeset_init(struct drm_device *dev)
  73{
  74        struct drm_mode_config *mode_config;
  75        struct pl111_drm_dev_private *priv = dev->dev_private;
  76        struct device_node *np = dev->dev->of_node;
  77        struct device_node *remote;
  78        struct drm_panel *panel = NULL;
  79        struct drm_bridge *bridge = NULL;
  80        bool defer = false;
  81        int ret;
  82        int i;
  83
  84        ret = drmm_mode_config_init(dev);
  85        if (ret)
  86                return ret;
  87
  88        mode_config = &dev->mode_config;
  89        mode_config->funcs = &mode_config_funcs;
  90        mode_config->min_width = 1;
  91        mode_config->max_width = 1024;
  92        mode_config->min_height = 1;
  93        mode_config->max_height = 768;
  94
  95        i = 0;
  96        for_each_endpoint_of_node(np, remote) {
  97                struct drm_panel *tmp_panel;
  98                struct drm_bridge *tmp_bridge;
  99
 100                dev_dbg(dev->dev, "checking endpoint %d\n", i);
 101
 102                ret = drm_of_find_panel_or_bridge(dev->dev->of_node,
 103                                                  0, i,
 104                                                  &tmp_panel,
 105                                                  &tmp_bridge);
 106                if (ret) {
 107                        if (ret == -EPROBE_DEFER) {
 108                                /*
 109                                 * Something deferred, but that is often just
 110                                 * another way of saying -ENODEV, but let's
 111                                 * cast a vote for later deferral.
 112                                 */
 113                                defer = true;
 114                        } else if (ret != -ENODEV) {
 115                                /* Continue, maybe something else is working */
 116                                dev_err(dev->dev,
 117                                        "endpoint %d returns %d\n", i, ret);
 118                        }
 119                }
 120
 121                if (tmp_panel) {
 122                        dev_info(dev->dev,
 123                                 "found panel on endpoint %d\n", i);
 124                        panel = tmp_panel;
 125                }
 126                if (tmp_bridge) {
 127                        dev_info(dev->dev,
 128                                 "found bridge on endpoint %d\n", i);
 129                        bridge = tmp_bridge;
 130                }
 131
 132                i++;
 133        }
 134
 135        /*
 136         * If we can't find neither panel nor bridge on any of the
 137         * endpoints, and any of them retured -EPROBE_DEFER, then
 138         * let's defer this driver too.
 139         */
 140        if ((!panel && !bridge) && defer)
 141                return -EPROBE_DEFER;
 142
 143        if (panel) {
 144                bridge = drm_panel_bridge_add_typed(panel,
 145                                                    DRM_MODE_CONNECTOR_Unknown);
 146                if (IS_ERR(bridge)) {
 147                        ret = PTR_ERR(bridge);
 148                        goto finish;
 149                }
 150        } else if (bridge) {
 151                dev_info(dev->dev, "Using non-panel bridge\n");
 152        } else {
 153                dev_err(dev->dev, "No bridge, exiting\n");
 154                return -ENODEV;
 155        }
 156
 157        priv->bridge = bridge;
 158        if (panel) {
 159                priv->panel = panel;
 160                priv->connector = drm_panel_bridge_connector(bridge);
 161        }
 162
 163        ret = pl111_display_init(dev);
 164        if (ret != 0) {
 165                dev_err(dev->dev, "Failed to init display\n");
 166                goto out_bridge;
 167        }
 168
 169        ret = drm_simple_display_pipe_attach_bridge(&priv->pipe,
 170                                                    bridge);
 171        if (ret)
 172                return ret;
 173
 174        if (!priv->variant->broken_vblank) {
 175                ret = drm_vblank_init(dev, 1);
 176                if (ret != 0) {
 177                        dev_err(dev->dev, "Failed to init vblank\n");
 178                        goto out_bridge;
 179                }
 180        }
 181
 182        drm_mode_config_reset(dev);
 183
 184        drm_kms_helper_poll_init(dev);
 185
 186        goto finish;
 187
 188out_bridge:
 189        if (panel)
 190                drm_panel_bridge_remove(bridge);
 191finish:
 192        return ret;
 193}
 194
 195static struct drm_gem_object *
 196pl111_gem_import_sg_table(struct drm_device *dev,
 197                          struct dma_buf_attachment *attach,
 198                          struct sg_table *sgt)
 199{
 200        struct pl111_drm_dev_private *priv = dev->dev_private;
 201
 202        /*
 203         * When using device-specific reserved memory we can't import
 204         * DMA buffers: those are passed by reference in any global
 205         * memory and we can only handle a specific range of memory.
 206         */
 207        if (priv->use_device_memory)
 208                return ERR_PTR(-EINVAL);
 209
 210        return drm_gem_cma_prime_import_sg_table(dev, attach, sgt);
 211}
 212
 213DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
 214
 215static const struct drm_driver pl111_drm_driver = {
 216        .driver_features =
 217                DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
 218        .ioctls = NULL,
 219        .fops = &drm_fops,
 220        .name = "pl111",
 221        .desc = DRIVER_DESC,
 222        .date = "20170317",
 223        .major = 1,
 224        .minor = 0,
 225        .patchlevel = 0,
 226        .dumb_create = drm_gem_cma_dumb_create,
 227        .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
 228        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 229        .gem_prime_import_sg_table = pl111_gem_import_sg_table,
 230        .gem_prime_mmap = drm_gem_prime_mmap,
 231
 232#if defined(CONFIG_DEBUG_FS)
 233        .debugfs_init = pl111_debugfs_init,
 234#endif
 235};
 236
 237static int pl111_amba_probe(struct amba_device *amba_dev,
 238                            const struct amba_id *id)
 239{
 240        struct device *dev = &amba_dev->dev;
 241        struct pl111_drm_dev_private *priv;
 242        const struct pl111_variant_data *variant = id->data;
 243        struct drm_device *drm;
 244        int ret;
 245
 246        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 247        if (!priv)
 248                return -ENOMEM;
 249
 250        drm = drm_dev_alloc(&pl111_drm_driver, dev);
 251        if (IS_ERR(drm))
 252                return PTR_ERR(drm);
 253        amba_set_drvdata(amba_dev, drm);
 254        priv->drm = drm;
 255        drm->dev_private = priv;
 256        priv->variant = variant;
 257
 258        ret = of_reserved_mem_device_init(dev);
 259        if (!ret) {
 260                dev_info(dev, "using device-specific reserved memory\n");
 261                priv->use_device_memory = true;
 262        }
 263
 264        if (of_property_read_u32(dev->of_node, "max-memory-bandwidth",
 265                                 &priv->memory_bw)) {
 266                dev_info(dev, "no max memory bandwidth specified, assume unlimited\n");
 267                priv->memory_bw = 0;
 268        }
 269
 270        /* The two main variants swap this register */
 271        if (variant->is_pl110 || variant->is_lcdc) {
 272                priv->ienb = CLCD_PL110_IENB;
 273                priv->ctrl = CLCD_PL110_CNTL;
 274        } else {
 275                priv->ienb = CLCD_PL111_IENB;
 276                priv->ctrl = CLCD_PL111_CNTL;
 277        }
 278
 279        priv->regs = devm_ioremap_resource(dev, &amba_dev->res);
 280        if (IS_ERR(priv->regs)) {
 281                dev_err(dev, "%s failed mmio\n", __func__);
 282                ret = PTR_ERR(priv->regs);
 283                goto dev_put;
 284        }
 285
 286        /* This may override some variant settings */
 287        ret = pl111_versatile_init(dev, priv);
 288        if (ret)
 289                goto dev_put;
 290
 291        pl111_nomadik_init(dev);
 292
 293        /* turn off interrupts before requesting the irq */
 294        writel(0, priv->regs + priv->ienb);
 295
 296        ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0,
 297                               variant->name, priv);
 298        if (ret != 0) {
 299                dev_err(dev, "%s failed irq %d\n", __func__, ret);
 300                return ret;
 301        }
 302
 303        ret = pl111_modeset_init(drm);
 304        if (ret != 0)
 305                goto dev_put;
 306
 307        ret = drm_dev_register(drm, 0);
 308        if (ret < 0)
 309                goto dev_put;
 310
 311        drm_fbdev_generic_setup(drm, priv->variant->fb_bpp);
 312
 313        return 0;
 314
 315dev_put:
 316        drm_dev_put(drm);
 317        of_reserved_mem_device_release(dev);
 318
 319        return ret;
 320}
 321
 322static void pl111_amba_remove(struct amba_device *amba_dev)
 323{
 324        struct device *dev = &amba_dev->dev;
 325        struct drm_device *drm = amba_get_drvdata(amba_dev);
 326        struct pl111_drm_dev_private *priv = drm->dev_private;
 327
 328        drm_dev_unregister(drm);
 329        if (priv->panel)
 330                drm_panel_bridge_remove(priv->bridge);
 331        drm_dev_put(drm);
 332        of_reserved_mem_device_release(dev);
 333}
 334
 335/*
 336 * This early variant lacks the 565 and 444 pixel formats.
 337 */
 338static const u32 pl110_pixel_formats[] = {
 339        DRM_FORMAT_ABGR8888,
 340        DRM_FORMAT_XBGR8888,
 341        DRM_FORMAT_ARGB8888,
 342        DRM_FORMAT_XRGB8888,
 343        DRM_FORMAT_ABGR1555,
 344        DRM_FORMAT_XBGR1555,
 345        DRM_FORMAT_ARGB1555,
 346        DRM_FORMAT_XRGB1555,
 347};
 348
 349static const struct pl111_variant_data pl110_variant = {
 350        .name = "PL110",
 351        .is_pl110 = true,
 352        .formats = pl110_pixel_formats,
 353        .nformats = ARRAY_SIZE(pl110_pixel_formats),
 354        .fb_bpp = 16,
 355};
 356
 357/* RealView, Versatile Express etc use this modern variant */
 358static const u32 pl111_pixel_formats[] = {
 359        DRM_FORMAT_ABGR8888,
 360        DRM_FORMAT_XBGR8888,
 361        DRM_FORMAT_ARGB8888,
 362        DRM_FORMAT_XRGB8888,
 363        DRM_FORMAT_BGR565,
 364        DRM_FORMAT_RGB565,
 365        DRM_FORMAT_ABGR1555,
 366        DRM_FORMAT_XBGR1555,
 367        DRM_FORMAT_ARGB1555,
 368        DRM_FORMAT_XRGB1555,
 369        DRM_FORMAT_ABGR4444,
 370        DRM_FORMAT_XBGR4444,
 371        DRM_FORMAT_ARGB4444,
 372        DRM_FORMAT_XRGB4444,
 373};
 374
 375static const struct pl111_variant_data pl111_variant = {
 376        .name = "PL111",
 377        .formats = pl111_pixel_formats,
 378        .nformats = ARRAY_SIZE(pl111_pixel_formats),
 379        .fb_bpp = 32,
 380};
 381
 382static const u32 pl110_nomadik_pixel_formats[] = {
 383        DRM_FORMAT_RGB888,
 384        DRM_FORMAT_BGR888,
 385        DRM_FORMAT_ABGR8888,
 386        DRM_FORMAT_XBGR8888,
 387        DRM_FORMAT_ARGB8888,
 388        DRM_FORMAT_XRGB8888,
 389        DRM_FORMAT_BGR565,
 390        DRM_FORMAT_RGB565,
 391        DRM_FORMAT_ABGR1555,
 392        DRM_FORMAT_XBGR1555,
 393        DRM_FORMAT_ARGB1555,
 394        DRM_FORMAT_XRGB1555,
 395        DRM_FORMAT_ABGR4444,
 396        DRM_FORMAT_XBGR4444,
 397        DRM_FORMAT_ARGB4444,
 398        DRM_FORMAT_XRGB4444,
 399};
 400
 401static const struct pl111_variant_data pl110_nomadik_variant = {
 402        .name = "LCDC (PL110 Nomadik)",
 403        .formats = pl110_nomadik_pixel_formats,
 404        .nformats = ARRAY_SIZE(pl110_nomadik_pixel_formats),
 405        .is_lcdc = true,
 406        .st_bitmux_control = true,
 407        .broken_vblank = true,
 408        .fb_bpp = 16,
 409};
 410
 411static const struct amba_id pl111_id_table[] = {
 412        {
 413                .id = 0x00041110,
 414                .mask = 0x000fffff,
 415                .data = (void *)&pl110_variant,
 416        },
 417        {
 418                .id = 0x00180110,
 419                .mask = 0x00fffffe,
 420                .data = (void *)&pl110_nomadik_variant,
 421        },
 422        {
 423                .id = 0x00041111,
 424                .mask = 0x000fffff,
 425                .data = (void *)&pl111_variant,
 426        },
 427        {0, 0},
 428};
 429MODULE_DEVICE_TABLE(amba, pl111_id_table);
 430
 431static struct amba_driver pl111_amba_driver __maybe_unused = {
 432        .drv = {
 433                .name = "drm-clcd-pl111",
 434        },
 435        .probe = pl111_amba_probe,
 436        .remove = pl111_amba_remove,
 437        .id_table = pl111_id_table,
 438};
 439
 440#ifdef CONFIG_ARM_AMBA
 441module_amba_driver(pl111_amba_driver);
 442#endif
 443
 444MODULE_DESCRIPTION(DRIVER_DESC);
 445MODULE_AUTHOR("ARM Ltd.");
 446MODULE_LICENSE("GPL");
 447