1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2019-2022 Bootlin 4 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> 5 */ 6 7 #include <linux/bitfield.h> 8 #include <linux/clk.h> 9 #include <linux/mfd/syscon.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/of_address.h> 13 #include <linux/of_reserved_mem.h> 14 #include <linux/platform_device.h> 15 #include <linux/regmap.h> 16 #include <linux/types.h> 17 18 #include <drm/clients/drm_client_setup.h> 19 #include <drm/drm_atomic_helper.h> 20 #include <drm/drm_drv.h> 21 #include <drm/drm_fbdev_dma.h> 22 #include <drm/drm_fourcc.h> 23 #include <drm/drm_gem_dma_helper.h> 24 #include <drm/drm_print.h> 25 26 #include "logicvc_crtc.h" 27 #include "logicvc_drm.h" 28 #include "logicvc_interface.h" 29 #include "logicvc_mode.h" 30 #include "logicvc_layer.h" 31 #include "logicvc_of.h" 32 #include "logicvc_regs.h" 33 34 DEFINE_DRM_GEM_DMA_FOPS(logicvc_drm_fops); 35 36 static int logicvc_drm_gem_dma_dumb_create(struct drm_file *file_priv, 37 struct drm_device *drm_dev, 38 struct drm_mode_create_dumb *args) 39 { 40 struct logicvc_drm *logicvc = logicvc_drm(drm_dev); 41 42 /* Stride is always fixed to its configuration value. */ 43 args->pitch = logicvc->config.row_stride * DIV_ROUND_UP(args->bpp, 8); 44 45 return drm_gem_dma_dumb_create_internal(file_priv, drm_dev, args); 46 } 47 48 static struct drm_driver logicvc_drm_driver = { 49 .driver_features = DRIVER_GEM | DRIVER_MODESET | 50 DRIVER_ATOMIC, 51 52 .fops = &logicvc_drm_fops, 53 .name = "logicvc-drm", 54 .desc = "Xylon LogiCVC DRM driver", 55 .major = 1, 56 .minor = 0, 57 58 DRM_GEM_DMA_DRIVER_OPS_VMAP_WITH_DUMB_CREATE(logicvc_drm_gem_dma_dumb_create), 59 DRM_FBDEV_DMA_DRIVER_OPS, 60 }; 61 62 static struct regmap_config logicvc_drm_regmap_config = { 63 .reg_bits = 32, 64 .val_bits = 32, 65 .reg_stride = 4, 66 .name = "logicvc-drm", 67 }; 68 69 static irqreturn_t logicvc_drm_irq_handler(int irq, void *data) 70 { 71 struct logicvc_drm *logicvc = data; 72 irqreturn_t ret = IRQ_NONE; 73 u32 stat = 0; 74 75 /* Get pending interrupt sources. */ 76 regmap_read(logicvc->regmap, LOGICVC_INT_STAT_REG, &stat); 77 78 /* Clear all pending interrupt sources. */ 79 regmap_write(logicvc->regmap, LOGICVC_INT_STAT_REG, stat); 80 81 if (stat & LOGICVC_INT_STAT_V_SYNC) { 82 logicvc_crtc_vblank_handler(logicvc); 83 ret = IRQ_HANDLED; 84 } 85 86 return ret; 87 } 88 89 static int logicvc_drm_config_parse(struct logicvc_drm *logicvc) 90 { 91 struct drm_device *drm_dev = &logicvc->drm_dev; 92 struct device *dev = drm_dev->dev; 93 struct device_node *of_node = dev->of_node; 94 struct logicvc_drm_config *config = &logicvc->config; 95 struct device_node *layers_node; 96 int ret; 97 98 logicvc_of_property_parse_bool(of_node, LOGICVC_OF_PROPERTY_DITHERING, 99 &config->dithering); 100 logicvc_of_property_parse_bool(of_node, 101 LOGICVC_OF_PROPERTY_BACKGROUND_LAYER, 102 &config->background_layer); 103 logicvc_of_property_parse_bool(of_node, 104 LOGICVC_OF_PROPERTY_LAYERS_CONFIGURABLE, 105 &config->layers_configurable); 106 107 ret = logicvc_of_property_parse_u32(of_node, 108 LOGICVC_OF_PROPERTY_DISPLAY_INTERFACE, 109 &config->display_interface); 110 if (ret) 111 return ret; 112 113 ret = logicvc_of_property_parse_u32(of_node, 114 LOGICVC_OF_PROPERTY_DISPLAY_COLORSPACE, 115 &config->display_colorspace); 116 if (ret) 117 return ret; 118 119 ret = logicvc_of_property_parse_u32(of_node, 120 LOGICVC_OF_PROPERTY_DISPLAY_DEPTH, 121 &config->display_depth); 122 if (ret) 123 return ret; 124 125 ret = logicvc_of_property_parse_u32(of_node, 126 LOGICVC_OF_PROPERTY_ROW_STRIDE, 127 &config->row_stride); 128 if (ret) 129 return ret; 130 131 layers_node = of_get_child_by_name(of_node, "layers"); 132 if (!layers_node) { 133 drm_err(drm_dev, "Missing non-optional layers node\n"); 134 return -EINVAL; 135 } 136 137 config->layers_count = of_get_child_count(layers_node); 138 if (!config->layers_count) { 139 drm_err(drm_dev, 140 "Missing a non-optional layers children node\n"); 141 return -EINVAL; 142 } 143 144 return 0; 145 } 146 147 static int logicvc_clocks_prepare(struct logicvc_drm *logicvc) 148 { 149 struct drm_device *drm_dev = &logicvc->drm_dev; 150 struct device *dev = drm_dev->dev; 151 152 struct { 153 struct clk **clk; 154 char *name; 155 bool optional; 156 } clocks_map[] = { 157 { 158 .clk = &logicvc->vclk, 159 .name = "vclk", 160 .optional = false, 161 }, 162 { 163 .clk = &logicvc->vclk2, 164 .name = "vclk2", 165 .optional = true, 166 }, 167 { 168 .clk = &logicvc->lvdsclk, 169 .name = "lvdsclk", 170 .optional = true, 171 }, 172 { 173 .clk = &logicvc->lvdsclkn, 174 .name = "lvdsclkn", 175 .optional = true, 176 }, 177 }; 178 unsigned int i; 179 int ret; 180 181 for (i = 0; i < ARRAY_SIZE(clocks_map); i++) { 182 struct clk *clk; 183 184 clk = devm_clk_get(dev, clocks_map[i].name); 185 if (IS_ERR(clk)) { 186 if (PTR_ERR(clk) == -ENOENT && clocks_map[i].optional) 187 continue; 188 189 drm_err(drm_dev, "Missing non-optional clock %s\n", 190 clocks_map[i].name); 191 192 ret = PTR_ERR(clk); 193 goto error; 194 } 195 196 ret = clk_prepare_enable(clk); 197 if (ret) { 198 drm_err(drm_dev, 199 "Failed to prepare and enable clock %s\n", 200 clocks_map[i].name); 201 goto error; 202 } 203 204 *clocks_map[i].clk = clk; 205 } 206 207 return 0; 208 209 error: 210 for (i = 0; i < ARRAY_SIZE(clocks_map); i++) { 211 if (!*clocks_map[i].clk) 212 continue; 213 214 clk_disable_unprepare(*clocks_map[i].clk); 215 *clocks_map[i].clk = NULL; 216 } 217 218 return ret; 219 } 220 221 static int logicvc_clocks_unprepare(struct logicvc_drm *logicvc) 222 { 223 struct clk **clocks[] = { 224 &logicvc->vclk, 225 &logicvc->vclk2, 226 &logicvc->lvdsclk, 227 &logicvc->lvdsclkn, 228 }; 229 unsigned int i; 230 231 for (i = 0; i < ARRAY_SIZE(clocks); i++) { 232 if (!*clocks[i]) 233 continue; 234 235 clk_disable_unprepare(*clocks[i]); 236 *clocks[i] = NULL; 237 } 238 239 return 0; 240 } 241 242 static const struct logicvc_drm_caps logicvc_drm_caps[] = { 243 { 244 .major = 3, 245 .layer_address = false, 246 }, 247 { 248 .major = 4, 249 .layer_address = true, 250 }, 251 { 252 .major = 5, 253 .layer_address = true, 254 }, 255 }; 256 257 static const struct logicvc_drm_caps * 258 logicvc_drm_caps_match(struct logicvc_drm *logicvc) 259 { 260 struct drm_device *drm_dev = &logicvc->drm_dev; 261 const struct logicvc_drm_caps *caps = NULL; 262 unsigned int major, minor; 263 char level; 264 unsigned int i; 265 u32 version; 266 267 regmap_read(logicvc->regmap, LOGICVC_IP_VERSION_REG, &version); 268 269 major = FIELD_GET(LOGICVC_IP_VERSION_MAJOR_MASK, version); 270 minor = FIELD_GET(LOGICVC_IP_VERSION_MINOR_MASK, version); 271 level = FIELD_GET(LOGICVC_IP_VERSION_LEVEL_MASK, version) + 'a'; 272 273 for (i = 0; i < ARRAY_SIZE(logicvc_drm_caps); i++) { 274 if (logicvc_drm_caps[i].major && 275 logicvc_drm_caps[i].major != major) 276 continue; 277 278 if (logicvc_drm_caps[i].minor && 279 logicvc_drm_caps[i].minor != minor) 280 continue; 281 282 if (logicvc_drm_caps[i].level && 283 logicvc_drm_caps[i].level != level) 284 continue; 285 286 caps = &logicvc_drm_caps[i]; 287 } 288 289 drm_info(drm_dev, "LogiCVC version %d.%02d.%c\n", major, minor, level); 290 291 return caps; 292 } 293 294 static int logicvc_drm_probe(struct platform_device *pdev) 295 { 296 struct device_node *of_node = pdev->dev.of_node; 297 struct device_node *reserved_mem_node; 298 struct reserved_mem *reserved_mem = NULL; 299 const struct logicvc_drm_caps *caps; 300 struct logicvc_drm *logicvc; 301 struct device *dev = &pdev->dev; 302 struct drm_device *drm_dev; 303 struct regmap *regmap = NULL; 304 struct resource res; 305 void __iomem *base; 306 int irq; 307 int ret; 308 309 ret = of_reserved_mem_device_init(dev); 310 if (ret && ret != -ENODEV) { 311 dev_err(dev, "Failed to init memory region\n"); 312 goto error_early; 313 } 314 315 reserved_mem_node = of_parse_phandle(of_node, "memory-region", 0); 316 if (reserved_mem_node) { 317 reserved_mem = of_reserved_mem_lookup(reserved_mem_node); 318 of_node_put(reserved_mem_node); 319 } 320 321 /* Get regmap from parent if available. */ 322 if (of_node->parent) 323 regmap = syscon_node_to_regmap(of_node->parent); 324 325 /* Register our own regmap otherwise. */ 326 if (IS_ERR_OR_NULL(regmap)) { 327 ret = of_address_to_resource(of_node, 0, &res); 328 if (ret) { 329 dev_err(dev, "Failed to get resource from address\n"); 330 goto error_reserved_mem; 331 } 332 333 base = devm_ioremap_resource(dev, &res); 334 if (IS_ERR(base)) { 335 dev_err(dev, "Failed to map I/O base\n"); 336 ret = PTR_ERR(base); 337 goto error_reserved_mem; 338 } 339 340 logicvc_drm_regmap_config.max_register = resource_size(&res) - 341 4; 342 343 regmap = devm_regmap_init_mmio(dev, base, 344 &logicvc_drm_regmap_config); 345 if (IS_ERR(regmap)) { 346 dev_err(dev, "Failed to create regmap for I/O\n"); 347 ret = PTR_ERR(regmap); 348 goto error_reserved_mem; 349 } 350 } 351 352 irq = platform_get_irq(pdev, 0); 353 if (irq < 0) { 354 ret = -ENODEV; 355 goto error_reserved_mem; 356 } 357 358 logicvc = devm_drm_dev_alloc(dev, &logicvc_drm_driver, 359 struct logicvc_drm, drm_dev); 360 if (IS_ERR(logicvc)) { 361 ret = PTR_ERR(logicvc); 362 goto error_reserved_mem; 363 } 364 365 platform_set_drvdata(pdev, logicvc); 366 drm_dev = &logicvc->drm_dev; 367 368 logicvc->regmap = regmap; 369 INIT_LIST_HEAD(&logicvc->layers_list); 370 371 caps = logicvc_drm_caps_match(logicvc); 372 if (!caps) { 373 ret = -EINVAL; 374 goto error_reserved_mem; 375 } 376 377 logicvc->caps = caps; 378 379 if (reserved_mem) 380 logicvc->reserved_mem_base = reserved_mem->base; 381 382 ret = logicvc_clocks_prepare(logicvc); 383 if (ret) { 384 drm_err(drm_dev, "Failed to prepare clocks\n"); 385 goto error_reserved_mem; 386 } 387 388 ret = devm_request_irq(dev, irq, logicvc_drm_irq_handler, 0, 389 dev_name(dev), logicvc); 390 if (ret) { 391 drm_err(drm_dev, "Failed to request IRQ\n"); 392 goto error_clocks; 393 } 394 395 ret = logicvc_drm_config_parse(logicvc); 396 if (ret && ret != -ENODEV) { 397 drm_err(drm_dev, "Failed to parse config\n"); 398 goto error_clocks; 399 } 400 401 ret = drmm_mode_config_init(drm_dev); 402 if (ret) { 403 drm_err(drm_dev, "Failed to init mode config\n"); 404 goto error_clocks; 405 } 406 407 ret = logicvc_layers_init(logicvc); 408 if (ret) { 409 drm_err(drm_dev, "Failed to initialize layers\n"); 410 goto error_clocks; 411 } 412 413 ret = logicvc_crtc_init(logicvc); 414 if (ret) { 415 drm_err(drm_dev, "Failed to initialize CRTC\n"); 416 goto error_clocks; 417 } 418 419 logicvc_layers_attach_crtc(logicvc); 420 421 ret = logicvc_interface_init(logicvc); 422 if (ret) { 423 if (ret != -EPROBE_DEFER) 424 drm_err(drm_dev, "Failed to initialize interface\n"); 425 426 goto error_clocks; 427 } 428 429 logicvc_interface_attach_crtc(logicvc); 430 431 ret = logicvc_mode_init(logicvc); 432 if (ret) { 433 drm_err(drm_dev, "Failed to initialize KMS\n"); 434 goto error_clocks; 435 } 436 437 ret = drm_dev_register(drm_dev, 0); 438 if (ret) { 439 drm_err(drm_dev, "Failed to register DRM device\n"); 440 goto error_mode; 441 } 442 443 drm_client_setup(drm_dev, NULL); 444 445 return 0; 446 447 error_mode: 448 logicvc_mode_fini(logicvc); 449 450 error_clocks: 451 logicvc_clocks_unprepare(logicvc); 452 453 error_reserved_mem: 454 of_reserved_mem_device_release(dev); 455 456 error_early: 457 return ret; 458 } 459 460 static void logicvc_drm_remove(struct platform_device *pdev) 461 { 462 struct logicvc_drm *logicvc = platform_get_drvdata(pdev); 463 struct device *dev = &pdev->dev; 464 struct drm_device *drm_dev = &logicvc->drm_dev; 465 466 drm_dev_unregister(drm_dev); 467 drm_atomic_helper_shutdown(drm_dev); 468 469 logicvc_mode_fini(logicvc); 470 471 logicvc_clocks_unprepare(logicvc); 472 473 of_reserved_mem_device_release(dev); 474 } 475 476 static void logicvc_drm_shutdown(struct platform_device *pdev) 477 { 478 struct logicvc_drm *logicvc = platform_get_drvdata(pdev); 479 struct drm_device *drm_dev = &logicvc->drm_dev; 480 481 drm_atomic_helper_shutdown(drm_dev); 482 } 483 484 static const struct of_device_id logicvc_drm_of_table[] = { 485 { .compatible = "xylon,logicvc-3.02.a-display" }, 486 { .compatible = "xylon,logicvc-4.01.a-display" }, 487 {}, 488 }; 489 MODULE_DEVICE_TABLE(of, logicvc_drm_of_table); 490 491 static struct platform_driver logicvc_drm_platform_driver = { 492 .probe = logicvc_drm_probe, 493 .remove = logicvc_drm_remove, 494 .shutdown = logicvc_drm_shutdown, 495 .driver = { 496 .name = "logicvc-drm", 497 .of_match_table = logicvc_drm_of_table, 498 }, 499 }; 500 501 module_platform_driver(logicvc_drm_platform_driver); 502 503 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); 504 MODULE_DESCRIPTION("Xylon LogiCVC DRM driver"); 505 MODULE_LICENSE("GPL"); 506