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, unsigned int pipe) 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, 160 unsigned int pipe) 161 { 162 struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; 163 unsigned int value; 164 int ret; 165 166 ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value); 167 if (ret) 168 dev_err(dev->dev, "read DCU_INT_MASK failed\n"); 169 value |= DCU_INT_MASK_VBLANK; 170 ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value); 171 if (ret) 172 dev_err(dev->dev, "set DCU_INT_MASK failed\n"); 173 } 174 175 static const struct file_operations fsl_dcu_drm_fops = { 176 .owner = THIS_MODULE, 177 .open = drm_open, 178 .release = drm_release, 179 .unlocked_ioctl = drm_ioctl, 180 #ifdef CONFIG_COMPAT 181 .compat_ioctl = drm_compat_ioctl, 182 #endif 183 .poll = drm_poll, 184 .read = drm_read, 185 .llseek = no_llseek, 186 .mmap = drm_gem_cma_mmap, 187 }; 188 189 static struct drm_driver fsl_dcu_drm_driver = { 190 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET 191 | DRIVER_PRIME | DRIVER_ATOMIC, 192 .load = fsl_dcu_load, 193 .unload = fsl_dcu_unload, 194 .preclose = fsl_dcu_drm_preclose, 195 .irq_handler = fsl_dcu_drm_irq, 196 .get_vblank_counter = drm_vblank_no_hw_counter, 197 .enable_vblank = fsl_dcu_drm_enable_vblank, 198 .disable_vblank = fsl_dcu_drm_disable_vblank, 199 .gem_free_object = drm_gem_cma_free_object, 200 .gem_vm_ops = &drm_gem_cma_vm_ops, 201 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 202 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 203 .gem_prime_import = drm_gem_prime_import, 204 .gem_prime_export = drm_gem_prime_export, 205 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 206 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 207 .gem_prime_vmap = drm_gem_cma_prime_vmap, 208 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 209 .gem_prime_mmap = drm_gem_cma_prime_mmap, 210 .dumb_create = drm_gem_cma_dumb_create, 211 .dumb_map_offset = drm_gem_cma_dumb_map_offset, 212 .dumb_destroy = drm_gem_dumb_destroy, 213 .fops = &fsl_dcu_drm_fops, 214 .name = "fsl-dcu-drm", 215 .desc = "Freescale DCU DRM", 216 .date = "20150213", 217 .major = 1, 218 .minor = 0, 219 }; 220 221 #ifdef CONFIG_PM_SLEEP 222 static int fsl_dcu_drm_pm_suspend(struct device *dev) 223 { 224 struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev); 225 226 if (!fsl_dev) 227 return 0; 228 229 drm_kms_helper_poll_disable(fsl_dev->drm); 230 regcache_cache_only(fsl_dev->regmap, true); 231 regcache_mark_dirty(fsl_dev->regmap); 232 clk_disable(fsl_dev->clk); 233 clk_unprepare(fsl_dev->clk); 234 235 return 0; 236 } 237 238 static int fsl_dcu_drm_pm_resume(struct device *dev) 239 { 240 struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev); 241 int ret; 242 243 if (!fsl_dev) 244 return 0; 245 246 ret = clk_enable(fsl_dev->clk); 247 if (ret < 0) { 248 dev_err(dev, "failed to enable dcu clk\n"); 249 clk_unprepare(fsl_dev->clk); 250 return ret; 251 } 252 ret = clk_prepare(fsl_dev->clk); 253 if (ret < 0) { 254 dev_err(dev, "failed to prepare dcu clk\n"); 255 return ret; 256 } 257 258 drm_kms_helper_poll_enable(fsl_dev->drm); 259 regcache_cache_only(fsl_dev->regmap, false); 260 regcache_sync(fsl_dev->regmap); 261 262 return 0; 263 } 264 #endif 265 266 static const struct dev_pm_ops fsl_dcu_drm_pm_ops = { 267 SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend, fsl_dcu_drm_pm_resume) 268 }; 269 270 static const struct fsl_dcu_soc_data fsl_dcu_ls1021a_data = { 271 .name = "ls1021a", 272 .total_layer = 16, 273 .max_layer = 4, 274 }; 275 276 static const struct fsl_dcu_soc_data fsl_dcu_vf610_data = { 277 .name = "vf610", 278 .total_layer = 64, 279 .max_layer = 6, 280 }; 281 282 static const struct of_device_id fsl_dcu_of_match[] = { 283 { 284 .compatible = "fsl,ls1021a-dcu", 285 .data = &fsl_dcu_ls1021a_data, 286 }, { 287 .compatible = "fsl,vf610-dcu", 288 .data = &fsl_dcu_vf610_data, 289 }, { 290 }, 291 }; 292 MODULE_DEVICE_TABLE(of, fsl_dcu_of_match); 293 294 static int fsl_dcu_drm_probe(struct platform_device *pdev) 295 { 296 struct fsl_dcu_drm_device *fsl_dev; 297 struct drm_device *drm; 298 struct device *dev = &pdev->dev; 299 struct resource *res; 300 void __iomem *base; 301 struct drm_driver *driver = &fsl_dcu_drm_driver; 302 const struct of_device_id *id; 303 int ret; 304 305 fsl_dev = devm_kzalloc(dev, sizeof(*fsl_dev), GFP_KERNEL); 306 if (!fsl_dev) 307 return -ENOMEM; 308 309 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 310 if (!res) { 311 dev_err(dev, "could not get memory IO resource\n"); 312 return -ENODEV; 313 } 314 315 base = devm_ioremap_resource(dev, res); 316 if (IS_ERR(base)) { 317 ret = PTR_ERR(base); 318 return ret; 319 } 320 321 fsl_dev->irq = platform_get_irq(pdev, 0); 322 if (fsl_dev->irq < 0) { 323 dev_err(dev, "failed to get irq\n"); 324 return -ENXIO; 325 } 326 327 fsl_dev->clk = devm_clk_get(dev, "dcu"); 328 if (IS_ERR(fsl_dev->clk)) { 329 ret = PTR_ERR(fsl_dev->clk); 330 dev_err(dev, "failed to get dcu clock\n"); 331 return ret; 332 } 333 ret = clk_prepare(fsl_dev->clk); 334 if (ret < 0) { 335 dev_err(dev, "failed to prepare dcu clk\n"); 336 return ret; 337 } 338 ret = clk_enable(fsl_dev->clk); 339 if (ret < 0) { 340 dev_err(dev, "failed to enable dcu clk\n"); 341 clk_unprepare(fsl_dev->clk); 342 return ret; 343 } 344 345 fsl_dev->regmap = devm_regmap_init_mmio(dev, base, 346 &fsl_dcu_regmap_config); 347 if (IS_ERR(fsl_dev->regmap)) { 348 dev_err(dev, "regmap init failed\n"); 349 return PTR_ERR(fsl_dev->regmap); 350 } 351 352 id = of_match_node(fsl_dcu_of_match, pdev->dev.of_node); 353 if (!id) 354 return -ENODEV; 355 fsl_dev->soc = id->data; 356 357 drm = drm_dev_alloc(driver, dev); 358 if (!drm) 359 return -ENOMEM; 360 361 fsl_dev->dev = dev; 362 fsl_dev->drm = drm; 363 fsl_dev->np = dev->of_node; 364 drm->dev_private = fsl_dev; 365 dev_set_drvdata(dev, fsl_dev); 366 drm_dev_set_unique(drm, dev_name(dev)); 367 368 ret = drm_dev_register(drm, 0); 369 if (ret < 0) 370 goto unref; 371 372 DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, 373 driver->major, driver->minor, driver->patchlevel, 374 driver->date, drm->primary->index); 375 376 return 0; 377 378 unref: 379 drm_dev_unref(drm); 380 return ret; 381 } 382 383 static int fsl_dcu_drm_remove(struct platform_device *pdev) 384 { 385 struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev); 386 387 drm_put_dev(fsl_dev->drm); 388 389 return 0; 390 } 391 392 static struct platform_driver fsl_dcu_drm_platform_driver = { 393 .probe = fsl_dcu_drm_probe, 394 .remove = fsl_dcu_drm_remove, 395 .driver = { 396 .name = "fsl-dcu", 397 .pm = &fsl_dcu_drm_pm_ops, 398 .of_match_table = fsl_dcu_of_match, 399 }, 400 }; 401 402 module_platform_driver(fsl_dcu_drm_platform_driver); 403 404 MODULE_DESCRIPTION("Freescale DCU DRM Driver"); 405 MODULE_LICENSE("GPL"); 406