1 /* 2 * Copyright 2015 Freescale Semiconductor, Inc. 3 * 4 * Freescale DCU drm device driver 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 12 #include <linux/clk.h> 13 #include <linux/clk-provider.h> 14 #include <linux/io.h> 15 #include <linux/mfd/syscon.h> 16 #include <linux/mm.h> 17 #include <linux/module.h> 18 #include <linux/of_platform.h> 19 #include <linux/platform_device.h> 20 #include <linux/pm.h> 21 #include <linux/pm_runtime.h> 22 #include <linux/regmap.h> 23 24 #include <drm/drmP.h> 25 #include <drm/drm_crtc_helper.h> 26 #include <drm/drm_gem_cma_helper.h> 27 28 #include "fsl_dcu_drm_crtc.h" 29 #include "fsl_dcu_drm_drv.h" 30 31 static const struct regmap_config fsl_dcu_regmap_config = { 32 .reg_bits = 32, 33 .reg_stride = 4, 34 .val_bits = 32, 35 .cache_type = REGCACHE_RBTREE, 36 }; 37 38 static int fsl_dcu_drm_irq_init(struct drm_device *dev) 39 { 40 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 41 unsigned int value; 42 int ret; 43 44 ret = drm_irq_install(dev, fsl_dev->irq); 45 if (ret < 0) 46 dev_err(dev->dev, "failed to install IRQ handler\n"); 47 48 ret = regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0); 49 if (ret) 50 dev_err(dev->dev, "set DCU_INT_STATUS failed\n"); 51 ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value); 52 if (ret) 53 dev_err(dev->dev, "read DCU_INT_MASK failed\n"); 54 value &= DCU_INT_MASK_VBLANK; 55 ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value); 56 if (ret) 57 dev_err(dev->dev, "set DCU_INT_MASK failed\n"); 58 ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, 59 DCU_UPDATE_MODE_READREG); 60 if (ret) 61 dev_err(dev->dev, "set DCU_UPDATE_MODE failed\n"); 62 63 return ret; 64 } 65 66 static int fsl_dcu_load(struct drm_device *drm, unsigned long flags) 67 { 68 struct device *dev = drm->dev; 69 struct fsl_dcu_drm_device *fsl_dev = drm->dev_private; 70 int ret; 71 72 ret = fsl_dcu_drm_modeset_init(fsl_dev); 73 if (ret < 0) { 74 dev_err(dev, "failed to initialize mode setting\n"); 75 return ret; 76 } 77 78 ret = drm_vblank_init(drm, drm->mode_config.num_crtc); 79 if (ret < 0) { 80 dev_err(dev, "failed to initialize vblank\n"); 81 goto done; 82 } 83 drm->vblank_disable_allowed = true; 84 85 ret = fsl_dcu_drm_irq_init(drm); 86 if (ret < 0) 87 goto done; 88 drm->irq_enabled = true; 89 90 fsl_dcu_fbdev_init(drm); 91 92 return 0; 93 done: 94 if (ret) { 95 drm_mode_config_cleanup(drm); 96 drm_vblank_cleanup(drm); 97 drm_irq_uninstall(drm); 98 drm->dev_private = NULL; 99 } 100 101 return ret; 102 } 103 104 static int fsl_dcu_unload(struct drm_device *dev) 105 { 106 drm_mode_config_cleanup(dev); 107 drm_vblank_cleanup(dev); 108 drm_irq_uninstall(dev); 109 110 dev->dev_private = NULL; 111 112 return 0; 113 } 114 115 static void fsl_dcu_drm_preclose(struct drm_device *dev, struct drm_file *file) 116 { 117 } 118 119 static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg) 120 { 121 struct drm_device *dev = arg; 122 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 123 unsigned int int_status; 124 int ret; 125 126 ret = regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status); 127 if (ret) 128 dev_err(dev->dev, "set DCU_INT_STATUS failed\n"); 129 if (int_status & DCU_INT_STATUS_VBLANK) 130 drm_handle_vblank(dev, 0); 131 132 ret = regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0xffffffff); 133 if (ret) 134 dev_err(dev->dev, "set DCU_INT_STATUS failed\n"); 135 ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, 136 DCU_UPDATE_MODE_READREG); 137 if (ret) 138 dev_err(dev->dev, "set DCU_UPDATE_MODE failed\n"); 139 140 return IRQ_HANDLED; 141 } 142 143 static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int crtc) 144 { 145 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 146 unsigned int value; 147 int ret; 148 149 ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value); 150 if (ret) 151 dev_err(dev->dev, "read DCU_INT_MASK failed\n"); 152 value &= ~DCU_INT_MASK_VBLANK; 153 ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value); 154 if (ret) 155 dev_err(dev->dev, "set DCU_INT_MASK failed\n"); 156 return 0; 157 } 158 159 static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int crtc) 160 { 161 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 162 unsigned int value; 163 int ret; 164 165 ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value); 166 if (ret) 167 dev_err(dev->dev, "read DCU_INT_MASK failed\n"); 168 value |= DCU_INT_MASK_VBLANK; 169 ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value); 170 if (ret) 171 dev_err(dev->dev, "set DCU_INT_MASK failed\n"); 172 } 173 174 static const struct file_operations fsl_dcu_drm_fops = { 175 .owner = THIS_MODULE, 176 .open = drm_open, 177 .release = drm_release, 178 .unlocked_ioctl = drm_ioctl, 179 #ifdef CONFIG_COMPAT 180 .compat_ioctl = drm_compat_ioctl, 181 #endif 182 .poll = drm_poll, 183 .read = drm_read, 184 .llseek = no_llseek, 185 .mmap = drm_gem_cma_mmap, 186 }; 187 188 static struct drm_driver fsl_dcu_drm_driver = { 189 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET 190 | DRIVER_PRIME | DRIVER_ATOMIC, 191 .load = fsl_dcu_load, 192 .unload = fsl_dcu_unload, 193 .preclose = fsl_dcu_drm_preclose, 194 .irq_handler = fsl_dcu_drm_irq, 195 .get_vblank_counter = drm_vblank_count, 196 .enable_vblank = fsl_dcu_drm_enable_vblank, 197 .disable_vblank = fsl_dcu_drm_disable_vblank, 198 .gem_free_object = drm_gem_cma_free_object, 199 .gem_vm_ops = &drm_gem_cma_vm_ops, 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 = drm_gem_prime_import, 203 .gem_prime_export = drm_gem_prime_export, 204 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 205 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 206 .gem_prime_vmap = drm_gem_cma_prime_vmap, 207 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 208 .gem_prime_mmap = drm_gem_cma_prime_mmap, 209 .dumb_create = drm_gem_cma_dumb_create, 210 .dumb_map_offset = drm_gem_cma_dumb_map_offset, 211 .dumb_destroy = drm_gem_dumb_destroy, 212 .fops = &fsl_dcu_drm_fops, 213 .name = "fsl-dcu-drm", 214 .desc = "Freescale DCU DRM", 215 .date = "20150213", 216 .major = 1, 217 .minor = 0, 218 }; 219 220 #ifdef CONFIG_PM_SLEEP 221 static int fsl_dcu_drm_pm_suspend(struct device *dev) 222 { 223 struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev); 224 225 if (!fsl_dev) 226 return 0; 227 228 drm_kms_helper_poll_disable(fsl_dev->drm); 229 regcache_cache_only(fsl_dev->regmap, true); 230 regcache_mark_dirty(fsl_dev->regmap); 231 clk_disable(fsl_dev->clk); 232 clk_unprepare(fsl_dev->clk); 233 234 return 0; 235 } 236 237 static int fsl_dcu_drm_pm_resume(struct device *dev) 238 { 239 struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev); 240 int ret; 241 242 if (!fsl_dev) 243 return 0; 244 245 ret = clk_enable(fsl_dev->clk); 246 if (ret < 0) { 247 dev_err(dev, "failed to enable dcu clk\n"); 248 clk_unprepare(fsl_dev->clk); 249 return ret; 250 } 251 ret = clk_prepare(fsl_dev->clk); 252 if (ret < 0) { 253 dev_err(dev, "failed to prepare dcu clk\n"); 254 return ret; 255 } 256 257 drm_kms_helper_poll_enable(fsl_dev->drm); 258 regcache_cache_only(fsl_dev->regmap, false); 259 regcache_sync(fsl_dev->regmap); 260 261 return 0; 262 } 263 #endif 264 265 static const struct dev_pm_ops fsl_dcu_drm_pm_ops = { 266 SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend, fsl_dcu_drm_pm_resume) 267 }; 268 269 static const struct fsl_dcu_soc_data fsl_dcu_ls1021a_data = { 270 .name = "ls1021a", 271 .total_layer = 16, 272 .max_layer = 4, 273 }; 274 275 static const struct fsl_dcu_soc_data fsl_dcu_vf610_data = { 276 .name = "vf610", 277 .total_layer = 64, 278 .max_layer = 6, 279 }; 280 281 static const struct of_device_id fsl_dcu_of_match[] = { 282 { 283 .compatible = "fsl,ls1021a-dcu", 284 .data = &fsl_dcu_ls1021a_data, 285 }, { 286 .compatible = "fsl,vf610-dcu", 287 .data = &fsl_dcu_vf610_data, 288 }, { 289 }, 290 }; 291 MODULE_DEVICE_TABLE(of, fsl_dcu_of_match); 292 293 static int fsl_dcu_drm_probe(struct platform_device *pdev) 294 { 295 struct fsl_dcu_drm_device *fsl_dev; 296 struct drm_device *drm; 297 struct device *dev = &pdev->dev; 298 struct resource *res; 299 void __iomem *base; 300 struct drm_driver *driver = &fsl_dcu_drm_driver; 301 const struct of_device_id *id; 302 int ret; 303 304 fsl_dev = devm_kzalloc(dev, sizeof(*fsl_dev), GFP_KERNEL); 305 if (!fsl_dev) 306 return -ENOMEM; 307 308 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 309 if (!res) { 310 dev_err(dev, "could not get memory IO resource\n"); 311 return -ENODEV; 312 } 313 314 base = devm_ioremap_resource(dev, res); 315 if (IS_ERR(base)) { 316 ret = PTR_ERR(base); 317 return ret; 318 } 319 320 fsl_dev->irq = platform_get_irq(pdev, 0); 321 if (fsl_dev->irq < 0) { 322 dev_err(dev, "failed to get irq\n"); 323 return -ENXIO; 324 } 325 326 fsl_dev->clk = devm_clk_get(dev, "dcu"); 327 if (IS_ERR(fsl_dev->clk)) { 328 ret = PTR_ERR(fsl_dev->clk); 329 dev_err(dev, "failed to get dcu clock\n"); 330 return ret; 331 } 332 ret = clk_prepare(fsl_dev->clk); 333 if (ret < 0) { 334 dev_err(dev, "failed to prepare dcu clk\n"); 335 return ret; 336 } 337 ret = clk_enable(fsl_dev->clk); 338 if (ret < 0) { 339 dev_err(dev, "failed to enable dcu clk\n"); 340 clk_unprepare(fsl_dev->clk); 341 return ret; 342 } 343 344 fsl_dev->regmap = devm_regmap_init_mmio(dev, base, 345 &fsl_dcu_regmap_config); 346 if (IS_ERR(fsl_dev->regmap)) { 347 dev_err(dev, "regmap init failed\n"); 348 return PTR_ERR(fsl_dev->regmap); 349 } 350 351 id = of_match_node(fsl_dcu_of_match, pdev->dev.of_node); 352 if (!id) 353 return -ENODEV; 354 fsl_dev->soc = id->data; 355 356 drm = drm_dev_alloc(driver, dev); 357 if (!drm) 358 return -ENOMEM; 359 360 fsl_dev->dev = dev; 361 fsl_dev->drm = drm; 362 fsl_dev->np = dev->of_node; 363 drm->dev_private = fsl_dev; 364 dev_set_drvdata(dev, fsl_dev); 365 drm_dev_set_unique(drm, dev_name(dev)); 366 367 ret = drm_dev_register(drm, 0); 368 if (ret < 0) 369 goto unref; 370 371 DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, 372 driver->major, driver->minor, driver->patchlevel, 373 driver->date, drm->primary->index); 374 375 return 0; 376 377 unref: 378 drm_dev_unref(drm); 379 return ret; 380 } 381 382 static int fsl_dcu_drm_remove(struct platform_device *pdev) 383 { 384 struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev); 385 386 drm_put_dev(fsl_dev->drm); 387 388 return 0; 389 } 390 391 static struct platform_driver fsl_dcu_drm_platform_driver = { 392 .probe = fsl_dcu_drm_probe, 393 .remove = fsl_dcu_drm_remove, 394 .driver = { 395 .name = "fsl-dcu", 396 .pm = &fsl_dcu_drm_pm_ops, 397 .of_match_table = fsl_dcu_of_match, 398 }, 399 }; 400 401 module_platform_driver(fsl_dcu_drm_platform_driver); 402 403 MODULE_DESCRIPTION("Freescale DCU DRM Driver"); 404 MODULE_LICENSE("GPL"); 405