root/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c

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

DEFINITIONS

This source file includes following definitions.
  1. fsl_dcu_drm_is_volatile_reg
  2. fsl_dcu_irq_uninstall
  3. fsl_dcu_load
  4. fsl_dcu_unload
  5. fsl_dcu_drm_irq
  6. fsl_dcu_drm_pm_suspend
  7. fsl_dcu_drm_pm_resume
  8. fsl_dcu_drm_probe
  9. fsl_dcu_drm_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright 2015 Freescale Semiconductor, Inc.
   4  *
   5  * Freescale DCU drm device driver
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/clk-provider.h>
  10 #include <linux/console.h>
  11 #include <linux/io.h>
  12 #include <linux/mfd/syscon.h>
  13 #include <linux/mm.h>
  14 #include <linux/module.h>
  15 #include <linux/of_platform.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/pm.h>
  18 #include <linux/pm_runtime.h>
  19 #include <linux/regmap.h>
  20 
  21 #include <drm/drm_atomic_helper.h>
  22 #include <drm/drm_drv.h>
  23 #include <drm/drm_fb_cma_helper.h>
  24 #include <drm/drm_fb_helper.h>
  25 #include <drm/drm_gem_cma_helper.h>
  26 #include <drm/drm_irq.h>
  27 #include <drm/drm_modeset_helper.h>
  28 #include <drm/drm_probe_helper.h>
  29 #include <drm/drm_vblank.h>
  30 
  31 #include "fsl_dcu_drm_crtc.h"
  32 #include "fsl_dcu_drm_drv.h"
  33 #include "fsl_tcon.h"
  34 
  35 static int legacyfb_depth = 24;
  36 module_param(legacyfb_depth, int, 0444);
  37 
  38 static bool fsl_dcu_drm_is_volatile_reg(struct device *dev, unsigned int reg)
  39 {
  40         if (reg == DCU_INT_STATUS || reg == DCU_UPDATE_MODE)
  41                 return true;
  42 
  43         return false;
  44 }
  45 
  46 static const struct regmap_config fsl_dcu_regmap_config = {
  47         .reg_bits = 32,
  48         .reg_stride = 4,
  49         .val_bits = 32,
  50 
  51         .volatile_reg = fsl_dcu_drm_is_volatile_reg,
  52 };
  53 
  54 static void fsl_dcu_irq_uninstall(struct drm_device *dev)
  55 {
  56         struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
  57 
  58         regmap_write(fsl_dev->regmap, DCU_INT_STATUS, ~0);
  59         regmap_write(fsl_dev->regmap, DCU_INT_MASK, ~0);
  60 }
  61 
  62 static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
  63 {
  64         struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
  65         int ret;
  66 
  67         ret = fsl_dcu_drm_modeset_init(fsl_dev);
  68         if (ret < 0) {
  69                 dev_err(dev->dev, "failed to initialize mode setting\n");
  70                 return ret;
  71         }
  72 
  73         ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
  74         if (ret < 0) {
  75                 dev_err(dev->dev, "failed to initialize vblank\n");
  76                 goto done;
  77         }
  78 
  79         ret = drm_irq_install(dev, fsl_dev->irq);
  80         if (ret < 0) {
  81                 dev_err(dev->dev, "failed to install IRQ handler\n");
  82                 goto done;
  83         }
  84 
  85         if (legacyfb_depth != 16 && legacyfb_depth != 24 &&
  86             legacyfb_depth != 32) {
  87                 dev_warn(dev->dev,
  88                         "Invalid legacyfb_depth.  Defaulting to 24bpp\n");
  89                 legacyfb_depth = 24;
  90         }
  91 
  92         return 0;
  93 done:
  94         drm_kms_helper_poll_fini(dev);
  95 
  96         drm_mode_config_cleanup(dev);
  97         drm_irq_uninstall(dev);
  98         dev->dev_private = NULL;
  99 
 100         return ret;
 101 }
 102 
 103 static void fsl_dcu_unload(struct drm_device *dev)
 104 {
 105         drm_atomic_helper_shutdown(dev);
 106         drm_kms_helper_poll_fini(dev);
 107 
 108         drm_mode_config_cleanup(dev);
 109         drm_irq_uninstall(dev);
 110 
 111         dev->dev_private = NULL;
 112 }
 113 
 114 static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
 115 {
 116         struct drm_device *dev = arg;
 117         struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
 118         unsigned int int_status;
 119         int ret;
 120 
 121         ret = regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
 122         if (ret) {
 123                 dev_err(dev->dev, "read DCU_INT_STATUS failed\n");
 124                 return IRQ_NONE;
 125         }
 126 
 127         if (int_status & DCU_INT_STATUS_VBLANK)
 128                 drm_handle_vblank(dev, 0);
 129 
 130         regmap_write(fsl_dev->regmap, DCU_INT_STATUS, int_status);
 131 
 132         return IRQ_HANDLED;
 133 }
 134 
 135 DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops);
 136 
 137 static struct drm_driver fsl_dcu_drm_driver = {
 138         .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 139         .load                   = fsl_dcu_load,
 140         .unload                 = fsl_dcu_unload,
 141         .irq_handler            = fsl_dcu_drm_irq,
 142         .irq_preinstall         = fsl_dcu_irq_uninstall,
 143         .irq_uninstall          = fsl_dcu_irq_uninstall,
 144         .gem_free_object_unlocked = drm_gem_cma_free_object,
 145         .gem_vm_ops             = &drm_gem_cma_vm_ops,
 146         .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
 147         .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
 148         .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
 149         .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
 150         .gem_prime_vmap         = drm_gem_cma_prime_vmap,
 151         .gem_prime_vunmap       = drm_gem_cma_prime_vunmap,
 152         .gem_prime_mmap         = drm_gem_cma_prime_mmap,
 153         .dumb_create            = drm_gem_cma_dumb_create,
 154         .fops                   = &fsl_dcu_drm_fops,
 155         .name                   = "fsl-dcu-drm",
 156         .desc                   = "Freescale DCU DRM",
 157         .date                   = "20160425",
 158         .major                  = 1,
 159         .minor                  = 1,
 160 };
 161 
 162 #ifdef CONFIG_PM_SLEEP
 163 static int fsl_dcu_drm_pm_suspend(struct device *dev)
 164 {
 165         struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
 166         int ret;
 167 
 168         if (!fsl_dev)
 169                 return 0;
 170 
 171         disable_irq(fsl_dev->irq);
 172 
 173         ret = drm_mode_config_helper_suspend(fsl_dev->drm);
 174         if (ret) {
 175                 enable_irq(fsl_dev->irq);
 176                 return ret;
 177         }
 178 
 179         clk_disable_unprepare(fsl_dev->clk);
 180 
 181         return 0;
 182 }
 183 
 184 static int fsl_dcu_drm_pm_resume(struct device *dev)
 185 {
 186         struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
 187         int ret;
 188 
 189         if (!fsl_dev)
 190                 return 0;
 191 
 192         ret = clk_prepare_enable(fsl_dev->clk);
 193         if (ret < 0) {
 194                 dev_err(dev, "failed to enable dcu clk\n");
 195                 return ret;
 196         }
 197 
 198         if (fsl_dev->tcon)
 199                 fsl_tcon_bypass_enable(fsl_dev->tcon);
 200         fsl_dcu_drm_init_planes(fsl_dev->drm);
 201         enable_irq(fsl_dev->irq);
 202 
 203         drm_mode_config_helper_resume(fsl_dev->drm);
 204 
 205         return 0;
 206 }
 207 #endif
 208 
 209 static const struct dev_pm_ops fsl_dcu_drm_pm_ops = {
 210         SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend, fsl_dcu_drm_pm_resume)
 211 };
 212 
 213 static const struct fsl_dcu_soc_data fsl_dcu_ls1021a_data = {
 214         .name = "ls1021a",
 215         .total_layer = 16,
 216         .max_layer = 4,
 217         .layer_regs = LS1021A_LAYER_REG_NUM,
 218 };
 219 
 220 static const struct fsl_dcu_soc_data fsl_dcu_vf610_data = {
 221         .name = "vf610",
 222         .total_layer = 64,
 223         .max_layer = 6,
 224         .layer_regs = VF610_LAYER_REG_NUM,
 225 };
 226 
 227 static const struct of_device_id fsl_dcu_of_match[] = {
 228         {
 229                 .compatible = "fsl,ls1021a-dcu",
 230                 .data = &fsl_dcu_ls1021a_data,
 231         }, {
 232                 .compatible = "fsl,vf610-dcu",
 233                 .data = &fsl_dcu_vf610_data,
 234         }, {
 235         },
 236 };
 237 MODULE_DEVICE_TABLE(of, fsl_dcu_of_match);
 238 
 239 static int fsl_dcu_drm_probe(struct platform_device *pdev)
 240 {
 241         struct fsl_dcu_drm_device *fsl_dev;
 242         struct drm_device *drm;
 243         struct device *dev = &pdev->dev;
 244         struct resource *res;
 245         void __iomem *base;
 246         struct drm_driver *driver = &fsl_dcu_drm_driver;
 247         struct clk *pix_clk_in;
 248         char pix_clk_name[32];
 249         const char *pix_clk_in_name;
 250         const struct of_device_id *id;
 251         int ret;
 252         u8 div_ratio_shift = 0;
 253 
 254         fsl_dev = devm_kzalloc(dev, sizeof(*fsl_dev), GFP_KERNEL);
 255         if (!fsl_dev)
 256                 return -ENOMEM;
 257 
 258         id = of_match_node(fsl_dcu_of_match, pdev->dev.of_node);
 259         if (!id)
 260                 return -ENODEV;
 261         fsl_dev->soc = id->data;
 262 
 263         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 264         base = devm_ioremap_resource(dev, res);
 265         if (IS_ERR(base)) {
 266                 ret = PTR_ERR(base);
 267                 return ret;
 268         }
 269 
 270         fsl_dev->irq = platform_get_irq(pdev, 0);
 271         if (fsl_dev->irq < 0) {
 272                 dev_err(dev, "failed to get irq\n");
 273                 return fsl_dev->irq;
 274         }
 275 
 276         fsl_dev->regmap = devm_regmap_init_mmio(dev, base,
 277                         &fsl_dcu_regmap_config);
 278         if (IS_ERR(fsl_dev->regmap)) {
 279                 dev_err(dev, "regmap init failed\n");
 280                 return PTR_ERR(fsl_dev->regmap);
 281         }
 282 
 283         fsl_dev->clk = devm_clk_get(dev, "dcu");
 284         if (IS_ERR(fsl_dev->clk)) {
 285                 dev_err(dev, "failed to get dcu clock\n");
 286                 return PTR_ERR(fsl_dev->clk);
 287         }
 288         ret = clk_prepare_enable(fsl_dev->clk);
 289         if (ret < 0) {
 290                 dev_err(dev, "failed to enable dcu clk\n");
 291                 return ret;
 292         }
 293 
 294         pix_clk_in = devm_clk_get(dev, "pix");
 295         if (IS_ERR(pix_clk_in)) {
 296                 /* legancy binding, use dcu clock as pixel clock input */
 297                 pix_clk_in = fsl_dev->clk;
 298         }
 299 
 300         if (of_property_read_bool(dev->of_node, "big-endian"))
 301                 div_ratio_shift = 24;
 302 
 303         pix_clk_in_name = __clk_get_name(pix_clk_in);
 304         snprintf(pix_clk_name, sizeof(pix_clk_name), "%s_pix", pix_clk_in_name);
 305         fsl_dev->pix_clk = clk_register_divider(dev, pix_clk_name,
 306                         pix_clk_in_name, 0, base + DCU_DIV_RATIO,
 307                         div_ratio_shift, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL);
 308         if (IS_ERR(fsl_dev->pix_clk)) {
 309                 dev_err(dev, "failed to register pix clk\n");
 310                 ret = PTR_ERR(fsl_dev->pix_clk);
 311                 goto disable_clk;
 312         }
 313 
 314         fsl_dev->tcon = fsl_tcon_init(dev);
 315 
 316         drm = drm_dev_alloc(driver, dev);
 317         if (IS_ERR(drm)) {
 318                 ret = PTR_ERR(drm);
 319                 goto unregister_pix_clk;
 320         }
 321 
 322         fsl_dev->dev = dev;
 323         fsl_dev->drm = drm;
 324         fsl_dev->np = dev->of_node;
 325         drm->dev_private = fsl_dev;
 326         dev_set_drvdata(dev, fsl_dev);
 327 
 328         ret = drm_dev_register(drm, 0);
 329         if (ret < 0)
 330                 goto put;
 331 
 332         drm_fbdev_generic_setup(drm, legacyfb_depth);
 333 
 334         return 0;
 335 
 336 put:
 337         drm_dev_put(drm);
 338 unregister_pix_clk:
 339         clk_unregister(fsl_dev->pix_clk);
 340 disable_clk:
 341         clk_disable_unprepare(fsl_dev->clk);
 342         return ret;
 343 }
 344 
 345 static int fsl_dcu_drm_remove(struct platform_device *pdev)
 346 {
 347         struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
 348 
 349         drm_dev_unregister(fsl_dev->drm);
 350         drm_dev_put(fsl_dev->drm);
 351         clk_disable_unprepare(fsl_dev->clk);
 352         clk_unregister(fsl_dev->pix_clk);
 353 
 354         return 0;
 355 }
 356 
 357 static struct platform_driver fsl_dcu_drm_platform_driver = {
 358         .probe          = fsl_dcu_drm_probe,
 359         .remove         = fsl_dcu_drm_remove,
 360         .driver         = {
 361                 .name   = "fsl-dcu",
 362                 .pm     = &fsl_dcu_drm_pm_ops,
 363                 .of_match_table = fsl_dcu_of_match,
 364         },
 365 };
 366 
 367 module_platform_driver(fsl_dcu_drm_platform_driver);
 368 
 369 MODULE_DESCRIPTION("Freescale DCU DRM Driver");
 370 MODULE_LICENSE("GPL");

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