linux/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* Hisilicon Hibmc SoC drm driver
   3 *
   4 * Based on the bochs drm driver.
   5 *
   6 * Copyright (c) 2016 Huawei Limited.
   7 *
   8 * Author:
   9 *      Rongrong Zou <zourongrong@huawei.com>
  10 *      Rongrong Zou <zourongrong@gmail.com>
  11 *      Jianhua Li <lijianhua@huawei.com>
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/pci.h>
  16
  17#include <drm/drm_aperture.h>
  18#include <drm/drm_atomic_helper.h>
  19#include <drm/drm_drv.h>
  20#include <drm/drm_gem_framebuffer_helper.h>
  21#include <drm/drm_gem_vram_helper.h>
  22#include <drm/drm_managed.h>
  23#include <drm/drm_vblank.h>
  24
  25#include "hibmc_drm_drv.h"
  26#include "hibmc_drm_regs.h"
  27
  28DEFINE_DRM_GEM_FOPS(hibmc_fops);
  29
  30static irqreturn_t hibmc_interrupt(int irq, void *arg)
  31{
  32        struct drm_device *dev = (struct drm_device *)arg;
  33        struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
  34        u32 status;
  35
  36        status = readl(priv->mmio + HIBMC_RAW_INTERRUPT);
  37
  38        if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
  39                writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
  40                       priv->mmio + HIBMC_RAW_INTERRUPT);
  41                drm_handle_vblank(dev, 0);
  42        }
  43
  44        return IRQ_HANDLED;
  45}
  46
  47static int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
  48                             struct drm_mode_create_dumb *args)
  49{
  50        return drm_gem_vram_fill_create_dumb(file, dev, 0, 128, args);
  51}
  52
  53static const struct drm_driver hibmc_driver = {
  54        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
  55        .fops                   = &hibmc_fops,
  56        .name                   = "hibmc",
  57        .date                   = "20160828",
  58        .desc                   = "hibmc drm driver",
  59        .major                  = 1,
  60        .minor                  = 0,
  61        .debugfs_init           = drm_vram_mm_debugfs_init,
  62        .dumb_create            = hibmc_dumb_create,
  63        .dumb_map_offset        = drm_gem_ttm_dumb_map_offset,
  64        .gem_prime_mmap         = drm_gem_prime_mmap,
  65};
  66
  67static int __maybe_unused hibmc_pm_suspend(struct device *dev)
  68{
  69        struct drm_device *drm_dev = dev_get_drvdata(dev);
  70
  71        return drm_mode_config_helper_suspend(drm_dev);
  72}
  73
  74static int  __maybe_unused hibmc_pm_resume(struct device *dev)
  75{
  76        struct drm_device *drm_dev = dev_get_drvdata(dev);
  77
  78        return drm_mode_config_helper_resume(drm_dev);
  79}
  80
  81static const struct dev_pm_ops hibmc_pm_ops = {
  82        SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
  83                                hibmc_pm_resume)
  84};
  85
  86static const struct drm_mode_config_funcs hibmc_mode_funcs = {
  87        .mode_valid = drm_vram_helper_mode_valid,
  88        .atomic_check = drm_atomic_helper_check,
  89        .atomic_commit = drm_atomic_helper_commit,
  90        .fb_create = drm_gem_fb_create,
  91};
  92
  93static int hibmc_kms_init(struct hibmc_drm_private *priv)
  94{
  95        struct drm_device *dev = &priv->dev;
  96        int ret;
  97
  98        ret = drmm_mode_config_init(dev);
  99        if (ret)
 100                return ret;
 101
 102        dev->mode_config.min_width = 0;
 103        dev->mode_config.min_height = 0;
 104        dev->mode_config.max_width = 1920;
 105        dev->mode_config.max_height = 1200;
 106
 107        dev->mode_config.fb_base = priv->fb_base;
 108        dev->mode_config.preferred_depth = 32;
 109        dev->mode_config.prefer_shadow = 1;
 110
 111        dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
 112
 113        ret = hibmc_de_init(priv);
 114        if (ret) {
 115                drm_err(dev, "failed to init de: %d\n", ret);
 116                return ret;
 117        }
 118
 119        ret = hibmc_vdac_init(priv);
 120        if (ret) {
 121                drm_err(dev, "failed to init vdac: %d\n", ret);
 122                return ret;
 123        }
 124
 125        return 0;
 126}
 127
 128/*
 129 * It can operate in one of three modes: 0, 1 or Sleep.
 130 */
 131void hibmc_set_power_mode(struct hibmc_drm_private *priv, u32 power_mode)
 132{
 133        u32 control_value = 0;
 134        void __iomem   *mmio = priv->mmio;
 135        u32 input = 1;
 136
 137        if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
 138                return;
 139
 140        if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
 141                input = 0;
 142
 143        control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
 144        control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
 145                           HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
 146        control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
 147        control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
 148        writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
 149}
 150
 151void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
 152{
 153        u32 gate_reg;
 154        u32 mode;
 155        void __iomem   *mmio = priv->mmio;
 156
 157        /* Get current power mode. */
 158        mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
 159                HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
 160
 161        switch (mode) {
 162        case HIBMC_PW_MODE_CTL_MODE_MODE0:
 163                gate_reg = HIBMC_MODE0_GATE;
 164                break;
 165
 166        case HIBMC_PW_MODE_CTL_MODE_MODE1:
 167                gate_reg = HIBMC_MODE1_GATE;
 168                break;
 169
 170        default:
 171                gate_reg = HIBMC_MODE0_GATE;
 172                break;
 173        }
 174        writel(gate, mmio + gate_reg);
 175}
 176
 177static void hibmc_hw_config(struct hibmc_drm_private *priv)
 178{
 179        u32 reg;
 180
 181        /* On hardware reset, power mode 0 is default. */
 182        hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
 183
 184        /* Enable display power gate & LOCALMEM power gate*/
 185        reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
 186        reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
 187        reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
 188        reg |= HIBMC_CURR_GATE_DISPLAY(1);
 189        reg |= HIBMC_CURR_GATE_LOCALMEM(1);
 190
 191        hibmc_set_current_gate(priv, reg);
 192
 193        /*
 194         * Reset the memory controller. If the memory controller
 195         * is not reset in chip,the system might hang when sw accesses
 196         * the memory.The memory should be resetted after
 197         * changing the MXCLK.
 198         */
 199        reg = readl(priv->mmio + HIBMC_MISC_CTRL);
 200        reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
 201        reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
 202        writel(reg, priv->mmio + HIBMC_MISC_CTRL);
 203
 204        reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
 205        reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
 206
 207        writel(reg, priv->mmio + HIBMC_MISC_CTRL);
 208}
 209
 210static int hibmc_hw_map(struct hibmc_drm_private *priv)
 211{
 212        struct drm_device *dev = &priv->dev;
 213        struct pci_dev *pdev = to_pci_dev(dev->dev);
 214        resource_size_t addr, size, ioaddr, iosize;
 215
 216        ioaddr = pci_resource_start(pdev, 1);
 217        iosize = pci_resource_len(pdev, 1);
 218        priv->mmio = devm_ioremap(dev->dev, ioaddr, iosize);
 219        if (!priv->mmio) {
 220                drm_err(dev, "Cannot map mmio region\n");
 221                return -ENOMEM;
 222        }
 223
 224        addr = pci_resource_start(pdev, 0);
 225        size = pci_resource_len(pdev, 0);
 226        priv->fb_map = devm_ioremap(dev->dev, addr, size);
 227        if (!priv->fb_map) {
 228                drm_err(dev, "Cannot map framebuffer\n");
 229                return -ENOMEM;
 230        }
 231        priv->fb_base = addr;
 232        priv->fb_size = size;
 233
 234        return 0;
 235}
 236
 237static int hibmc_hw_init(struct hibmc_drm_private *priv)
 238{
 239        int ret;
 240
 241        ret = hibmc_hw_map(priv);
 242        if (ret)
 243                return ret;
 244
 245        hibmc_hw_config(priv);
 246
 247        return 0;
 248}
 249
 250static int hibmc_unload(struct drm_device *dev)
 251{
 252        struct pci_dev *pdev = to_pci_dev(dev->dev);
 253
 254        drm_atomic_helper_shutdown(dev);
 255
 256        free_irq(pdev->irq, dev);
 257
 258        pci_disable_msi(to_pci_dev(dev->dev));
 259
 260        return 0;
 261}
 262
 263static int hibmc_load(struct drm_device *dev)
 264{
 265        struct pci_dev *pdev = to_pci_dev(dev->dev);
 266        struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
 267        int ret;
 268
 269        ret = hibmc_hw_init(priv);
 270        if (ret)
 271                goto err;
 272
 273        ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0), priv->fb_size);
 274        if (ret) {
 275                drm_err(dev, "Error initializing VRAM MM; %d\n", ret);
 276                goto err;
 277        }
 278
 279        ret = hibmc_kms_init(priv);
 280        if (ret)
 281                goto err;
 282
 283        ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
 284        if (ret) {
 285                drm_err(dev, "failed to initialize vblank: %d\n", ret);
 286                goto err;
 287        }
 288
 289        ret = pci_enable_msi(pdev);
 290        if (ret) {
 291                drm_warn(dev, "enabling MSI failed: %d\n", ret);
 292        } else {
 293                /* PCI devices require shared interrupts. */
 294                ret = request_irq(pdev->irq, hibmc_interrupt, IRQF_SHARED,
 295                                  dev->driver->name, dev);
 296                if (ret)
 297                        drm_warn(dev, "install irq failed: %d\n", ret);
 298        }
 299
 300        /* reset all the states of crtc/plane/encoder/connector */
 301        drm_mode_config_reset(dev);
 302
 303        return 0;
 304
 305err:
 306        hibmc_unload(dev);
 307        drm_err(dev, "failed to initialize drm driver: %d\n", ret);
 308        return ret;
 309}
 310
 311static int hibmc_pci_probe(struct pci_dev *pdev,
 312                           const struct pci_device_id *ent)
 313{
 314        struct hibmc_drm_private *priv;
 315        struct drm_device *dev;
 316        int ret;
 317
 318        ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &hibmc_driver);
 319        if (ret)
 320                return ret;
 321
 322        priv = devm_drm_dev_alloc(&pdev->dev, &hibmc_driver,
 323                                  struct hibmc_drm_private, dev);
 324        if (IS_ERR(priv)) {
 325                DRM_ERROR("failed to allocate drm_device\n");
 326                return PTR_ERR(priv);
 327        }
 328
 329        dev = &priv->dev;
 330        pci_set_drvdata(pdev, dev);
 331
 332        ret = pcim_enable_device(pdev);
 333        if (ret) {
 334                drm_err(dev, "failed to enable pci device: %d\n", ret);
 335                goto err_return;
 336        }
 337
 338        ret = hibmc_load(dev);
 339        if (ret) {
 340                drm_err(dev, "failed to load hibmc: %d\n", ret);
 341                goto err_return;
 342        }
 343
 344        ret = drm_dev_register(dev, 0);
 345        if (ret) {
 346                drm_err(dev, "failed to register drv for userspace access: %d\n",
 347                          ret);
 348                goto err_unload;
 349        }
 350
 351        drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth);
 352
 353        return 0;
 354
 355err_unload:
 356        hibmc_unload(dev);
 357err_return:
 358        return ret;
 359}
 360
 361static void hibmc_pci_remove(struct pci_dev *pdev)
 362{
 363        struct drm_device *dev = pci_get_drvdata(pdev);
 364
 365        drm_dev_unregister(dev);
 366        hibmc_unload(dev);
 367}
 368
 369static const struct pci_device_id hibmc_pci_table[] = {
 370        { PCI_VDEVICE(HUAWEI, 0x1711) },
 371        {0,}
 372};
 373
 374static struct pci_driver hibmc_pci_driver = {
 375        .name =         "hibmc-drm",
 376        .id_table =     hibmc_pci_table,
 377        .probe =        hibmc_pci_probe,
 378        .remove =       hibmc_pci_remove,
 379        .driver.pm =    &hibmc_pm_ops,
 380};
 381
 382module_pci_driver(hibmc_pci_driver);
 383
 384MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
 385MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
 386MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
 387MODULE_LICENSE("GPL v2");
 388