root/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c

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

DEFINITIONS

This source file includes following definitions.
  1. aspeed_gfx_setup_mode_config
  2. aspeed_gfx_irq_handler
  3. aspeed_gfx_load
  4. aspeed_gfx_unload
  5. aspeed_gfx_probe
  6. aspeed_gfx_remove

   1 // SPDX-License-Identifier: GPL-2.0+
   2 // Copyright 2018 IBM Corporation
   3 
   4 #include <linux/clk.h>
   5 #include <linux/dma-mapping.h>
   6 #include <linux/irq.h>
   7 #include <linux/mfd/syscon.h>
   8 #include <linux/module.h>
   9 #include <linux/of.h>
  10 #include <linux/of_reserved_mem.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/regmap.h>
  13 #include <linux/reset.h>
  14 
  15 #include <drm/drm_atomic_helper.h>
  16 #include <drm/drm_crtc_helper.h>
  17 #include <drm/drm_device.h>
  18 #include <drm/drm_fb_cma_helper.h>
  19 #include <drm/drm_fb_helper.h>
  20 #include <drm/drm_gem_cma_helper.h>
  21 #include <drm/drm_gem_framebuffer_helper.h>
  22 #include <drm/drm_probe_helper.h>
  23 #include <drm/drm_simple_kms_helper.h>
  24 #include <drm/drm_vblank.h>
  25 #include <drm/drm_drv.h>
  26 
  27 #include "aspeed_gfx.h"
  28 
  29 /**
  30  * DOC: ASPEED GFX Driver
  31  *
  32  * This driver is for the ASPEED BMC SoC's 'GFX' display hardware, also called
  33  * the 'SOC Display Controller' in the datasheet. This driver runs on the ARM
  34  * based BMC systems, unlike the ast driver which runs on a host CPU and is for
  35  * a PCIe graphics device.
  36  *
  37  * The AST2500 supports a total of 3 output paths:
  38  *
  39  *   1. VGA output, the output target can choose either or both to the DAC
  40  *   or DVO interface.
  41  *
  42  *   2. Graphics CRT output, the output target can choose either or both to
  43  *   the DAC or DVO interface.
  44  *
  45  *   3. Video input from DVO, the video input can be used for video engine
  46  *   capture or DAC display output.
  47  *
  48  * Output options are selected in SCU2C.
  49  *
  50  * The "VGA mode" device is the PCI attached controller. The "Graphics CRT"
  51  * is the ARM's internal display controller.
  52  *
  53  * The driver only supports a simple configuration consisting of a 40MHz
  54  * pixel clock, fixed by hardware limitations, and the VGA output path.
  55  *
  56  * The driver was written with the 'AST2500 Software Programming Guide' v17,
  57  * which is available under NDA from ASPEED.
  58  */
  59 
  60 static const struct drm_mode_config_funcs aspeed_gfx_mode_config_funcs = {
  61         .fb_create              = drm_gem_fb_create,
  62         .atomic_check           = drm_atomic_helper_check,
  63         .atomic_commit          = drm_atomic_helper_commit,
  64 };
  65 
  66 static void aspeed_gfx_setup_mode_config(struct drm_device *drm)
  67 {
  68         drm_mode_config_init(drm);
  69 
  70         drm->mode_config.min_width = 0;
  71         drm->mode_config.min_height = 0;
  72         drm->mode_config.max_width = 800;
  73         drm->mode_config.max_height = 600;
  74         drm->mode_config.funcs = &aspeed_gfx_mode_config_funcs;
  75 }
  76 
  77 static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data)
  78 {
  79         struct drm_device *drm = data;
  80         struct aspeed_gfx *priv = drm->dev_private;
  81         u32 reg;
  82 
  83         reg = readl(priv->base + CRT_CTRL1);
  84 
  85         if (reg & CRT_CTRL_VERTICAL_INTR_STS) {
  86                 drm_crtc_handle_vblank(&priv->pipe.crtc);
  87                 writel(reg, priv->base + CRT_CTRL1);
  88                 return IRQ_HANDLED;
  89         }
  90 
  91         return IRQ_NONE;
  92 }
  93 
  94 
  95 
  96 static int aspeed_gfx_load(struct drm_device *drm)
  97 {
  98         struct platform_device *pdev = to_platform_device(drm->dev);
  99         struct aspeed_gfx *priv;
 100         struct resource *res;
 101         int ret;
 102 
 103         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 104         if (!priv)
 105                 return -ENOMEM;
 106         drm->dev_private = priv;
 107 
 108         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 109         priv->base = devm_ioremap_resource(drm->dev, res);
 110         if (IS_ERR(priv->base))
 111                 return PTR_ERR(priv->base);
 112 
 113         priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu");
 114         if (IS_ERR(priv->scu)) {
 115                 dev_err(&pdev->dev, "failed to find SCU regmap\n");
 116                 return PTR_ERR(priv->scu);
 117         }
 118 
 119         ret = of_reserved_mem_device_init(drm->dev);
 120         if (ret) {
 121                 dev_err(&pdev->dev,
 122                         "failed to initialize reserved mem: %d\n", ret);
 123                 return ret;
 124         }
 125 
 126         ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
 127         if (ret) {
 128                 dev_err(&pdev->dev, "failed to set DMA mask: %d\n", ret);
 129                 return ret;
 130         }
 131 
 132         priv->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 133         if (IS_ERR(priv->rst)) {
 134                 dev_err(&pdev->dev,
 135                         "missing or invalid reset controller device tree entry");
 136                 return PTR_ERR(priv->rst);
 137         }
 138         reset_control_deassert(priv->rst);
 139 
 140         priv->clk = devm_clk_get(drm->dev, NULL);
 141         if (IS_ERR(priv->clk)) {
 142                 dev_err(&pdev->dev,
 143                         "missing or invalid clk device tree entry");
 144                 return PTR_ERR(priv->clk);
 145         }
 146         clk_prepare_enable(priv->clk);
 147 
 148         /* Sanitize control registers */
 149         writel(0, priv->base + CRT_CTRL1);
 150         writel(0, priv->base + CRT_CTRL2);
 151 
 152         aspeed_gfx_setup_mode_config(drm);
 153 
 154         ret = drm_vblank_init(drm, 1);
 155         if (ret < 0) {
 156                 dev_err(drm->dev, "Failed to initialise vblank\n");
 157                 return ret;
 158         }
 159 
 160         ret = aspeed_gfx_create_output(drm);
 161         if (ret < 0) {
 162                 dev_err(drm->dev, "Failed to create outputs\n");
 163                 return ret;
 164         }
 165 
 166         ret = aspeed_gfx_create_pipe(drm);
 167         if (ret < 0) {
 168                 dev_err(drm->dev, "Cannot setup simple display pipe\n");
 169                 return ret;
 170         }
 171 
 172         ret = devm_request_irq(drm->dev, platform_get_irq(pdev, 0),
 173                                aspeed_gfx_irq_handler, 0, "aspeed gfx", drm);
 174         if (ret < 0) {
 175                 dev_err(drm->dev, "Failed to install IRQ handler\n");
 176                 return ret;
 177         }
 178 
 179         drm_mode_config_reset(drm);
 180 
 181         drm_fbdev_generic_setup(drm, 32);
 182 
 183         return 0;
 184 }
 185 
 186 static void aspeed_gfx_unload(struct drm_device *drm)
 187 {
 188         drm_kms_helper_poll_fini(drm);
 189         drm_mode_config_cleanup(drm);
 190 
 191         drm->dev_private = NULL;
 192 }
 193 
 194 DEFINE_DRM_GEM_CMA_FOPS(fops);
 195 
 196 static struct drm_driver aspeed_gfx_driver = {
 197         .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 198         .gem_create_object      = drm_cma_gem_create_object_default_funcs,
 199         .dumb_create            = drm_gem_cma_dumb_create,
 200         .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
 201         .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
 202         .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
 203         .gem_prime_mmap         = drm_gem_prime_mmap,
 204         .fops = &fops,
 205         .name = "aspeed-gfx-drm",
 206         .desc = "ASPEED GFX DRM",
 207         .date = "20180319",
 208         .major = 1,
 209         .minor = 0,
 210 };
 211 
 212 static const struct of_device_id aspeed_gfx_match[] = {
 213         { .compatible = "aspeed,ast2500-gfx" },
 214         { }
 215 };
 216 
 217 static int aspeed_gfx_probe(struct platform_device *pdev)
 218 {
 219         struct drm_device *drm;
 220         int ret;
 221 
 222         drm = drm_dev_alloc(&aspeed_gfx_driver, &pdev->dev);
 223         if (IS_ERR(drm))
 224                 return PTR_ERR(drm);
 225 
 226         ret = aspeed_gfx_load(drm);
 227         if (ret)
 228                 goto err_free;
 229 
 230         ret = drm_dev_register(drm, 0);
 231         if (ret)
 232                 goto err_unload;
 233 
 234         return 0;
 235 
 236 err_unload:
 237         aspeed_gfx_unload(drm);
 238 err_free:
 239         drm_dev_put(drm);
 240 
 241         return ret;
 242 }
 243 
 244 static int aspeed_gfx_remove(struct platform_device *pdev)
 245 {
 246         struct drm_device *drm = platform_get_drvdata(pdev);
 247 
 248         drm_dev_unregister(drm);
 249         aspeed_gfx_unload(drm);
 250         drm_dev_put(drm);
 251 
 252         return 0;
 253 }
 254 
 255 static struct platform_driver aspeed_gfx_platform_driver = {
 256         .probe          = aspeed_gfx_probe,
 257         .remove         = aspeed_gfx_remove,
 258         .driver = {
 259                 .name = "aspeed_gfx",
 260                 .of_match_table = aspeed_gfx_match,
 261         },
 262 };
 263 
 264 module_platform_driver(aspeed_gfx_platform_driver);
 265 
 266 MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
 267 MODULE_DESCRIPTION("ASPEED BMC DRM/KMS driver");
 268 MODULE_LICENSE("GPL");

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