Lines Matching +full:display +full:- +full:backend
1 // SPDX-License-Identifier: GPL-2.0-or-later
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
14 #include <linux/dma-mapping.h>
35 /* backend <-> TCON muxing selection done in backend */
55 regmap_write(engine->regs, SUN4I_BACKEND_OCCTL_REG, in sun4i_backend_apply_color_correction()
59 regmap_write(engine->regs, SUN4I_BACKEND_OCRCOEF_REG(i), in sun4i_backend_apply_color_correction()
68 regmap_update_bits(engine->regs, SUN4I_BACKEND_OCCTL_REG, in sun4i_backend_disable_color_correction()
76 regmap_write(engine->regs, SUN4I_BACKEND_REGBUFFCTL_REG, in sun4i_backend_commit()
81 void sun4i_backend_layer_enable(struct sun4i_backend *backend, in sun4i_backend_layer_enable() argument
94 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG, in sun4i_backend_layer_enable()
134 return -EINVAL; in sun4i_backend_drm_format_to_layer()
169 int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, in sun4i_backend_update_layer_coord() argument
172 struct drm_plane_state *state = plane->state; in sun4i_backend_update_layer_coord()
178 state->crtc_w, state->crtc_h); in sun4i_backend_update_layer_coord()
179 regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYSIZE_REG(layer), in sun4i_backend_update_layer_coord()
180 SUN4I_BACKEND_LAYSIZE(state->crtc_w, in sun4i_backend_update_layer_coord()
181 state->crtc_h)); in sun4i_backend_update_layer_coord()
185 state->crtc_x, state->crtc_y); in sun4i_backend_update_layer_coord()
186 regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYCOOR_REG(layer), in sun4i_backend_update_layer_coord()
187 SUN4I_BACKEND_LAYCOOR(state->crtc_x, in sun4i_backend_update_layer_coord()
188 state->crtc_y)); in sun4i_backend_update_layer_coord()
193 static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend, in sun4i_backend_update_yuv_format() argument
196 struct drm_plane_state *state = plane->state; in sun4i_backend_update_yuv_format()
197 struct drm_framebuffer *fb = state->fb; in sun4i_backend_update_yuv_format()
198 const struct drm_format_info *format = fb->format; in sun4i_backend_update_yuv_format()
199 const uint32_t fmt = format->format; in sun4i_backend_update_yuv_format()
204 regmap_write(backend->engine.regs, in sun4i_backend_update_yuv_format()
212 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), in sun4i_backend_update_yuv_format()
216 /* TODO: Add support for the multi-planar YUV formats */ in sun4i_backend_update_yuv_format()
245 regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val); in sun4i_backend_update_yuv_format()
250 int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, in sun4i_backend_update_layer_formats() argument
253 struct drm_plane_state *state = plane->state; in sun4i_backend_update_layer_formats()
254 struct drm_framebuffer *fb = state->fb; in sun4i_backend_update_layer_formats()
259 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), in sun4i_backend_update_layer_formats()
262 val = SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA(state->alpha >> 8); in sun4i_backend_update_layer_formats()
263 if (state->alpha != DRM_BLEND_ALPHA_OPAQUE) in sun4i_backend_update_layer_formats()
265 regmap_update_bits(backend->engine.regs, in sun4i_backend_update_layer_formats()
271 if (fb->format->is_yuv) in sun4i_backend_update_layer_formats()
272 return sun4i_backend_update_yuv_format(backend, layer, plane); in sun4i_backend_update_layer_formats()
274 ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val); in sun4i_backend_update_layer_formats()
280 regmap_update_bits(backend->engine.regs, in sun4i_backend_update_layer_formats()
287 int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend, in sun4i_backend_update_layer_frontend() argument
299 regmap_update_bits(backend->engine.regs, in sun4i_backend_update_layer_frontend()
304 regmap_update_bits(backend->engine.regs, in sun4i_backend_update_layer_frontend()
311 static int sun4i_backend_update_yuv_buffer(struct sun4i_backend *backend, in sun4i_backend_update_yuv_buffer() argument
315 /* TODO: Add support for the multi-planar YUV formats */ in sun4i_backend_update_yuv_buffer()
317 regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVADD_REG(0), paddr); in sun4i_backend_update_yuv_buffer()
319 DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); in sun4i_backend_update_yuv_buffer()
320 regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVLINEWIDTH_REG(0), in sun4i_backend_update_yuv_buffer()
321 fb->pitches[0] * 8); in sun4i_backend_update_yuv_buffer()
326 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, in sun4i_backend_update_layer_buffer() argument
329 struct drm_plane_state *state = plane->state; in sun4i_backend_update_layer_buffer()
330 struct drm_framebuffer *fb = state->fb; in sun4i_backend_update_layer_buffer()
335 DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); in sun4i_backend_update_layer_buffer()
336 regmap_write(backend->engine.regs, in sun4i_backend_update_layer_buffer()
338 fb->pitches[0] * 8); in sun4i_backend_update_layer_buffer()
344 if (fb->format->is_yuv) in sun4i_backend_update_layer_buffer()
345 return sun4i_backend_update_yuv_buffer(backend, fb, dma_addr); in sun4i_backend_update_layer_buffer()
350 regmap_write(backend->engine.regs, in sun4i_backend_update_layer_buffer()
357 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_LAYFB_H4ADD_REG, in sun4i_backend_update_layer_buffer()
364 int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer, in sun4i_backend_update_layer_zpos() argument
367 struct drm_plane_state *state = plane->state; in sun4i_backend_update_layer_zpos()
369 unsigned int priority = state->normalized_zpos; in sun4i_backend_update_layer_zpos()
370 unsigned int pipe = p_state->pipe; in sun4i_backend_update_layer_zpos()
374 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), in sun4i_backend_update_layer_zpos()
377 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(p_state->pipe) | in sun4i_backend_update_layer_zpos()
383 void sun4i_backend_cleanup_layer(struct sun4i_backend *backend, in sun4i_backend_cleanup_layer() argument
386 regmap_update_bits(backend->engine.regs, in sun4i_backend_cleanup_layer()
394 u16 src_h = state->src_h >> 16; in sun4i_backend_plane_uses_scaler()
395 u16 src_w = state->src_w >> 16; in sun4i_backend_plane_uses_scaler()
398 src_w, src_h, state->crtc_w, state->crtc_h); in sun4i_backend_plane_uses_scaler()
400 if ((state->crtc_h != src_h) || (state->crtc_w != src_w)) in sun4i_backend_plane_uses_scaler()
408 struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane); in sun4i_backend_plane_uses_frontend()
409 struct sun4i_backend *backend = layer->backend; in sun4i_backend_plane_uses_frontend() local
410 uint32_t format = state->fb->format->format; in sun4i_backend_plane_uses_frontend()
411 uint64_t modifier = state->fb->modifier; in sun4i_backend_plane_uses_frontend()
413 if (IS_ERR(backend->frontend)) in sun4i_backend_plane_uses_frontend()
423 * TODO: The backend alone allows 2x and 4x integer scaling, including in sun4i_backend_plane_uses_frontend()
425 * Use the backend directly instead of the frontend in this case, with in sun4i_backend_plane_uses_frontend()
433 * Here the format is supported by both the frontend and the backend in sun4i_backend_plane_uses_frontend()
434 * and no frontend scaling is required, so use the backend directly. in sun4i_backend_plane_uses_frontend()
461 WARN_ON(regmap_read_poll_timeout(engine->regs, in sun4i_backend_atomic_begin()
471 struct sun4i_backend *backend = engine_to_sun4i_backend(engine); in sun4i_backend_atomic_check() local
472 struct drm_atomic_state *state = crtc_state->state; in sun4i_backend_atomic_check()
473 struct drm_device *drm = state->dev; in sun4i_backend_atomic_check()
485 if (!crtc_state->planes_changed) in sun4i_backend_atomic_check()
488 drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { in sun4i_backend_atomic_check()
493 struct drm_framebuffer *fb = plane_state->fb; in sun4i_backend_atomic_check()
496 &layer_state->uses_frontend)) in sun4i_backend_atomic_check()
497 return -EINVAL; in sun4i_backend_atomic_check()
499 if (layer_state->uses_frontend) { in sun4i_backend_atomic_check()
501 plane->index); in sun4i_backend_atomic_check()
504 if (fb->format->is_yuv) { in sun4i_backend_atomic_check()
511 &fb->format->format); in sun4i_backend_atomic_check()
512 if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE)) in sun4i_backend_atomic_check()
516 plane_state->normalized_zpos); in sun4i_backend_atomic_check()
519 plane_states[plane_state->normalized_zpos] = plane_state; in sun4i_backend_atomic_check()
543 * This two-step scenario makes us unable to guarantee a in sun4i_backend_atomic_check()
551 * discard the pixel data entirely and just display the pixels in sun4i_backend_atomic_check()
562 if (backend->quirks->supports_lowest_plane_alpha) in sun4i_backend_atomic_check()
567 return -EINVAL; in sun4i_backend_atomic_check()
571 if (!backend->quirks->supports_lowest_plane_alpha && in sun4i_backend_atomic_check()
572 (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE)) in sun4i_backend_atomic_check()
573 return -EINVAL; in sun4i_backend_atomic_check()
577 struct drm_framebuffer *fb = p_state->fb; in sun4i_backend_atomic_check()
584 if (fb->format->has_alpha || (p_state->alpha != DRM_BLEND_ALPHA_OPAQUE)) in sun4i_backend_atomic_check()
587 s_state->pipe = current_pipe; in sun4i_backend_atomic_check()
593 return -EINVAL; in sun4i_backend_atomic_check()
598 return -EINVAL; in sun4i_backend_atomic_check()
610 struct sun4i_backend *backend = engine_to_sun4i_backend(engine); in sun4i_backend_vblank_quirk() local
611 struct sun4i_frontend *frontend = backend->frontend; in sun4i_backend_vblank_quirk()
621 * This is due to the fact that the backend will not take into in sun4i_backend_vblank_quirk()
630 spin_lock(&backend->frontend_lock); in sun4i_backend_vblank_quirk()
631 if (backend->frontend_teardown) { in sun4i_backend_vblank_quirk()
633 backend->frontend_teardown = false; in sun4i_backend_vblank_quirk()
635 spin_unlock(&backend->frontend_lock); in sun4i_backend_vblank_quirk()
641 bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); in sun4i_backend_mode_set()
644 mode->hdisplay, mode->vdisplay); in sun4i_backend_mode_set()
646 regmap_write(engine->regs, SUN4I_BACKEND_DISSIZE_REG, in sun4i_backend_mode_set()
647 SUN4I_BACKEND_DISSIZE(mode->hdisplay, mode->vdisplay)); in sun4i_backend_mode_set()
649 regmap_update_bits(engine->regs, SUN4I_BACKEND_MODCTL_REG, in sun4i_backend_mode_set()
653 DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", in sun4i_backend_mode_set()
658 struct sun4i_backend *backend = dev_get_drvdata(dev); in sun4i_backend_init_sat() local
661 backend->sat_reset = devm_reset_control_get(dev, "sat"); in sun4i_backend_init_sat()
662 if (IS_ERR(backend->sat_reset)) { in sun4i_backend_init_sat()
664 return PTR_ERR(backend->sat_reset); in sun4i_backend_init_sat()
667 ret = reset_control_deassert(backend->sat_reset); in sun4i_backend_init_sat()
673 backend->sat_clk = devm_clk_get(dev, "sat"); in sun4i_backend_init_sat()
674 if (IS_ERR(backend->sat_clk)) { in sun4i_backend_init_sat()
676 ret = PTR_ERR(backend->sat_clk); in sun4i_backend_init_sat()
680 ret = clk_prepare_enable(backend->sat_clk); in sun4i_backend_init_sat()
689 reset_control_assert(backend->sat_reset); in sun4i_backend_init_sat()
694 struct sun4i_backend *backend = dev_get_drvdata(dev); in sun4i_backend_free_sat() local
696 clk_disable_unprepare(backend->sat_clk); in sun4i_backend_free_sat()
697 reset_control_assert(backend->sat_reset); in sun4i_backend_free_sat()
703 * The display backend can take video output from the display frontend, or
704 * the display enhancement unit on the A80, as input for one it its layers.
705 * This relationship within the display pipeline is encoded in the device
706 * tree with of_graph, and we use it here to figure out which backend, if
716 ep = of_graph_get_endpoint_by_regs(node, 0, -1); in sun4i_backend_of_get_id()
718 return -EINVAL; in sun4i_backend_of_get_id()
723 return -EINVAL; in sun4i_backend_of_get_id()
739 return ERR_PTR(-EINVAL); in sun4i_backend_find_frontend()
748 list_for_each_entry(frontend, &drv->frontend_list, list) { in sun4i_backend_find_frontend()
749 if (remote == frontend->node) { in sun4i_backend_find_frontend()
757 return ERR_PTR(-EINVAL); in sun4i_backend_find_frontend()
783 struct sun4i_drv *drv = drm->dev_private; in sun4i_backend_bind()
784 struct sun4i_backend *backend; in sun4i_backend_bind() local
789 backend = devm_kzalloc(dev, sizeof(*backend), GFP_KERNEL); in sun4i_backend_bind()
790 if (!backend) in sun4i_backend_bind()
791 return -ENOMEM; in sun4i_backend_bind()
792 dev_set_drvdata(dev, backend); in sun4i_backend_bind()
793 spin_lock_init(&backend->frontend_lock); in sun4i_backend_bind()
795 if (of_property_present(dev->of_node, "interconnects")) { in sun4i_backend_bind()
800 * for us, and DRM doesn't do per-device allocation either, so in sun4i_backend_bind()
803 ret = of_dma_configure(drm->dev, dev->of_node, true); in sun4i_backend_bind()
808 backend->engine.node = dev->of_node; in sun4i_backend_bind()
809 backend->engine.ops = &sun4i_backend_engine_ops; in sun4i_backend_bind()
810 backend->engine.id = sun4i_backend_of_get_id(dev->of_node); in sun4i_backend_bind()
811 if (backend->engine.id < 0) in sun4i_backend_bind()
812 return backend->engine.id; in sun4i_backend_bind()
814 backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node); in sun4i_backend_bind()
815 if (IS_ERR(backend->frontend)) in sun4i_backend_bind()
822 backend->reset = devm_reset_control_get(dev, NULL); in sun4i_backend_bind()
823 if (IS_ERR(backend->reset)) { in sun4i_backend_bind()
825 return PTR_ERR(backend->reset); in sun4i_backend_bind()
828 ret = reset_control_deassert(backend->reset); in sun4i_backend_bind()
834 backend->bus_clk = devm_clk_get(dev, "ahb"); in sun4i_backend_bind()
835 if (IS_ERR(backend->bus_clk)) { in sun4i_backend_bind()
836 dev_err(dev, "Couldn't get the backend bus clock\n"); in sun4i_backend_bind()
837 ret = PTR_ERR(backend->bus_clk); in sun4i_backend_bind()
840 clk_prepare_enable(backend->bus_clk); in sun4i_backend_bind()
842 backend->mod_clk = devm_clk_get(dev, "mod"); in sun4i_backend_bind()
843 if (IS_ERR(backend->mod_clk)) { in sun4i_backend_bind()
844 dev_err(dev, "Couldn't get the backend module clock\n"); in sun4i_backend_bind()
845 ret = PTR_ERR(backend->mod_clk); in sun4i_backend_bind()
849 ret = clk_set_rate_exclusive(backend->mod_clk, 300000000); in sun4i_backend_bind()
855 clk_prepare_enable(backend->mod_clk); in sun4i_backend_bind()
857 backend->ram_clk = devm_clk_get(dev, "ram"); in sun4i_backend_bind()
858 if (IS_ERR(backend->ram_clk)) { in sun4i_backend_bind()
859 dev_err(dev, "Couldn't get the backend RAM clock\n"); in sun4i_backend_bind()
860 ret = PTR_ERR(backend->ram_clk); in sun4i_backend_bind()
863 clk_prepare_enable(backend->ram_clk); in sun4i_backend_bind()
865 if (of_device_is_compatible(dev->of_node, in sun4i_backend_bind()
866 "allwinner,sun8i-a33-display-backend")) { in sun4i_backend_bind()
874 backend->engine.regs = devm_regmap_init_mmio(dev, regs, in sun4i_backend_bind()
876 if (IS_ERR(backend->engine.regs)) { in sun4i_backend_bind()
877 dev_err(dev, "Couldn't create the backend regmap\n"); in sun4i_backend_bind()
878 return PTR_ERR(backend->engine.regs); in sun4i_backend_bind()
881 list_add_tail(&backend->engine.list, &drv->engine_list); in sun4i_backend_bind()
884 * Many of the backend's layer configuration registers have in sun4i_backend_bind()
892 regmap_write(backend->engine.regs, i, 0); in sun4i_backend_bind()
895 regmap_write(backend->engine.regs, SUN4I_BACKEND_REGBUFFCTL_REG, in sun4i_backend_bind()
898 /* Enable the backend */ in sun4i_backend_bind()
899 regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG, in sun4i_backend_bind()
905 if (quirks->needs_output_muxing) { in sun4i_backend_bind()
908 * and TCONs, so we select the backend with same ID. in sun4i_backend_bind()
916 regmap_update_bits(backend->engine.regs, in sun4i_backend_bind()
919 (backend->engine.id in sun4i_backend_bind()
924 backend->quirks = quirks; in sun4i_backend_bind()
929 clk_disable_unprepare(backend->ram_clk); in sun4i_backend_bind()
931 clk_rate_exclusive_put(backend->mod_clk); in sun4i_backend_bind()
932 clk_disable_unprepare(backend->mod_clk); in sun4i_backend_bind()
934 clk_disable_unprepare(backend->bus_clk); in sun4i_backend_bind()
936 reset_control_assert(backend->reset); in sun4i_backend_bind()
943 struct sun4i_backend *backend = dev_get_drvdata(dev); in sun4i_backend_unbind() local
945 list_del(&backend->engine.list); in sun4i_backend_unbind()
947 if (of_device_is_compatible(dev->of_node, in sun4i_backend_unbind()
948 "allwinner,sun8i-a33-display-backend")) in sun4i_backend_unbind()
951 clk_disable_unprepare(backend->ram_clk); in sun4i_backend_unbind()
952 clk_rate_exclusive_put(backend->mod_clk); in sun4i_backend_unbind()
953 clk_disable_unprepare(backend->mod_clk); in sun4i_backend_unbind()
954 clk_disable_unprepare(backend->bus_clk); in sun4i_backend_unbind()
955 reset_control_assert(backend->reset); in sun4i_backend_unbind()
965 return component_add(&pdev->dev, &sun4i_backend_ops); in sun4i_backend_probe()
970 component_del(&pdev->dev, &sun4i_backend_ops); in sun4i_backend_remove()
996 .compatible = "allwinner,sun4i-a10-display-backend",
1000 .compatible = "allwinner,sun5i-a13-display-backend",
1004 .compatible = "allwinner,sun6i-a31-display-backend",
1008 .compatible = "allwinner,sun7i-a20-display-backend",
1012 .compatible = "allwinner,sun8i-a23-display-backend",
1016 .compatible = "allwinner,sun8i-a33-display-backend",
1020 .compatible = "allwinner,sun9i-a80-display-backend",
1031 .name = "sun4i-backend",
1037 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1038 MODULE_DESCRIPTION("Allwinner A10 Display Backend Driver");