| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2015 Free Electrons |
|---|
| 3 | 4 | * Copyright (C) 2015 NextThing Co |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * 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 | 7 | */ |
|---|
| 12 | | - |
|---|
| 13 | | -#include <drm/drmP.h> |
|---|
| 14 | | -#include <drm/drm_atomic.h> |
|---|
| 15 | | -#include <drm/drm_atomic_helper.h> |
|---|
| 16 | | -#include <drm/drm_crtc.h> |
|---|
| 17 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 18 | | -#include <drm/drm_fb_cma_helper.h> |
|---|
| 19 | | -#include <drm/drm_gem_cma_helper.h> |
|---|
| 20 | | -#include <drm/drm_plane_helper.h> |
|---|
| 21 | 8 | |
|---|
| 22 | 9 | #include <linux/component.h> |
|---|
| 23 | 10 | #include <linux/list.h> |
|---|
| 11 | +#include <linux/module.h> |
|---|
| 24 | 12 | #include <linux/of_device.h> |
|---|
| 25 | 13 | #include <linux/of_graph.h> |
|---|
| 14 | +#include <linux/dma-mapping.h> |
|---|
| 15 | +#include <linux/platform_device.h> |
|---|
| 26 | 16 | #include <linux/reset.h> |
|---|
| 17 | + |
|---|
| 18 | +#include <drm/drm_atomic.h> |
|---|
| 19 | +#include <drm/drm_atomic_helper.h> |
|---|
| 20 | +#include <drm/drm_crtc.h> |
|---|
| 21 | +#include <drm/drm_fb_cma_helper.h> |
|---|
| 22 | +#include <drm/drm_fourcc.h> |
|---|
| 23 | +#include <drm/drm_gem_cma_helper.h> |
|---|
| 24 | +#include <drm/drm_plane_helper.h> |
|---|
| 25 | +#include <drm/drm_probe_helper.h> |
|---|
| 27 | 26 | |
|---|
| 28 | 27 | #include "sun4i_backend.h" |
|---|
| 29 | 28 | #include "sun4i_drv.h" |
|---|
| .. | .. |
|---|
| 34 | 33 | struct sun4i_backend_quirks { |
|---|
| 35 | 34 | /* backend <-> TCON muxing selection done in backend */ |
|---|
| 36 | 35 | bool needs_output_muxing; |
|---|
| 36 | + |
|---|
| 37 | + /* alpha at the lowest z position is not always supported */ |
|---|
| 38 | + bool supports_lowest_plane_alpha; |
|---|
| 37 | 39 | }; |
|---|
| 38 | 40 | |
|---|
| 39 | 41 | static const u32 sunxi_rgb2yuv_coef[12] = { |
|---|
| .. | .. |
|---|
| 41 | 43 | 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808, |
|---|
| 42 | 44 | 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 |
|---|
| 43 | 45 | }; |
|---|
| 44 | | - |
|---|
| 45 | | -/* |
|---|
| 46 | | - * These coefficients are taken from the A33 BSP from Allwinner. |
|---|
| 47 | | - * |
|---|
| 48 | | - * The formula is for each component, each coefficient being multiplied by |
|---|
| 49 | | - * 1024 and each constant being multiplied by 16: |
|---|
| 50 | | - * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 |
|---|
| 51 | | - * R = 1.164 * Y + 1.596 * V - 222 |
|---|
| 52 | | - * B = 1.164 * Y + 2.018 * U + 276 |
|---|
| 53 | | - * |
|---|
| 54 | | - * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255], |
|---|
| 55 | | - * following the BT601 spec. |
|---|
| 56 | | - */ |
|---|
| 57 | | -static const u32 sunxi_bt601_yuv2rgb_coef[12] = { |
|---|
| 58 | | - 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877, |
|---|
| 59 | | - 0x000004a7, 0x00000000, 0x00000662, 0x00003211, |
|---|
| 60 | | - 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, |
|---|
| 61 | | -}; |
|---|
| 62 | | - |
|---|
| 63 | | -static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format) |
|---|
| 64 | | -{ |
|---|
| 65 | | - switch (format) { |
|---|
| 66 | | - case DRM_FORMAT_YUV411: |
|---|
| 67 | | - case DRM_FORMAT_YUV422: |
|---|
| 68 | | - case DRM_FORMAT_YUV444: |
|---|
| 69 | | - return true; |
|---|
| 70 | | - default: |
|---|
| 71 | | - return false; |
|---|
| 72 | | - } |
|---|
| 73 | | -} |
|---|
| 74 | | - |
|---|
| 75 | | -static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format) |
|---|
| 76 | | -{ |
|---|
| 77 | | - switch (format) { |
|---|
| 78 | | - case DRM_FORMAT_YUYV: |
|---|
| 79 | | - case DRM_FORMAT_YVYU: |
|---|
| 80 | | - case DRM_FORMAT_UYVY: |
|---|
| 81 | | - case DRM_FORMAT_VYUY: |
|---|
| 82 | | - return true; |
|---|
| 83 | | - |
|---|
| 84 | | - default: |
|---|
| 85 | | - return false; |
|---|
| 86 | | - } |
|---|
| 87 | | -} |
|---|
| 88 | 46 | |
|---|
| 89 | 47 | static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) |
|---|
| 90 | 48 | { |
|---|
| .. | .. |
|---|
| 178 | 136 | return 0; |
|---|
| 179 | 137 | } |
|---|
| 180 | 138 | |
|---|
| 139 | +static const uint32_t sun4i_backend_formats[] = { |
|---|
| 140 | + DRM_FORMAT_ARGB1555, |
|---|
| 141 | + DRM_FORMAT_ARGB4444, |
|---|
| 142 | + DRM_FORMAT_ARGB8888, |
|---|
| 143 | + DRM_FORMAT_RGB565, |
|---|
| 144 | + DRM_FORMAT_RGB888, |
|---|
| 145 | + DRM_FORMAT_RGBA4444, |
|---|
| 146 | + DRM_FORMAT_RGBA5551, |
|---|
| 147 | + DRM_FORMAT_UYVY, |
|---|
| 148 | + DRM_FORMAT_VYUY, |
|---|
| 149 | + DRM_FORMAT_XRGB8888, |
|---|
| 150 | + DRM_FORMAT_YUYV, |
|---|
| 151 | + DRM_FORMAT_YVYU, |
|---|
| 152 | +}; |
|---|
| 153 | + |
|---|
| 154 | +bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier) |
|---|
| 155 | +{ |
|---|
| 156 | + unsigned int i; |
|---|
| 157 | + |
|---|
| 158 | + if (modifier != DRM_FORMAT_MOD_LINEAR) |
|---|
| 159 | + return false; |
|---|
| 160 | + |
|---|
| 161 | + for (i = 0; i < ARRAY_SIZE(sun4i_backend_formats); i++) |
|---|
| 162 | + if (sun4i_backend_formats[i] == fmt) |
|---|
| 163 | + return true; |
|---|
| 164 | + |
|---|
| 165 | + return false; |
|---|
| 166 | +} |
|---|
| 167 | + |
|---|
| 181 | 168 | int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, |
|---|
| 182 | 169 | int layer, struct drm_plane *plane) |
|---|
| 183 | 170 | { |
|---|
| .. | .. |
|---|
| 215 | 202 | { |
|---|
| 216 | 203 | struct drm_plane_state *state = plane->state; |
|---|
| 217 | 204 | struct drm_framebuffer *fb = state->fb; |
|---|
| 218 | | - uint32_t format = fb->format->format; |
|---|
| 205 | + const struct drm_format_info *format = fb->format; |
|---|
| 206 | + const uint32_t fmt = format->format; |
|---|
| 219 | 207 | u32 val = SUN4I_BACKEND_IYUVCTL_EN; |
|---|
| 220 | 208 | int i; |
|---|
| 221 | 209 | |
|---|
| .. | .. |
|---|
| 233 | 221 | SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN); |
|---|
| 234 | 222 | |
|---|
| 235 | 223 | /* TODO: Add support for the multi-planar YUV formats */ |
|---|
| 236 | | - if (sun4i_backend_format_is_packed_yuv422(format)) |
|---|
| 224 | + if (drm_format_info_is_yuv_packed(format) && |
|---|
| 225 | + drm_format_info_is_yuv_sampling_422(format)) |
|---|
| 237 | 226 | val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422; |
|---|
| 238 | 227 | else |
|---|
| 239 | | - DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", format); |
|---|
| 228 | + DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", fmt); |
|---|
| 240 | 229 | |
|---|
| 241 | 230 | /* |
|---|
| 242 | 231 | * Allwinner seems to list the pixel sequence from right to left, while |
|---|
| 243 | 232 | * DRM lists it from left to right. |
|---|
| 244 | 233 | */ |
|---|
| 245 | | - switch (format) { |
|---|
| 234 | + switch (fmt) { |
|---|
| 246 | 235 | case DRM_FORMAT_YUYV: |
|---|
| 247 | 236 | val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY; |
|---|
| 248 | 237 | break; |
|---|
| .. | .. |
|---|
| 257 | 246 | break; |
|---|
| 258 | 247 | default: |
|---|
| 259 | 248 | DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n", |
|---|
| 260 | | - format); |
|---|
| 249 | + fmt); |
|---|
| 261 | 250 | } |
|---|
| 262 | 251 | |
|---|
| 263 | 252 | regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val); |
|---|
| .. | .. |
|---|
| 371 | 360 | paddr = drm_fb_cma_get_gem_addr(fb, state, 0); |
|---|
| 372 | 361 | DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); |
|---|
| 373 | 362 | |
|---|
| 374 | | - /* |
|---|
| 375 | | - * backend DMA accesses DRAM directly, bypassing the system |
|---|
| 376 | | - * bus. As such, the address range is different and the buffer |
|---|
| 377 | | - * address needs to be corrected. |
|---|
| 378 | | - */ |
|---|
| 379 | | - paddr -= PHYS_OFFSET; |
|---|
| 380 | | - |
|---|
| 381 | 363 | if (fb->format->is_yuv) |
|---|
| 382 | 364 | return sun4i_backend_update_yuv_buffer(backend, fb, paddr); |
|---|
| 383 | 365 | |
|---|
| .. | .. |
|---|
| 417 | 399 | return 0; |
|---|
| 418 | 400 | } |
|---|
| 419 | 401 | |
|---|
| 402 | +void sun4i_backend_cleanup_layer(struct sun4i_backend *backend, |
|---|
| 403 | + int layer) |
|---|
| 404 | +{ |
|---|
| 405 | + regmap_update_bits(backend->engine.regs, |
|---|
| 406 | + SUN4I_BACKEND_ATTCTL_REG0(layer), |
|---|
| 407 | + SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN | |
|---|
| 408 | + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0); |
|---|
| 409 | +} |
|---|
| 410 | + |
|---|
| 420 | 411 | static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state) |
|---|
| 421 | 412 | { |
|---|
| 422 | 413 | u16 src_h = state->src_h >> 16; |
|---|
| .. | .. |
|---|
| 435 | 426 | { |
|---|
| 436 | 427 | struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane); |
|---|
| 437 | 428 | struct sun4i_backend *backend = layer->backend; |
|---|
| 429 | + uint32_t format = state->fb->format->format; |
|---|
| 430 | + uint64_t modifier = state->fb->modifier; |
|---|
| 438 | 431 | |
|---|
| 439 | 432 | if (IS_ERR(backend->frontend)) |
|---|
| 440 | 433 | return false; |
|---|
| 441 | 434 | |
|---|
| 442 | | - return sun4i_backend_plane_uses_scaler(state); |
|---|
| 435 | + if (!sun4i_frontend_format_is_supported(format, modifier)) |
|---|
| 436 | + return false; |
|---|
| 437 | + |
|---|
| 438 | + if (!sun4i_backend_format_is_supported(format, modifier)) |
|---|
| 439 | + return true; |
|---|
| 440 | + |
|---|
| 441 | + /* |
|---|
| 442 | + * TODO: The backend alone allows 2x and 4x integer scaling, including |
|---|
| 443 | + * support for an alpha component (which the frontend doesn't support). |
|---|
| 444 | + * Use the backend directly instead of the frontend in this case, with |
|---|
| 445 | + * another test to return false. |
|---|
| 446 | + */ |
|---|
| 447 | + |
|---|
| 448 | + if (sun4i_backend_plane_uses_scaler(state)) |
|---|
| 449 | + return true; |
|---|
| 450 | + |
|---|
| 451 | + /* |
|---|
| 452 | + * Here the format is supported by both the frontend and the backend |
|---|
| 453 | + * and no frontend scaling is required, so use the backend directly. |
|---|
| 454 | + */ |
|---|
| 455 | + return false; |
|---|
| 456 | +} |
|---|
| 457 | + |
|---|
| 458 | +static bool sun4i_backend_plane_is_supported(struct drm_plane_state *state, |
|---|
| 459 | + bool *uses_frontend) |
|---|
| 460 | +{ |
|---|
| 461 | + if (sun4i_backend_plane_uses_frontend(state)) { |
|---|
| 462 | + *uses_frontend = true; |
|---|
| 463 | + return true; |
|---|
| 464 | + } |
|---|
| 465 | + |
|---|
| 466 | + *uses_frontend = false; |
|---|
| 467 | + |
|---|
| 468 | + /* Scaling is not supported without the frontend. */ |
|---|
| 469 | + if (sun4i_backend_plane_uses_scaler(state)) |
|---|
| 470 | + return false; |
|---|
| 471 | + |
|---|
| 472 | + return true; |
|---|
| 443 | 473 | } |
|---|
| 444 | 474 | |
|---|
| 445 | 475 | static void sun4i_backend_atomic_begin(struct sunxi_engine *engine, |
|---|
| .. | .. |
|---|
| 457 | 487 | struct drm_crtc_state *crtc_state) |
|---|
| 458 | 488 | { |
|---|
| 459 | 489 | struct drm_plane_state *plane_states[SUN4I_BACKEND_NUM_LAYERS] = { 0 }; |
|---|
| 490 | + struct sun4i_backend *backend = engine_to_sun4i_backend(engine); |
|---|
| 460 | 491 | struct drm_atomic_state *state = crtc_state->state; |
|---|
| 461 | 492 | struct drm_device *drm = state->dev; |
|---|
| 462 | 493 | struct drm_plane *plane; |
|---|
| 463 | 494 | unsigned int num_planes = 0; |
|---|
| 464 | 495 | unsigned int num_alpha_planes = 0; |
|---|
| 465 | 496 | unsigned int num_frontend_planes = 0; |
|---|
| 497 | + unsigned int num_alpha_planes_max = 1; |
|---|
| 466 | 498 | unsigned int num_yuv_planes = 0; |
|---|
| 467 | 499 | unsigned int current_pipe = 0; |
|---|
| 468 | 500 | unsigned int i; |
|---|
| .. | .. |
|---|
| 480 | 512 | struct drm_framebuffer *fb = plane_state->fb; |
|---|
| 481 | 513 | struct drm_format_name_buf format_name; |
|---|
| 482 | 514 | |
|---|
| 483 | | - if (sun4i_backend_plane_uses_frontend(plane_state)) { |
|---|
| 515 | + if (!sun4i_backend_plane_is_supported(plane_state, |
|---|
| 516 | + &layer_state->uses_frontend)) |
|---|
| 517 | + return -EINVAL; |
|---|
| 518 | + |
|---|
| 519 | + if (layer_state->uses_frontend) { |
|---|
| 484 | 520 | DRM_DEBUG_DRIVER("Using the frontend for plane %d\n", |
|---|
| 485 | 521 | plane->index); |
|---|
| 486 | | - |
|---|
| 487 | | - layer_state->uses_frontend = true; |
|---|
| 488 | 522 | num_frontend_planes++; |
|---|
| 489 | 523 | } else { |
|---|
| 490 | | - layer_state->uses_frontend = false; |
|---|
| 524 | + if (fb->format->is_yuv) { |
|---|
| 525 | + DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); |
|---|
| 526 | + num_yuv_planes++; |
|---|
| 527 | + } |
|---|
| 491 | 528 | } |
|---|
| 492 | 529 | |
|---|
| 493 | 530 | DRM_DEBUG_DRIVER("Plane FB format is %s\n", |
|---|
| .. | .. |
|---|
| 495 | 532 | &format_name)); |
|---|
| 496 | 533 | if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE)) |
|---|
| 497 | 534 | num_alpha_planes++; |
|---|
| 498 | | - |
|---|
| 499 | | - if (fb->format->is_yuv) { |
|---|
| 500 | | - DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); |
|---|
| 501 | | - num_yuv_planes++; |
|---|
| 502 | | - } |
|---|
| 503 | 535 | |
|---|
| 504 | 536 | DRM_DEBUG_DRIVER("Plane zpos is %d\n", |
|---|
| 505 | 537 | plane_state->normalized_zpos); |
|---|
| .. | .. |
|---|
| 526 | 558 | * the layer with the highest priority. |
|---|
| 527 | 559 | * |
|---|
| 528 | 560 | * The second step is the actual alpha blending, that takes |
|---|
| 529 | | - * the two pipes as input, and uses the eventual alpha |
|---|
| 561 | + * the two pipes as input, and uses the potential alpha |
|---|
| 530 | 562 | * component to do the transparency between the two. |
|---|
| 531 | 563 | * |
|---|
| 532 | | - * This two steps scenario makes us unable to guarantee a |
|---|
| 564 | + * This two-step scenario makes us unable to guarantee a |
|---|
| 533 | 565 | * robust alpha blending between the 4 layers in all |
|---|
| 534 | 566 | * situations, since this means that we need to have one layer |
|---|
| 535 | 567 | * with alpha at the lowest position of our two pipes. |
|---|
| 536 | 568 | * |
|---|
| 537 | | - * However, we cannot even do that, since the hardware has a |
|---|
| 538 | | - * bug where the lowest plane of the lowest pipe (pipe 0, |
|---|
| 539 | | - * priority 0), if it has any alpha, will discard the pixel |
|---|
| 540 | | - * entirely and just display the pixels in the background |
|---|
| 541 | | - * color (black by default). |
|---|
| 569 | + * However, we cannot even do that on every platform, since |
|---|
| 570 | + * the hardware has a bug where the lowest plane of the lowest |
|---|
| 571 | + * pipe (pipe 0, priority 0), if it has any alpha, will |
|---|
| 572 | + * discard the pixel data entirely and just display the pixels |
|---|
| 573 | + * in the background color (black by default). |
|---|
| 542 | 574 | * |
|---|
| 543 | | - * This means that we effectively have only three valid |
|---|
| 544 | | - * configurations with alpha, all of them with the alpha being |
|---|
| 545 | | - * on pipe1 with the lowest position, which can be 1, 2 or 3 |
|---|
| 546 | | - * depending on the number of planes and their zpos. |
|---|
| 575 | + * This means that on the affected platforms, we effectively |
|---|
| 576 | + * have only three valid configurations with alpha, all of |
|---|
| 577 | + * them with the alpha being on pipe1 with the lowest |
|---|
| 578 | + * position, which can be 1, 2 or 3 depending on the number of |
|---|
| 579 | + * planes and their zpos. |
|---|
| 547 | 580 | */ |
|---|
| 548 | | - if (num_alpha_planes > SUN4I_BACKEND_NUM_ALPHA_LAYERS) { |
|---|
| 581 | + |
|---|
| 582 | + /* For platforms that are not affected by the issue described above. */ |
|---|
| 583 | + if (backend->quirks->supports_lowest_plane_alpha) |
|---|
| 584 | + num_alpha_planes_max++; |
|---|
| 585 | + |
|---|
| 586 | + if (num_alpha_planes > num_alpha_planes_max) { |
|---|
| 549 | 587 | DRM_DEBUG_DRIVER("Too many planes with alpha, rejecting...\n"); |
|---|
| 550 | 588 | return -EINVAL; |
|---|
| 551 | 589 | } |
|---|
| 552 | 590 | |
|---|
| 553 | 591 | /* We can't have an alpha plane at the lowest position */ |
|---|
| 554 | | - if (plane_states[0]->fb->format->has_alpha || |
|---|
| 592 | + if (!backend->quirks->supports_lowest_plane_alpha && |
|---|
| 555 | 593 | (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE)) |
|---|
| 556 | 594 | return -EINVAL; |
|---|
| 557 | 595 | |
|---|
| .. | .. |
|---|
| 673 | 711 | */ |
|---|
| 674 | 712 | static int sun4i_backend_of_get_id(struct device_node *node) |
|---|
| 675 | 713 | { |
|---|
| 676 | | - struct device_node *port, *ep; |
|---|
| 677 | | - int ret = -EINVAL; |
|---|
| 714 | + struct device_node *ep, *remote; |
|---|
| 715 | + struct of_endpoint of_ep; |
|---|
| 678 | 716 | |
|---|
| 679 | | - /* input is port 0 */ |
|---|
| 680 | | - port = of_graph_get_port_by_id(node, 0); |
|---|
| 681 | | - if (!port) |
|---|
| 717 | + /* Input port is 0, and we want the first endpoint. */ |
|---|
| 718 | + ep = of_graph_get_endpoint_by_regs(node, 0, -1); |
|---|
| 719 | + if (!ep) |
|---|
| 682 | 720 | return -EINVAL; |
|---|
| 683 | 721 | |
|---|
| 684 | | - /* try finding an upstream endpoint */ |
|---|
| 685 | | - for_each_available_child_of_node(port, ep) { |
|---|
| 686 | | - struct device_node *remote; |
|---|
| 687 | | - u32 reg; |
|---|
| 722 | + remote = of_graph_get_remote_endpoint(ep); |
|---|
| 723 | + of_node_put(ep); |
|---|
| 724 | + if (!remote) |
|---|
| 725 | + return -EINVAL; |
|---|
| 688 | 726 | |
|---|
| 689 | | - remote = of_graph_get_remote_endpoint(ep); |
|---|
| 690 | | - if (!remote) |
|---|
| 691 | | - continue; |
|---|
| 692 | | - |
|---|
| 693 | | - ret = of_property_read_u32(remote, "reg", ®); |
|---|
| 694 | | - if (ret) |
|---|
| 695 | | - continue; |
|---|
| 696 | | - |
|---|
| 697 | | - ret = reg; |
|---|
| 698 | | - } |
|---|
| 699 | | - |
|---|
| 700 | | - of_node_put(port); |
|---|
| 701 | | - |
|---|
| 702 | | - return ret; |
|---|
| 727 | + of_graph_parse_endpoint(remote, &of_ep); |
|---|
| 728 | + of_node_put(remote); |
|---|
| 729 | + return of_ep.id; |
|---|
| 703 | 730 | } |
|---|
| 704 | 731 | |
|---|
| 705 | 732 | /* TODO: This needs to take multiple pipelines into account */ |
|---|
| .. | .. |
|---|
| 742 | 769 | .vblank_quirk = sun4i_backend_vblank_quirk, |
|---|
| 743 | 770 | }; |
|---|
| 744 | 771 | |
|---|
| 745 | | -static struct regmap_config sun4i_backend_regmap_config = { |
|---|
| 772 | +static const struct regmap_config sun4i_backend_regmap_config = { |
|---|
| 746 | 773 | .reg_bits = 32, |
|---|
| 747 | 774 | .val_bits = 32, |
|---|
| 748 | 775 | .reg_stride = 4, |
|---|
| .. | .. |
|---|
| 766 | 793 | return -ENOMEM; |
|---|
| 767 | 794 | dev_set_drvdata(dev, backend); |
|---|
| 768 | 795 | spin_lock_init(&backend->frontend_lock); |
|---|
| 796 | + |
|---|
| 797 | + if (of_find_property(dev->of_node, "interconnects", NULL)) { |
|---|
| 798 | + /* |
|---|
| 799 | + * This assume we have the same DMA constraints for all our the |
|---|
| 800 | + * devices in our pipeline (all the backends, but also the |
|---|
| 801 | + * frontends). This sounds bad, but it has always been the case |
|---|
| 802 | + * for us, and DRM doesn't do per-device allocation either, so |
|---|
| 803 | + * we would need to fix DRM first... |
|---|
| 804 | + */ |
|---|
| 805 | + ret = of_dma_configure(drm->dev, dev->of_node, true); |
|---|
| 806 | + if (ret) |
|---|
| 807 | + return ret; |
|---|
| 808 | + } else { |
|---|
| 809 | + /* |
|---|
| 810 | + * If we don't have the interconnect property, most likely |
|---|
| 811 | + * because of an old DT, we need to set the DMA offset by hand |
|---|
| 812 | + * on our device since the RAM mapping is at 0 for the DMA bus, |
|---|
| 813 | + * unlike the CPU. |
|---|
| 814 | + * |
|---|
| 815 | + * XXX(hch): this has no business in a driver and needs to move |
|---|
| 816 | + * to the device tree. |
|---|
| 817 | + * |
|---|
| 818 | + * If we have two subsequent calls to dma_direct_set_offset |
|---|
| 819 | + * returns -EINVAL. Unfortunately, this happens when we have two |
|---|
| 820 | + * backends in the system, and will result in the driver |
|---|
| 821 | + * reporting an error while it has been setup properly before. |
|---|
| 822 | + * Ignore EINVAL, but it should really be removed eventually. |
|---|
| 823 | + */ |
|---|
| 824 | + ret = dma_direct_set_offset(drm->dev, PHYS_OFFSET, 0, SZ_4G); |
|---|
| 825 | + if (ret && ret != -EINVAL) |
|---|
| 826 | + return ret; |
|---|
| 827 | + } |
|---|
| 769 | 828 | |
|---|
| 770 | 829 | backend->engine.node = dev->of_node; |
|---|
| 771 | 830 | backend->engine.ops = &sun4i_backend_engine_ops; |
|---|
| .. | .. |
|---|
| 808 | 867 | ret = PTR_ERR(backend->mod_clk); |
|---|
| 809 | 868 | goto err_disable_bus_clk; |
|---|
| 810 | 869 | } |
|---|
| 870 | + |
|---|
| 871 | + ret = clk_set_rate_exclusive(backend->mod_clk, 300000000); |
|---|
| 872 | + if (ret) { |
|---|
| 873 | + dev_err(dev, "Couldn't set the module clock frequency\n"); |
|---|
| 874 | + goto err_disable_bus_clk; |
|---|
| 875 | + } |
|---|
| 876 | + |
|---|
| 811 | 877 | clk_prepare_enable(backend->mod_clk); |
|---|
| 812 | 878 | |
|---|
| 813 | 879 | backend->ram_clk = devm_clk_get(dev, "ram"); |
|---|
| .. | .. |
|---|
| 877 | 943 | : SUN4I_BACKEND_MODCTL_OUT_LCD0)); |
|---|
| 878 | 944 | } |
|---|
| 879 | 945 | |
|---|
| 946 | + backend->quirks = quirks; |
|---|
| 947 | + |
|---|
| 880 | 948 | return 0; |
|---|
| 881 | 949 | |
|---|
| 882 | 950 | err_disable_ram_clk: |
|---|
| 883 | 951 | clk_disable_unprepare(backend->ram_clk); |
|---|
| 884 | 952 | err_disable_mod_clk: |
|---|
| 953 | + clk_rate_exclusive_put(backend->mod_clk); |
|---|
| 885 | 954 | clk_disable_unprepare(backend->mod_clk); |
|---|
| 886 | 955 | err_disable_bus_clk: |
|---|
| 887 | 956 | clk_disable_unprepare(backend->bus_clk); |
|---|
| .. | .. |
|---|
| 902 | 971 | sun4i_backend_free_sat(dev); |
|---|
| 903 | 972 | |
|---|
| 904 | 973 | clk_disable_unprepare(backend->ram_clk); |
|---|
| 974 | + clk_rate_exclusive_put(backend->mod_clk); |
|---|
| 905 | 975 | clk_disable_unprepare(backend->mod_clk); |
|---|
| 906 | 976 | clk_disable_unprepare(backend->bus_clk); |
|---|
| 907 | 977 | reset_control_assert(backend->reset); |
|---|
| .. | .. |
|---|
| 939 | 1009 | }; |
|---|
| 940 | 1010 | |
|---|
| 941 | 1011 | static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = { |
|---|
| 1012 | + .supports_lowest_plane_alpha = true, |
|---|
| 942 | 1013 | }; |
|---|
| 943 | 1014 | |
|---|
| 944 | 1015 | static const struct sun4i_backend_quirks sun9i_backend_quirks = { |
|---|
| .. | .. |
|---|
| 962 | 1033 | .data = &sun7i_backend_quirks, |
|---|
| 963 | 1034 | }, |
|---|
| 964 | 1035 | { |
|---|
| 1036 | + .compatible = "allwinner,sun8i-a23-display-backend", |
|---|
| 1037 | + .data = &sun8i_a33_backend_quirks, |
|---|
| 1038 | + }, |
|---|
| 1039 | + { |
|---|
| 965 | 1040 | .compatible = "allwinner,sun8i-a33-display-backend", |
|---|
| 966 | 1041 | .data = &sun8i_a33_backend_quirks, |
|---|
| 967 | 1042 | }, |
|---|