Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.14 643 lines 15 kB view raw
1/* 2 * rcar_du_kms.c -- R-Car Display Unit Mode Setting 3 * 4 * Copyright (C) 2013-2015 Renesas Electronics Corporation 5 * 6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 */ 13 14#include <drm/drmP.h> 15#include <drm/drm_atomic.h> 16#include <drm/drm_atomic_helper.h> 17#include <drm/drm_crtc.h> 18#include <drm/drm_crtc_helper.h> 19#include <drm/drm_fb_cma_helper.h> 20#include <drm/drm_gem_cma_helper.h> 21 22#include <linux/of_graph.h> 23#include <linux/wait.h> 24 25#include "rcar_du_crtc.h" 26#include "rcar_du_drv.h" 27#include "rcar_du_encoder.h" 28#include "rcar_du_kms.h" 29#include "rcar_du_lvdsenc.h" 30#include "rcar_du_regs.h" 31#include "rcar_du_vsp.h" 32 33/* ----------------------------------------------------------------------------- 34 * Format helpers 35 */ 36 37static const struct rcar_du_format_info rcar_du_format_infos[] = { 38 { 39 .fourcc = DRM_FORMAT_RGB565, 40 .bpp = 16, 41 .planes = 1, 42 .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP, 43 .edf = PnDDCR4_EDF_NONE, 44 }, { 45 .fourcc = DRM_FORMAT_ARGB1555, 46 .bpp = 16, 47 .planes = 1, 48 .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB, 49 .edf = PnDDCR4_EDF_NONE, 50 }, { 51 .fourcc = DRM_FORMAT_XRGB1555, 52 .bpp = 16, 53 .planes = 1, 54 .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB, 55 .edf = PnDDCR4_EDF_NONE, 56 }, { 57 .fourcc = DRM_FORMAT_XRGB8888, 58 .bpp = 32, 59 .planes = 1, 60 .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP, 61 .edf = PnDDCR4_EDF_RGB888, 62 }, { 63 .fourcc = DRM_FORMAT_ARGB8888, 64 .bpp = 32, 65 .planes = 1, 66 .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP, 67 .edf = PnDDCR4_EDF_ARGB8888, 68 }, { 69 .fourcc = DRM_FORMAT_UYVY, 70 .bpp = 16, 71 .planes = 1, 72 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 73 .edf = PnDDCR4_EDF_NONE, 74 }, { 75 .fourcc = DRM_FORMAT_YUYV, 76 .bpp = 16, 77 .planes = 1, 78 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 79 .edf = PnDDCR4_EDF_NONE, 80 }, { 81 .fourcc = DRM_FORMAT_NV12, 82 .bpp = 12, 83 .planes = 2, 84 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 85 .edf = PnDDCR4_EDF_NONE, 86 }, { 87 .fourcc = DRM_FORMAT_NV21, 88 .bpp = 12, 89 .planes = 2, 90 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 91 .edf = PnDDCR4_EDF_NONE, 92 }, { 93 .fourcc = DRM_FORMAT_NV16, 94 .bpp = 16, 95 .planes = 2, 96 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, 97 .edf = PnDDCR4_EDF_NONE, 98 }, 99 /* 100 * The following formats are not supported on Gen2 and thus have no 101 * associated .pnmr or .edf settings. 102 */ 103 { 104 .fourcc = DRM_FORMAT_NV61, 105 .bpp = 16, 106 .planes = 2, 107 }, { 108 .fourcc = DRM_FORMAT_YUV420, 109 .bpp = 12, 110 .planes = 3, 111 }, { 112 .fourcc = DRM_FORMAT_YVU420, 113 .bpp = 12, 114 .planes = 3, 115 }, { 116 .fourcc = DRM_FORMAT_YUV422, 117 .bpp = 16, 118 .planes = 3, 119 }, { 120 .fourcc = DRM_FORMAT_YVU422, 121 .bpp = 16, 122 .planes = 3, 123 }, { 124 .fourcc = DRM_FORMAT_YUV444, 125 .bpp = 24, 126 .planes = 3, 127 }, { 128 .fourcc = DRM_FORMAT_YVU444, 129 .bpp = 24, 130 .planes = 3, 131 }, 132}; 133 134const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc) 135{ 136 unsigned int i; 137 138 for (i = 0; i < ARRAY_SIZE(rcar_du_format_infos); ++i) { 139 if (rcar_du_format_infos[i].fourcc == fourcc) 140 return &rcar_du_format_infos[i]; 141 } 142 143 return NULL; 144} 145 146/* ----------------------------------------------------------------------------- 147 * Frame buffer 148 */ 149 150int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, 151 struct drm_mode_create_dumb *args) 152{ 153 struct rcar_du_device *rcdu = dev->dev_private; 154 unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); 155 unsigned int align; 156 157 /* 158 * The R8A7779 DU requires a 16 pixels pitch alignment as documented, 159 * but the R8A7790 DU seems to require a 128 bytes pitch alignment. 160 */ 161 if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) 162 align = 128; 163 else 164 align = 16 * args->bpp / 8; 165 166 args->pitch = roundup(min_pitch, align); 167 168 return drm_gem_cma_dumb_create_internal(file, dev, args); 169} 170 171static struct drm_framebuffer * 172rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, 173 const struct drm_mode_fb_cmd2 *mode_cmd) 174{ 175 struct rcar_du_device *rcdu = dev->dev_private; 176 const struct rcar_du_format_info *format; 177 unsigned int max_pitch; 178 unsigned int align; 179 unsigned int bpp; 180 unsigned int i; 181 182 format = rcar_du_format_info(mode_cmd->pixel_format); 183 if (format == NULL) { 184 dev_dbg(dev->dev, "unsupported pixel format %08x\n", 185 mode_cmd->pixel_format); 186 return ERR_PTR(-EINVAL); 187 } 188 189 /* 190 * The pitch and alignment constraints are expressed in pixels on the 191 * hardware side and in bytes in the DRM API. 192 */ 193 bpp = format->planes == 1 ? format->bpp / 8 : 1; 194 max_pitch = 4096 * bpp; 195 196 if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) 197 align = 128; 198 else 199 align = 16 * bpp; 200 201 if (mode_cmd->pitches[0] & (align - 1) || 202 mode_cmd->pitches[0] >= max_pitch) { 203 dev_dbg(dev->dev, "invalid pitch value %u\n", 204 mode_cmd->pitches[0]); 205 return ERR_PTR(-EINVAL); 206 } 207 208 for (i = 1; i < format->planes; ++i) { 209 if (mode_cmd->pitches[i] != mode_cmd->pitches[0]) { 210 dev_dbg(dev->dev, 211 "luma and chroma pitches do not match\n"); 212 return ERR_PTR(-EINVAL); 213 } 214 } 215 216 return drm_fb_cma_create(dev, file_priv, mode_cmd); 217} 218 219static void rcar_du_output_poll_changed(struct drm_device *dev) 220{ 221 struct rcar_du_device *rcdu = dev->dev_private; 222 223 drm_fbdev_cma_hotplug_event(rcdu->fbdev); 224} 225 226/* ----------------------------------------------------------------------------- 227 * Atomic Check and Update 228 */ 229 230static int rcar_du_atomic_check(struct drm_device *dev, 231 struct drm_atomic_state *state) 232{ 233 struct rcar_du_device *rcdu = dev->dev_private; 234 int ret; 235 236 ret = drm_atomic_helper_check_modeset(dev, state); 237 if (ret) 238 return ret; 239 240 ret = drm_atomic_normalize_zpos(dev, state); 241 if (ret) 242 return ret; 243 244 ret = drm_atomic_helper_check_planes(dev, state); 245 if (ret) 246 return ret; 247 248 if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) 249 return 0; 250 251 return rcar_du_atomic_check_planes(dev, state); 252} 253 254static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) 255{ 256 struct drm_device *dev = old_state->dev; 257 258 /* Apply the atomic update. */ 259 drm_atomic_helper_commit_modeset_disables(dev, old_state); 260 drm_atomic_helper_commit_planes(dev, old_state, 261 DRM_PLANE_COMMIT_ACTIVE_ONLY); 262 drm_atomic_helper_commit_modeset_enables(dev, old_state); 263 264 drm_atomic_helper_commit_hw_done(old_state); 265 drm_atomic_helper_wait_for_flip_done(dev, old_state); 266 267 drm_atomic_helper_cleanup_planes(dev, old_state); 268} 269 270/* ----------------------------------------------------------------------------- 271 * Initialization 272 */ 273 274static const struct drm_mode_config_helper_funcs rcar_du_mode_config_helper = { 275 .atomic_commit_tail = rcar_du_atomic_commit_tail, 276}; 277 278static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { 279 .fb_create = rcar_du_fb_create, 280 .output_poll_changed = rcar_du_output_poll_changed, 281 .atomic_check = rcar_du_atomic_check, 282 .atomic_commit = drm_atomic_helper_commit, 283}; 284 285static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, 286 enum rcar_du_output output, 287 struct of_endpoint *ep) 288{ 289 struct device_node *connector = NULL; 290 struct device_node *encoder = NULL; 291 struct device_node *ep_node = NULL; 292 struct device_node *entity_ep_node; 293 struct device_node *entity; 294 int ret; 295 296 /* 297 * Locate the connected entity and infer its type from the number of 298 * endpoints. 299 */ 300 entity = of_graph_get_remote_port_parent(ep->local_node); 301 if (!entity) { 302 dev_dbg(rcdu->dev, "unconnected endpoint %pOF, skipping\n", 303 ep->local_node); 304 return -ENODEV; 305 } 306 307 if (!of_device_is_available(entity)) { 308 dev_dbg(rcdu->dev, 309 "connected entity %pOF is disabled, skipping\n", 310 entity); 311 return -ENODEV; 312 } 313 314 entity_ep_node = of_graph_get_remote_endpoint(ep->local_node); 315 316 for_each_endpoint_of_node(entity, ep_node) { 317 if (ep_node == entity_ep_node) 318 continue; 319 320 /* 321 * We've found one endpoint other than the input, this must 322 * be an encoder. Locate the connector. 323 */ 324 encoder = entity; 325 connector = of_graph_get_remote_port_parent(ep_node); 326 of_node_put(ep_node); 327 328 if (!connector) { 329 dev_warn(rcdu->dev, 330 "no connector for encoder %pOF, skipping\n", 331 encoder); 332 of_node_put(entity_ep_node); 333 of_node_put(encoder); 334 return -ENODEV; 335 } 336 337 break; 338 } 339 340 of_node_put(entity_ep_node); 341 342 if (!encoder) { 343 /* 344 * If no encoder has been found the entity must be the 345 * connector. 346 */ 347 connector = entity; 348 } 349 350 ret = rcar_du_encoder_init(rcdu, output, encoder, connector); 351 if (ret && ret != -EPROBE_DEFER) 352 dev_warn(rcdu->dev, 353 "failed to initialize encoder %pOF on output %u (%d), skipping\n", 354 encoder, output, ret); 355 356 of_node_put(encoder); 357 of_node_put(connector); 358 359 return ret; 360} 361 362static int rcar_du_encoders_init(struct rcar_du_device *rcdu) 363{ 364 struct device_node *np = rcdu->dev->of_node; 365 struct device_node *ep_node; 366 unsigned int num_encoders = 0; 367 368 /* 369 * Iterate over the endpoints and create one encoder for each output 370 * pipeline. 371 */ 372 for_each_endpoint_of_node(np, ep_node) { 373 enum rcar_du_output output; 374 struct of_endpoint ep; 375 unsigned int i; 376 int ret; 377 378 ret = of_graph_parse_endpoint(ep_node, &ep); 379 if (ret < 0) { 380 of_node_put(ep_node); 381 return ret; 382 } 383 384 /* Find the output route corresponding to the port number. */ 385 for (i = 0; i < RCAR_DU_OUTPUT_MAX; ++i) { 386 if (rcdu->info->routes[i].possible_crtcs && 387 rcdu->info->routes[i].port == ep.port) { 388 output = i; 389 break; 390 } 391 } 392 393 if (i == RCAR_DU_OUTPUT_MAX) { 394 dev_warn(rcdu->dev, 395 "port %u references unexisting output, skipping\n", 396 ep.port); 397 continue; 398 } 399 400 /* Process the output pipeline. */ 401 ret = rcar_du_encoders_init_one(rcdu, output, &ep); 402 if (ret < 0) { 403 if (ret == -EPROBE_DEFER) { 404 of_node_put(ep_node); 405 return ret; 406 } 407 408 continue; 409 } 410 411 num_encoders++; 412 } 413 414 return num_encoders; 415} 416 417static int rcar_du_properties_init(struct rcar_du_device *rcdu) 418{ 419 rcdu->props.alpha = 420 drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255); 421 if (rcdu->props.alpha == NULL) 422 return -ENOMEM; 423 424 /* 425 * The color key is expressed as an RGB888 triplet stored in a 32-bit 426 * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0) 427 * or enable source color keying (1). 428 */ 429 rcdu->props.colorkey = 430 drm_property_create_range(rcdu->ddev, 0, "colorkey", 431 0, 0x01ffffff); 432 if (rcdu->props.colorkey == NULL) 433 return -ENOMEM; 434 435 return 0; 436} 437 438static int rcar_du_vsps_init(struct rcar_du_device *rcdu) 439{ 440 const struct device_node *np = rcdu->dev->of_node; 441 struct of_phandle_args args; 442 struct { 443 struct device_node *np; 444 unsigned int crtcs_mask; 445 } vsps[RCAR_DU_MAX_VSPS] = { { 0, }, }; 446 unsigned int vsps_count = 0; 447 unsigned int cells; 448 unsigned int i; 449 int ret; 450 451 /* 452 * First parse the DT vsps property to populate the list of VSPs. Each 453 * entry contains a pointer to the VSP DT node and a bitmask of the 454 * connected DU CRTCs. 455 */ 456 cells = of_property_count_u32_elems(np, "vsps") / rcdu->num_crtcs - 1; 457 if (cells > 1) 458 return -EINVAL; 459 460 for (i = 0; i < rcdu->num_crtcs; ++i) { 461 unsigned int j; 462 463 ret = of_parse_phandle_with_fixed_args(np, "vsps", cells, i, 464 &args); 465 if (ret < 0) 466 goto error; 467 468 /* 469 * Add the VSP to the list or update the corresponding existing 470 * entry if the VSP has already been added. 471 */ 472 for (j = 0; j < vsps_count; ++j) { 473 if (vsps[j].np == args.np) 474 break; 475 } 476 477 if (j < vsps_count) 478 of_node_put(args.np); 479 else 480 vsps[vsps_count++].np = args.np; 481 482 vsps[j].crtcs_mask |= BIT(i); 483 484 /* Store the VSP pointer and pipe index in the CRTC. */ 485 rcdu->crtcs[i].vsp = &rcdu->vsps[j]; 486 rcdu->crtcs[i].vsp_pipe = cells >= 1 ? args.args[0] : 0; 487 } 488 489 /* 490 * Then initialize all the VSPs from the node pointers and CRTCs bitmask 491 * computed previously. 492 */ 493 for (i = 0; i < vsps_count; ++i) { 494 struct rcar_du_vsp *vsp = &rcdu->vsps[i]; 495 496 vsp->index = i; 497 vsp->dev = rcdu; 498 499 ret = rcar_du_vsp_init(vsp, vsps[i].np, vsps[i].crtcs_mask); 500 if (ret < 0) 501 goto error; 502 } 503 504 return 0; 505 506error: 507 for (i = 0; i < ARRAY_SIZE(vsps); ++i) 508 of_node_put(vsps[i].np); 509 510 return ret; 511} 512 513int rcar_du_modeset_init(struct rcar_du_device *rcdu) 514{ 515 static const unsigned int mmio_offsets[] = { 516 DU0_REG_OFFSET, DU2_REG_OFFSET 517 }; 518 519 struct drm_device *dev = rcdu->ddev; 520 struct drm_encoder *encoder; 521 struct drm_fbdev_cma *fbdev; 522 unsigned int num_encoders; 523 unsigned int num_groups; 524 unsigned int i; 525 int ret; 526 527 drm_mode_config_init(dev); 528 529 dev->mode_config.min_width = 0; 530 dev->mode_config.min_height = 0; 531 dev->mode_config.max_width = 4095; 532 dev->mode_config.max_height = 2047; 533 dev->mode_config.funcs = &rcar_du_mode_config_funcs; 534 dev->mode_config.helper_private = &rcar_du_mode_config_helper; 535 536 rcdu->num_crtcs = rcdu->info->num_crtcs; 537 538 ret = rcar_du_properties_init(rcdu); 539 if (ret < 0) 540 return ret; 541 542 /* 543 * Initialize vertical blanking interrupts handling. Start with vblank 544 * disabled for all CRTCs. 545 */ 546 ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1); 547 if (ret < 0) 548 return ret; 549 550 /* Initialize the groups. */ 551 num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2); 552 553 for (i = 0; i < num_groups; ++i) { 554 struct rcar_du_group *rgrp = &rcdu->groups[i]; 555 556 mutex_init(&rgrp->lock); 557 558 rgrp->dev = rcdu; 559 rgrp->mmio_offset = mmio_offsets[i]; 560 rgrp->index = i; 561 rgrp->num_crtcs = min(rcdu->num_crtcs - 2 * i, 2U); 562 563 /* 564 * If we have more than one CRTCs in this group pre-associate 565 * the low-order planes with CRTC 0 and the high-order planes 566 * with CRTC 1 to minimize flicker occurring when the 567 * association is changed. 568 */ 569 rgrp->dptsr_planes = rgrp->num_crtcs > 1 570 ? (rcdu->info->gen >= 3 ? 0x04 : 0xf0) 571 : 0; 572 573 if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { 574 ret = rcar_du_planes_init(rgrp); 575 if (ret < 0) 576 return ret; 577 } 578 } 579 580 /* Initialize the compositors. */ 581 if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { 582 ret = rcar_du_vsps_init(rcdu); 583 if (ret < 0) 584 return ret; 585 } 586 587 /* Create the CRTCs. */ 588 for (i = 0; i < rcdu->num_crtcs; ++i) { 589 struct rcar_du_group *rgrp = &rcdu->groups[i / 2]; 590 591 ret = rcar_du_crtc_create(rgrp, i); 592 if (ret < 0) 593 return ret; 594 } 595 596 /* Initialize the encoders. */ 597 ret = rcar_du_lvdsenc_init(rcdu); 598 if (ret < 0) 599 return ret; 600 601 ret = rcar_du_encoders_init(rcdu); 602 if (ret < 0) 603 return ret; 604 605 if (ret == 0) { 606 dev_err(rcdu->dev, "error: no encoder could be initialized\n"); 607 return -EINVAL; 608 } 609 610 num_encoders = ret; 611 612 /* 613 * Set the possible CRTCs and possible clones. There's always at least 614 * one way for all encoders to clone each other, set all bits in the 615 * possible clones field. 616 */ 617 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 618 struct rcar_du_encoder *renc = to_rcar_encoder(encoder); 619 const struct rcar_du_output_routing *route = 620 &rcdu->info->routes[renc->output]; 621 622 encoder->possible_crtcs = route->possible_crtcs; 623 encoder->possible_clones = (1 << num_encoders) - 1; 624 } 625 626 drm_mode_config_reset(dev); 627 628 drm_kms_helper_poll_init(dev); 629 630 if (dev->mode_config.num_connector) { 631 fbdev = drm_fbdev_cma_init(dev, 32, 632 dev->mode_config.num_connector); 633 if (IS_ERR(fbdev)) 634 return PTR_ERR(fbdev); 635 636 rcdu->fbdev = fbdev; 637 } else { 638 dev_info(rcdu->dev, 639 "no connector found, disabling fbdev emulation\n"); 640 } 641 642 return 0; 643}