1 /* 2 * Copyright (C) 2015 Free Electrons 3 * Copyright (C) 2015 NextThing Co 4 * 5 * Maxime Ripard <maxime.ripard@free-electrons.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 */ 12 13 #include <drm/drmP.h> 14 #include <drm/drm_atomic_helper.h> 15 #include <drm/drm_crtc.h> 16 #include <drm/drm_crtc_helper.h> 17 #include <drm/drm_fb_cma_helper.h> 18 #include <drm/drm_gem_cma_helper.h> 19 #include <drm/drm_plane_helper.h> 20 21 #include <linux/component.h> 22 #include <linux/list.h> 23 #include <linux/of_device.h> 24 #include <linux/of_graph.h> 25 #include <linux/reset.h> 26 27 #include "sun4i_backend.h" 28 #include "sun4i_drv.h" 29 #include "sun4i_layer.h" 30 #include "sunxi_engine.h" 31 32 struct sun4i_backend_quirks { 33 /* backend <-> TCON muxing selection done in backend */ 34 bool needs_output_muxing; 35 }; 36 37 static const u32 sunxi_rgb2yuv_coef[12] = { 38 0x00000107, 0x00000204, 0x00000064, 0x00000108, 39 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808, 40 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 41 }; 42 43 static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) 44 { 45 int i; 46 47 DRM_DEBUG_DRIVER("Applying RGB to YUV color correction\n"); 48 49 /* Set color correction */ 50 regmap_write(engine->regs, SUN4I_BACKEND_OCCTL_REG, 51 SUN4I_BACKEND_OCCTL_ENABLE); 52 53 for (i = 0; i < 12; i++) 54 regmap_write(engine->regs, SUN4I_BACKEND_OCRCOEF_REG(i), 55 sunxi_rgb2yuv_coef[i]); 56 } 57 58 static void sun4i_backend_disable_color_correction(struct sunxi_engine *engine) 59 { 60 DRM_DEBUG_DRIVER("Disabling color correction\n"); 61 62 /* Disable color correction */ 63 regmap_update_bits(engine->regs, SUN4I_BACKEND_OCCTL_REG, 64 SUN4I_BACKEND_OCCTL_ENABLE, 0); 65 } 66 67 static void sun4i_backend_commit(struct sunxi_engine *engine) 68 { 69 DRM_DEBUG_DRIVER("Committing changes\n"); 70 71 regmap_write(engine->regs, SUN4I_BACKEND_REGBUFFCTL_REG, 72 SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS | 73 SUN4I_BACKEND_REGBUFFCTL_LOADCTL); 74 } 75 76 void sun4i_backend_layer_enable(struct sun4i_backend *backend, 77 int layer, bool enable) 78 { 79 u32 val; 80 81 DRM_DEBUG_DRIVER("%sabling layer %d\n", enable ? "En" : "Dis", 82 layer); 83 84 if (enable) 85 val = SUN4I_BACKEND_MODCTL_LAY_EN(layer); 86 else 87 val = 0; 88 89 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG, 90 SUN4I_BACKEND_MODCTL_LAY_EN(layer), val); 91 } 92 93 static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane, 94 u32 format, u32 *mode) 95 { 96 if ((plane->type == DRM_PLANE_TYPE_PRIMARY) && 97 (format == DRM_FORMAT_ARGB8888)) 98 format = DRM_FORMAT_XRGB8888; 99 100 switch (format) { 101 case DRM_FORMAT_ARGB8888: 102 *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888; 103 break; 104 105 case DRM_FORMAT_ARGB4444: 106 *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB4444; 107 break; 108 109 case DRM_FORMAT_ARGB1555: 110 *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB1555; 111 break; 112 113 case DRM_FORMAT_RGBA5551: 114 *mode = SUN4I_BACKEND_LAY_FBFMT_RGBA5551; 115 break; 116 117 case DRM_FORMAT_RGBA4444: 118 *mode = SUN4I_BACKEND_LAY_FBFMT_RGBA4444; 119 break; 120 121 case DRM_FORMAT_XRGB8888: 122 *mode = SUN4I_BACKEND_LAY_FBFMT_XRGB8888; 123 break; 124 125 case DRM_FORMAT_RGB888: 126 *mode = SUN4I_BACKEND_LAY_FBFMT_RGB888; 127 break; 128 129 case DRM_FORMAT_RGB565: 130 *mode = SUN4I_BACKEND_LAY_FBFMT_RGB565; 131 break; 132 133 default: 134 return -EINVAL; 135 } 136 137 return 0; 138 } 139 140 int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, 141 int layer, struct drm_plane *plane) 142 { 143 struct drm_plane_state *state = plane->state; 144 struct drm_framebuffer *fb = state->fb; 145 146 DRM_DEBUG_DRIVER("Updating layer %d\n", layer); 147 148 if (plane->type == DRM_PLANE_TYPE_PRIMARY) { 149 DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n", 150 state->crtc_w, state->crtc_h); 151 regmap_write(backend->engine.regs, SUN4I_BACKEND_DISSIZE_REG, 152 SUN4I_BACKEND_DISSIZE(state->crtc_w, 153 state->crtc_h)); 154 } 155 156 /* Set the line width */ 157 DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); 158 regmap_write(backend->engine.regs, 159 SUN4I_BACKEND_LAYLINEWIDTH_REG(layer), 160 fb->pitches[0] * 8); 161 162 /* Set height and width */ 163 DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n", 164 state->crtc_w, state->crtc_h); 165 regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYSIZE_REG(layer), 166 SUN4I_BACKEND_LAYSIZE(state->crtc_w, 167 state->crtc_h)); 168 169 /* Set base coordinates */ 170 DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n", 171 state->crtc_x, state->crtc_y); 172 regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYCOOR_REG(layer), 173 SUN4I_BACKEND_LAYCOOR(state->crtc_x, 174 state->crtc_y)); 175 176 return 0; 177 } 178 179 int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, 180 int layer, struct drm_plane *plane) 181 { 182 struct drm_plane_state *state = plane->state; 183 struct drm_framebuffer *fb = state->fb; 184 bool interlaced = false; 185 u32 val; 186 int ret; 187 188 if (plane->state->crtc) 189 interlaced = plane->state->crtc->state->adjusted_mode.flags 190 & DRM_MODE_FLAG_INTERLACE; 191 192 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG, 193 SUN4I_BACKEND_MODCTL_ITLMOD_EN, 194 interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0); 195 196 DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", 197 interlaced ? "on" : "off"); 198 199 ret = sun4i_backend_drm_format_to_layer(plane, fb->format->format, 200 &val); 201 if (ret) { 202 DRM_DEBUG_DRIVER("Invalid format\n"); 203 return ret; 204 } 205 206 regmap_update_bits(backend->engine.regs, 207 SUN4I_BACKEND_ATTCTL_REG1(layer), 208 SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val); 209 210 return 0; 211 } 212 213 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, 214 int layer, struct drm_plane *plane) 215 { 216 struct drm_plane_state *state = plane->state; 217 struct drm_framebuffer *fb = state->fb; 218 u32 lo_paddr, hi_paddr; 219 dma_addr_t paddr; 220 221 /* Get the start of the displayed memory */ 222 paddr = drm_fb_cma_get_gem_addr(fb, state, 0); 223 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); 224 225 /* 226 * backend DMA accesses DRAM directly, bypassing the system 227 * bus. As such, the address range is different and the buffer 228 * address needs to be corrected. 229 */ 230 paddr -= PHYS_OFFSET; 231 232 /* Write the 32 lower bits of the address (in bits) */ 233 lo_paddr = paddr << 3; 234 DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr); 235 regmap_write(backend->engine.regs, 236 SUN4I_BACKEND_LAYFB_L32ADD_REG(layer), 237 lo_paddr); 238 239 /* And the upper bits */ 240 hi_paddr = paddr >> 29; 241 DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", hi_paddr); 242 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_LAYFB_H4ADD_REG, 243 SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer), 244 SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr)); 245 246 return 0; 247 } 248 249 static int sun4i_backend_init_sat(struct device *dev) { 250 struct sun4i_backend *backend = dev_get_drvdata(dev); 251 int ret; 252 253 backend->sat_reset = devm_reset_control_get(dev, "sat"); 254 if (IS_ERR(backend->sat_reset)) { 255 dev_err(dev, "Couldn't get the SAT reset line\n"); 256 return PTR_ERR(backend->sat_reset); 257 } 258 259 ret = reset_control_deassert(backend->sat_reset); 260 if (ret) { 261 dev_err(dev, "Couldn't deassert the SAT reset line\n"); 262 return ret; 263 } 264 265 backend->sat_clk = devm_clk_get(dev, "sat"); 266 if (IS_ERR(backend->sat_clk)) { 267 dev_err(dev, "Couldn't get our SAT clock\n"); 268 ret = PTR_ERR(backend->sat_clk); 269 goto err_assert_reset; 270 } 271 272 ret = clk_prepare_enable(backend->sat_clk); 273 if (ret) { 274 dev_err(dev, "Couldn't enable the SAT clock\n"); 275 return ret; 276 } 277 278 return 0; 279 280 err_assert_reset: 281 reset_control_assert(backend->sat_reset); 282 return ret; 283 } 284 285 static int sun4i_backend_free_sat(struct device *dev) { 286 struct sun4i_backend *backend = dev_get_drvdata(dev); 287 288 clk_disable_unprepare(backend->sat_clk); 289 reset_control_assert(backend->sat_reset); 290 291 return 0; 292 } 293 294 /* 295 * The display backend can take video output from the display frontend, or 296 * the display enhancement unit on the A80, as input for one it its layers. 297 * This relationship within the display pipeline is encoded in the device 298 * tree with of_graph, and we use it here to figure out which backend, if 299 * there are 2 or more, we are currently probing. The number would be in 300 * the "reg" property of the upstream output port endpoint. 301 */ 302 static int sun4i_backend_of_get_id(struct device_node *node) 303 { 304 struct device_node *port, *ep; 305 int ret = -EINVAL; 306 307 /* input is port 0 */ 308 port = of_graph_get_port_by_id(node, 0); 309 if (!port) 310 return -EINVAL; 311 312 /* try finding an upstream endpoint */ 313 for_each_available_child_of_node(port, ep) { 314 struct device_node *remote; 315 u32 reg; 316 317 remote = of_graph_get_remote_endpoint(ep); 318 if (!remote) 319 continue; 320 321 ret = of_property_read_u32(remote, "reg", ®); 322 if (ret) 323 continue; 324 325 ret = reg; 326 } 327 328 of_node_put(port); 329 330 return ret; 331 } 332 333 static const struct sunxi_engine_ops sun4i_backend_engine_ops = { 334 .commit = sun4i_backend_commit, 335 .layers_init = sun4i_layers_init, 336 .apply_color_correction = sun4i_backend_apply_color_correction, 337 .disable_color_correction = sun4i_backend_disable_color_correction, 338 }; 339 340 static struct regmap_config sun4i_backend_regmap_config = { 341 .reg_bits = 32, 342 .val_bits = 32, 343 .reg_stride = 4, 344 .max_register = 0x5800, 345 }; 346 347 static int sun4i_backend_bind(struct device *dev, struct device *master, 348 void *data) 349 { 350 struct platform_device *pdev = to_platform_device(dev); 351 struct drm_device *drm = data; 352 struct sun4i_drv *drv = drm->dev_private; 353 struct sun4i_backend *backend; 354 const struct sun4i_backend_quirks *quirks; 355 struct resource *res; 356 void __iomem *regs; 357 int i, ret; 358 359 backend = devm_kzalloc(dev, sizeof(*backend), GFP_KERNEL); 360 if (!backend) 361 return -ENOMEM; 362 dev_set_drvdata(dev, backend); 363 364 backend->engine.node = dev->of_node; 365 backend->engine.ops = &sun4i_backend_engine_ops; 366 backend->engine.id = sun4i_backend_of_get_id(dev->of_node); 367 if (backend->engine.id < 0) 368 return backend->engine.id; 369 370 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 371 regs = devm_ioremap_resource(dev, res); 372 if (IS_ERR(regs)) 373 return PTR_ERR(regs); 374 375 backend->reset = devm_reset_control_get(dev, NULL); 376 if (IS_ERR(backend->reset)) { 377 dev_err(dev, "Couldn't get our reset line\n"); 378 return PTR_ERR(backend->reset); 379 } 380 381 ret = reset_control_deassert(backend->reset); 382 if (ret) { 383 dev_err(dev, "Couldn't deassert our reset line\n"); 384 return ret; 385 } 386 387 backend->bus_clk = devm_clk_get(dev, "ahb"); 388 if (IS_ERR(backend->bus_clk)) { 389 dev_err(dev, "Couldn't get the backend bus clock\n"); 390 ret = PTR_ERR(backend->bus_clk); 391 goto err_assert_reset; 392 } 393 clk_prepare_enable(backend->bus_clk); 394 395 backend->mod_clk = devm_clk_get(dev, "mod"); 396 if (IS_ERR(backend->mod_clk)) { 397 dev_err(dev, "Couldn't get the backend module clock\n"); 398 ret = PTR_ERR(backend->mod_clk); 399 goto err_disable_bus_clk; 400 } 401 clk_prepare_enable(backend->mod_clk); 402 403 backend->ram_clk = devm_clk_get(dev, "ram"); 404 if (IS_ERR(backend->ram_clk)) { 405 dev_err(dev, "Couldn't get the backend RAM clock\n"); 406 ret = PTR_ERR(backend->ram_clk); 407 goto err_disable_mod_clk; 408 } 409 clk_prepare_enable(backend->ram_clk); 410 411 if (of_device_is_compatible(dev->of_node, 412 "allwinner,sun8i-a33-display-backend")) { 413 ret = sun4i_backend_init_sat(dev); 414 if (ret) { 415 dev_err(dev, "Couldn't init SAT resources\n"); 416 goto err_disable_ram_clk; 417 } 418 } 419 420 backend->engine.regs = devm_regmap_init_mmio(dev, regs, 421 &sun4i_backend_regmap_config); 422 if (IS_ERR(backend->engine.regs)) { 423 dev_err(dev, "Couldn't create the backend regmap\n"); 424 return PTR_ERR(backend->engine.regs); 425 } 426 427 list_add_tail(&backend->engine.list, &drv->engine_list); 428 429 /* 430 * Many of the backend's layer configuration registers have 431 * undefined default values. This poses a risk as we use 432 * regmap_update_bits in some places, and don't overwrite 433 * the whole register. 434 * 435 * Clear the registers here to have something predictable. 436 */ 437 for (i = 0x800; i < 0x1000; i += 4) 438 regmap_write(backend->engine.regs, i, 0); 439 440 /* Disable registers autoloading */ 441 regmap_write(backend->engine.regs, SUN4I_BACKEND_REGBUFFCTL_REG, 442 SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS); 443 444 /* Enable the backend */ 445 regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG, 446 SUN4I_BACKEND_MODCTL_DEBE_EN | 447 SUN4I_BACKEND_MODCTL_START_CTL); 448 449 /* Set output selection if needed */ 450 quirks = of_device_get_match_data(dev); 451 if (quirks->needs_output_muxing) { 452 /* 453 * We assume there is no dynamic muxing of backends 454 * and TCONs, so we select the backend with same ID. 455 * 456 * While dynamic selection might be interesting, since 457 * the CRTC is tied to the TCON, while the layers are 458 * tied to the backends, this means, we will need to 459 * switch between groups of layers. There might not be 460 * a way to represent this constraint in DRM. 461 */ 462 regmap_update_bits(backend->engine.regs, 463 SUN4I_BACKEND_MODCTL_REG, 464 SUN4I_BACKEND_MODCTL_OUT_SEL, 465 (backend->engine.id 466 ? SUN4I_BACKEND_MODCTL_OUT_LCD1 467 : SUN4I_BACKEND_MODCTL_OUT_LCD0)); 468 } 469 470 return 0; 471 472 err_disable_ram_clk: 473 clk_disable_unprepare(backend->ram_clk); 474 err_disable_mod_clk: 475 clk_disable_unprepare(backend->mod_clk); 476 err_disable_bus_clk: 477 clk_disable_unprepare(backend->bus_clk); 478 err_assert_reset: 479 reset_control_assert(backend->reset); 480 return ret; 481 } 482 483 static void sun4i_backend_unbind(struct device *dev, struct device *master, 484 void *data) 485 { 486 struct sun4i_backend *backend = dev_get_drvdata(dev); 487 488 list_del(&backend->engine.list); 489 490 if (of_device_is_compatible(dev->of_node, 491 "allwinner,sun8i-a33-display-backend")) 492 sun4i_backend_free_sat(dev); 493 494 clk_disable_unprepare(backend->ram_clk); 495 clk_disable_unprepare(backend->mod_clk); 496 clk_disable_unprepare(backend->bus_clk); 497 reset_control_assert(backend->reset); 498 } 499 500 static const struct component_ops sun4i_backend_ops = { 501 .bind = sun4i_backend_bind, 502 .unbind = sun4i_backend_unbind, 503 }; 504 505 static int sun4i_backend_probe(struct platform_device *pdev) 506 { 507 return component_add(&pdev->dev, &sun4i_backend_ops); 508 } 509 510 static int sun4i_backend_remove(struct platform_device *pdev) 511 { 512 component_del(&pdev->dev, &sun4i_backend_ops); 513 514 return 0; 515 } 516 517 static const struct sun4i_backend_quirks sun4i_backend_quirks = { 518 .needs_output_muxing = true, 519 }; 520 521 static const struct sun4i_backend_quirks sun5i_backend_quirks = { 522 }; 523 524 static const struct sun4i_backend_quirks sun6i_backend_quirks = { 525 }; 526 527 static const struct sun4i_backend_quirks sun7i_backend_quirks = { 528 .needs_output_muxing = true, 529 }; 530 531 static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = { 532 }; 533 534 static const struct of_device_id sun4i_backend_of_table[] = { 535 { 536 .compatible = "allwinner,sun4i-a10-display-backend", 537 .data = &sun4i_backend_quirks, 538 }, 539 { 540 .compatible = "allwinner,sun5i-a13-display-backend", 541 .data = &sun5i_backend_quirks, 542 }, 543 { 544 .compatible = "allwinner,sun6i-a31-display-backend", 545 .data = &sun6i_backend_quirks, 546 }, 547 { 548 .compatible = "allwinner,sun7i-a20-display-backend", 549 .data = &sun7i_backend_quirks, 550 }, 551 { 552 .compatible = "allwinner,sun8i-a33-display-backend", 553 .data = &sun8i_a33_backend_quirks, 554 }, 555 { } 556 }; 557 MODULE_DEVICE_TABLE(of, sun4i_backend_of_table); 558 559 static struct platform_driver sun4i_backend_platform_driver = { 560 .probe = sun4i_backend_probe, 561 .remove = sun4i_backend_remove, 562 .driver = { 563 .name = "sun4i-backend", 564 .of_match_table = sun4i_backend_of_table, 565 }, 566 }; 567 module_platform_driver(sun4i_backend_platform_driver); 568 569 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 570 MODULE_DESCRIPTION("Allwinner A10 Display Backend Driver"); 571 MODULE_LICENSE("GPL"); 572