Lines Matching +full:display +full:- +full:controller
1 // SPDX-License-Identifier: GPL-2.0
3 * ZynqMP Display Controller Driver
5 * Copyright (C) 2017 - 2020 Xilinx, Inc.
8 * - Hyun Woo Kwon <hyun.kwon@xilinx.com>
9 * - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
28 #include <linux/dma-mapping.h>
43 * --------
45 * The display controller part of ZynqMP DP subsystem, made of the Audio/Video
48 * +------------------------------------------------------------+
49 * +--------+ | +----------------+ +-----------+ |
50 * | DPDMA | --->| | --> | Video | Video +-------------+ |
51 * | 4x vid | | | | | Rendering | -+--> | | | +------+
52 * | 2x aud | | | Audio/Video | --> | Pipeline | | | DisplayPort |---> | PHY0 |
53 * +--------+ | | Buffer Manager | +-----------+ | | Source | | +------+
54 * | | and STC | +-----------+ | | Controller | | +------+
55 * Live Video --->| | --> | Audio | Audio | |---> | PHY1 |
56 * | | | | Mixer | --+-> | | | +------+
57 * Live Audio --->| | --> | | || +-------------+ |
58 * | +----------------+ +-----------+ || |
59 * +---------------------------------------||-------------------+
64 * Only non-live input from the DPDMA and output to the DisplayPort Source
65 * Controller are currently supported. Interface with the programmable logic
68 * The display controller code creates planes for the DPDMA video and graphics
79 * struct zynqmp_disp_format - Display subsystem format information
95 * enum zynqmp_disp_layer_id - Layer identifier
105 * enum zynqmp_disp_layer_mode - Layer mode
106 * @ZYNQMP_DISP_LAYER_NONLIVE: non-live (memory) mode
115 * struct zynqmp_disp_layer_dma - DMA channel for one data plane of a layer
127 * struct zynqmp_disp_layer_info - Static layer information
139 * struct zynqmp_disp_layer - Display layer (DRM plane)
163 * struct zynqmp_disp - Display controller
166 * @dpsub: Display subsystem
205 /* -----------------------------------------------------------------------------
411 return readl(disp->avbuf.base + reg); in zynqmp_disp_avbuf_read()
416 writel(val, disp->avbuf.base + reg); in zynqmp_disp_avbuf_write()
421 return layer->id == ZYNQMP_DISP_LAYER_GFX; in zynqmp_disp_layer_is_gfx()
426 return layer->id == ZYNQMP_DISP_LAYER_VID; in zynqmp_disp_layer_is_video()
430 * zynqmp_disp_avbuf_set_format - Set the input format for a layer
431 * @disp: Display controller
448 val |= fmt->buf_fmt; in zynqmp_disp_avbuf_set_format()
456 zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]); in zynqmp_disp_avbuf_set_format()
461 * zynqmp_disp_avbuf_set_clocks_sources - Set the clocks sources
462 * @disp: Display controller
489 * zynqmp_disp_avbuf_enable_channels - Enable buffer channels
490 * @disp: Display controller
517 * zynqmp_disp_avbuf_disable_channels - Disable buffer channels
518 * @disp: Display controller
532 * zynqmp_disp_avbuf_enable_audio - Enable audio
533 * @disp: Display controller
535 * Enable all audio buffers with a non-live (memory) source.
549 * zynqmp_disp_avbuf_disable_audio - Disable audio
550 * @disp: Display controller
566 * zynqmp_disp_avbuf_enable_video - Enable a video layer
567 * @disp: Display controller
598 * zynqmp_disp_avbuf_disable_video - Disable a video layer
599 * @disp: Display controller
621 * zynqmp_disp_avbuf_enable - Enable the video pipe
622 * @disp: Display controller
624 * De-assert the video pipe reset.
632 * zynqmp_disp_avbuf_disable - Disable the video pipe
633 * @disp: Display controller
643 /* -----------------------------------------------------------------------------
649 writel(val, disp->blend.base + reg); in zynqmp_disp_blend_write()
655 * Hardcode RGB <-> YUV conversion to full-range SDTV for now.
694 * zynqmp_disp_blend_set_output_format - Set the output format of the blender
695 * @disp: Display controller
737 * zynqmp_disp_blend_set_bg_color - Set the background color
738 * @disp: Display controller
756 * zynqmp_disp_blend_set_global_alpha - Configure global alpha blending
757 * @disp: Display controller
770 * zynqmp_disp_blend_layer_set_csc - Configure colorspace conversion for layer
771 * @disp: Display controller
789 if (layer->disp_fmt->swap) { in zynqmp_disp_blend_layer_set_csc()
790 if (layer->drm_fmt->is_yuv) { in zynqmp_disp_blend_layer_set_csc()
822 * zynqmp_disp_blend_layer_enable - Enable a layer
823 * @disp: Display controller
833 val = (layer->drm_fmt->is_yuv ? in zynqmp_disp_blend_layer_enable()
835 (layer->drm_fmt->hsub > 1 ? in zynqmp_disp_blend_layer_enable()
839 ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id), in zynqmp_disp_blend_layer_enable()
842 if (layer->drm_fmt->is_yuv) { in zynqmp_disp_blend_layer_enable()
854 * zynqmp_disp_blend_layer_disable - Disable a layer
855 * @disp: Display controller
862 ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id), in zynqmp_disp_blend_layer_disable()
869 /* -----------------------------------------------------------------------------
875 writel(val, disp->audio.base + reg); in zynqmp_disp_audio_write()
879 * zynqmp_disp_audio_enable - Enable the audio mixer
880 * @disp: Display controller
882 * Enable the audio mixer by de-asserting the soft reset. The audio state is set to
887 /* Clear the audio soft reset register as it's an non-reset flop. */ in zynqmp_disp_audio_enable()
894 * zynqmp_disp_audio_disable - Disable the audio mixer
895 * @disp: Display controller
908 disp->audio.clk = devm_clk_get(disp->dev, "dp_live_audio_aclk"); in zynqmp_disp_audio_init()
909 if (!IS_ERR(disp->audio.clk)) { in zynqmp_disp_audio_init()
910 disp->audio.clk_from_ps = false; in zynqmp_disp_audio_init()
915 disp->audio.clk = devm_clk_get(disp->dev, "dp_aud_clk"); in zynqmp_disp_audio_init()
916 if (!IS_ERR(disp->audio.clk)) { in zynqmp_disp_audio_init()
917 disp->audio.clk_from_ps = true; in zynqmp_disp_audio_init()
921 dev_err(disp->dev, "audio disabled due to missing clock\n"); in zynqmp_disp_audio_init()
924 /* -----------------------------------------------------------------------------
925 * ZynqMP Display external functions for zynqmp_dp
929 * zynqmp_disp_handle_vblank - Handle the vblank event
930 * @disp: Display controller
937 struct drm_crtc *crtc = &disp->crtc; in zynqmp_disp_handle_vblank()
943 * zynqmp_disp_audio_enabled - If the audio is enabled
944 * @disp: Display controller
952 return !!disp->audio.clk; in zynqmp_disp_audio_enabled()
956 * zynqmp_disp_get_audio_clk_rate - Get the current audio clock rate
957 * @disp: Display controller
965 return clk_get_rate(disp->audio.clk); in zynqmp_disp_get_audio_clk_rate()
969 * zynqmp_disp_get_crtc_mask - Return the CRTC bit mask
970 * @disp: Display controller
976 return drm_crtc_mask(&disp->crtc); in zynqmp_disp_get_crtc_mask()
979 /* -----------------------------------------------------------------------------
980 * ZynqMP Display Layer & DRM Plane
984 * zynqmp_disp_layer_find_format - Find format information for a DRM format
988 * Search display subsystem format information corresponding to the given DRM
1000 for (i = 0; i < layer->info->num_formats; i++) { in zynqmp_disp_layer_find_format()
1001 if (layer->info->formats[i].drm_fmt == drm_fmt) in zynqmp_disp_layer_find_format()
1002 return &layer->info->formats[i]; in zynqmp_disp_layer_find_format()
1009 * zynqmp_disp_layer_enable - Enable a layer
1017 zynqmp_disp_avbuf_enable_video(layer->disp, layer, in zynqmp_disp_layer_enable()
1019 zynqmp_disp_blend_layer_enable(layer->disp, layer); in zynqmp_disp_layer_enable()
1021 layer->mode = ZYNQMP_DISP_LAYER_NONLIVE; in zynqmp_disp_layer_enable()
1025 * zynqmp_disp_layer_disable - Disable the layer
1035 for (i = 0; i < layer->drm_fmt->num_planes; i++) in zynqmp_disp_layer_disable()
1036 dmaengine_terminate_sync(layer->dmas[i].chan); in zynqmp_disp_layer_disable()
1038 zynqmp_disp_avbuf_disable_video(layer->disp, layer); in zynqmp_disp_layer_disable()
1039 zynqmp_disp_blend_layer_disable(layer->disp, layer); in zynqmp_disp_layer_disable()
1043 * zynqmp_disp_layer_set_format - Set the layer format
1047 * Set the format for @layer based on @state->fb->format. The layer must be
1053 const struct drm_format_info *info = state->fb->format; in zynqmp_disp_layer_set_format()
1056 layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format); in zynqmp_disp_layer_set_format()
1057 layer->drm_fmt = info; in zynqmp_disp_layer_set_format()
1059 zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt); in zynqmp_disp_layer_set_format()
1065 for (i = 0; i < info->num_planes; i++) { in zynqmp_disp_layer_set_format()
1066 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; in zynqmp_disp_layer_set_format()
1076 dmaengine_slave_config(dma->chan, &config); in zynqmp_disp_layer_set_format()
1081 * zynqmp_disp_layer_update - Update the layer framebuffer
1093 const struct drm_format_info *info = layer->drm_fmt; in zynqmp_disp_layer_update()
1096 for (i = 0; i < layer->drm_fmt->num_planes; i++) { in zynqmp_disp_layer_update()
1097 unsigned int width = state->crtc_w / (i ? info->hsub : 1); in zynqmp_disp_layer_update()
1098 unsigned int height = state->crtc_h / (i ? info->vsub : 1); in zynqmp_disp_layer_update()
1099 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; in zynqmp_disp_layer_update()
1103 dma_addr = drm_fb_dma_get_gem_addr(state->fb, state, i); in zynqmp_disp_layer_update()
1105 dma->xt.numf = height; in zynqmp_disp_layer_update()
1106 dma->sgl.size = width * info->cpp[i]; in zynqmp_disp_layer_update()
1107 dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size; in zynqmp_disp_layer_update()
1108 dma->xt.src_start = dma_addr; in zynqmp_disp_layer_update()
1109 dma->xt.frame_size = 1; in zynqmp_disp_layer_update()
1110 dma->xt.dir = DMA_MEM_TO_DEV; in zynqmp_disp_layer_update()
1111 dma->xt.src_sgl = true; in zynqmp_disp_layer_update()
1112 dma->xt.dst_sgl = false; in zynqmp_disp_layer_update()
1114 desc = dmaengine_prep_interleaved_dma(dma->chan, &dma->xt, in zynqmp_disp_layer_update()
1119 dev_err(layer->disp->dev, in zynqmp_disp_layer_update()
1121 return -ENOMEM; in zynqmp_disp_layer_update()
1125 dma_async_issue_pending(dma->chan); in zynqmp_disp_layer_update()
1144 if (!new_plane_state->crtc) in zynqmp_disp_plane_atomic_check()
1147 crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc); in zynqmp_disp_plane_atomic_check()
1166 if (!old_state->fb) in zynqmp_disp_plane_atomic_disable()
1172 zynqmp_disp_blend_set_global_alpha(layer->disp, false, in zynqmp_disp_plane_atomic_disable()
1173 plane->state->alpha >> 8); in zynqmp_disp_plane_atomic_disable()
1185 if (!old_state->fb || in zynqmp_disp_plane_atomic_update()
1186 old_state->fb->format->format != new_state->fb->format->format) in zynqmp_disp_plane_atomic_update()
1195 if (old_state->fb) in zynqmp_disp_plane_atomic_update()
1204 zynqmp_disp_blend_set_global_alpha(layer->disp, true, in zynqmp_disp_plane_atomic_update()
1205 plane->state->alpha >> 8); in zynqmp_disp_plane_atomic_update()
1207 /* Enable or re-enable the plane is the format has changed. */ in zynqmp_disp_plane_atomic_update()
1233 struct zynqmp_disp_layer *layer = &disp->layers[i]; in zynqmp_disp_create_planes()
1237 drm_formats = drmm_kcalloc(disp->drm, sizeof(*drm_formats), in zynqmp_disp_create_planes()
1238 layer->info->num_formats, in zynqmp_disp_create_planes()
1241 return -ENOMEM; in zynqmp_disp_create_planes()
1243 for (j = 0; j < layer->info->num_formats; ++j) in zynqmp_disp_create_planes()
1244 drm_formats[j] = layer->info->formats[j].drm_fmt; in zynqmp_disp_create_planes()
1249 ret = drm_universal_plane_init(disp->drm, &layer->plane, 0, in zynqmp_disp_create_planes()
1252 layer->info->num_formats, in zynqmp_disp_create_planes()
1257 drm_plane_helper_add(&layer->plane, in zynqmp_disp_create_planes()
1260 drm_plane_create_zpos_immutable_property(&layer->plane, i); in zynqmp_disp_create_planes()
1262 drm_plane_create_alpha_property(&layer->plane); in zynqmp_disp_create_planes()
1269 * zynqmp_disp_layer_release_dma - Release DMA channels for a layer
1270 * @disp: Display controller
1280 if (!layer->info) in zynqmp_disp_layer_release_dma()
1283 for (i = 0; i < layer->info->num_channels; i++) { in zynqmp_disp_layer_release_dma()
1284 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; in zynqmp_disp_layer_release_dma()
1286 if (!dma->chan) in zynqmp_disp_layer_release_dma()
1290 dmaengine_terminate_sync(dma->chan); in zynqmp_disp_layer_release_dma()
1291 dma_release_channel(dma->chan); in zynqmp_disp_layer_release_dma()
1296 * zynqmp_disp_destroy_layers - Destroy all layers
1297 * @disp: Display controller
1304 zynqmp_disp_layer_release_dma(disp, &disp->layers[i]); in zynqmp_disp_destroy_layers()
1308 * zynqmp_disp_layer_request_dma - Request DMA channels for a layer
1309 * @disp: Display controller
1323 for (i = 0; i < layer->info->num_channels; i++) { in zynqmp_disp_layer_request_dma()
1324 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; in zynqmp_disp_layer_request_dma()
1328 "%s%u", dma_names[layer->id], i); in zynqmp_disp_layer_request_dma()
1329 dma->chan = dma_request_chan(disp->dev, dma_channel_name); in zynqmp_disp_layer_request_dma()
1330 if (IS_ERR(dma->chan)) { in zynqmp_disp_layer_request_dma()
1331 dev_err(disp->dev, "failed to request dma channel\n"); in zynqmp_disp_layer_request_dma()
1332 ret = PTR_ERR(dma->chan); in zynqmp_disp_layer_request_dma()
1333 dma->chan = NULL; in zynqmp_disp_layer_request_dma()
1342 * zynqmp_disp_create_layers - Create and initialize all layers
1343 * @disp: Display controller
1366 struct zynqmp_disp_layer *layer = &disp->layers[i]; in zynqmp_disp_create_layers()
1368 layer->id = i; in zynqmp_disp_create_layers()
1369 layer->disp = disp; in zynqmp_disp_create_layers()
1370 layer->info = &layer_info[i]; in zynqmp_disp_create_layers()
1384 /* -----------------------------------------------------------------------------
1385 * ZynqMP Display & DRM CRTC
1389 * zynqmp_disp_enable - Enable the display controller
1390 * @disp: Display controller
1396 zynqmp_disp_avbuf_set_clocks_sources(disp, disp->pclk_from_ps, in zynqmp_disp_enable()
1397 disp->audio.clk_from_ps, true); in zynqmp_disp_enable()
1405 * zynqmp_disp_disable - Disable the display controller
1406 * @disp: Display controller
1426 unsigned long mode_clock = adjusted_mode->clock * 1000; in zynqmp_disp_crtc_setup_clock()
1431 ret = clk_set_rate(disp->pclk, mode_clock); in zynqmp_disp_crtc_setup_clock()
1433 dev_err(disp->dev, "failed to set a pixel clock\n"); in zynqmp_disp_crtc_setup_clock()
1437 rate = clk_get_rate(disp->pclk); in zynqmp_disp_crtc_setup_clock()
1438 diff = rate - mode_clock; in zynqmp_disp_crtc_setup_clock()
1440 dev_info(disp->dev, in zynqmp_disp_crtc_setup_clock()
1444 dev_dbg(disp->dev, in zynqmp_disp_crtc_setup_clock()
1456 struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; in zynqmp_disp_crtc_atomic_enable()
1459 pm_runtime_get_sync(disp->dev); in zynqmp_disp_crtc_atomic_enable()
1463 ret = clk_prepare_enable(disp->pclk); in zynqmp_disp_crtc_atomic_enable()
1465 dev_err(disp->dev, "failed to enable a pixel clock\n"); in zynqmp_disp_crtc_atomic_enable()
1466 pm_runtime_put_sync(disp->dev); in zynqmp_disp_crtc_atomic_enable()
1476 vrefresh = (adjusted_mode->clock * 1000) / in zynqmp_disp_crtc_atomic_enable()
1477 (adjusted_mode->vtotal * adjusted_mode->htotal); in zynqmp_disp_crtc_atomic_enable()
1493 old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary); in zynqmp_disp_crtc_atomic_disable()
1495 zynqmp_disp_plane_atomic_disable(crtc->primary, state); in zynqmp_disp_crtc_atomic_disable()
1499 drm_crtc_vblank_off(&disp->crtc); in zynqmp_disp_crtc_atomic_disable()
1501 spin_lock_irq(&crtc->dev->event_lock); in zynqmp_disp_crtc_atomic_disable()
1502 if (crtc->state->event) { in zynqmp_disp_crtc_atomic_disable()
1503 drm_crtc_send_vblank_event(crtc, crtc->state->event); in zynqmp_disp_crtc_atomic_disable()
1504 crtc->state->event = NULL; in zynqmp_disp_crtc_atomic_disable()
1506 spin_unlock_irq(&crtc->dev->event_lock); in zynqmp_disp_crtc_atomic_disable()
1508 clk_disable_unprepare(disp->pclk); in zynqmp_disp_crtc_atomic_disable()
1509 pm_runtime_put_sync(disp->dev); in zynqmp_disp_crtc_atomic_disable()
1529 if (crtc->state->event) { in zynqmp_disp_crtc_atomic_flush()
1533 event = crtc->state->event; in zynqmp_disp_crtc_atomic_flush()
1534 crtc->state->event = NULL; in zynqmp_disp_crtc_atomic_flush()
1536 event->pipe = drm_crtc_index(crtc); in zynqmp_disp_crtc_atomic_flush()
1540 spin_lock_irq(&crtc->dev->event_lock); in zynqmp_disp_crtc_atomic_flush()
1542 spin_unlock_irq(&crtc->dev->event_lock); in zynqmp_disp_crtc_atomic_flush()
1558 zynqmp_dp_enable_vblank(disp->dpsub->dp); in zynqmp_disp_crtc_enable_vblank()
1567 zynqmp_dp_disable_vblank(disp->dpsub->dp); in zynqmp_disp_crtc_disable_vblank()
1583 struct drm_plane *plane = &disp->layers[ZYNQMP_DISP_LAYER_GFX].plane; in zynqmp_disp_create_crtc()
1586 ret = drm_crtc_init_with_planes(disp->drm, &disp->crtc, plane, in zynqmp_disp_create_crtc()
1591 drm_crtc_helper_add(&disp->crtc, &zynqmp_disp_crtc_helper_funcs); in zynqmp_disp_create_crtc()
1594 drm_crtc_vblank_off(&disp->crtc); in zynqmp_disp_create_crtc()
1601 u32 possible_crtcs = drm_crtc_mask(&disp->crtc); in zynqmp_disp_map_crtc_to_plane()
1605 disp->layers[i].plane.possible_crtcs = possible_crtcs; in zynqmp_disp_map_crtc_to_plane()
1608 /* -----------------------------------------------------------------------------
1614 struct zynqmp_disp *disp = dpsub->disp; in zynqmp_disp_drm_init()
1632 struct platform_device *pdev = to_platform_device(dpsub->dev); in zynqmp_disp_probe()
1640 return -ENOMEM; in zynqmp_disp_probe()
1642 disp->dev = &pdev->dev; in zynqmp_disp_probe()
1643 disp->dpsub = dpsub; in zynqmp_disp_probe()
1644 disp->drm = drm; in zynqmp_disp_probe()
1646 dpsub->disp = disp; in zynqmp_disp_probe()
1649 disp->blend.base = devm_ioremap_resource(disp->dev, res); in zynqmp_disp_probe()
1650 if (IS_ERR(disp->blend.base)) in zynqmp_disp_probe()
1651 return PTR_ERR(disp->blend.base); in zynqmp_disp_probe()
1654 disp->avbuf.base = devm_ioremap_resource(disp->dev, res); in zynqmp_disp_probe()
1655 if (IS_ERR(disp->avbuf.base)) in zynqmp_disp_probe()
1656 return PTR_ERR(disp->avbuf.base); in zynqmp_disp_probe()
1659 disp->audio.base = devm_ioremap_resource(disp->dev, res); in zynqmp_disp_probe()
1660 if (IS_ERR(disp->audio.base)) in zynqmp_disp_probe()
1661 return PTR_ERR(disp->audio.base); in zynqmp_disp_probe()
1664 disp->pclk = devm_clk_get(disp->dev, "dp_live_video_in_clk"); in zynqmp_disp_probe()
1665 if (!IS_ERR(disp->pclk)) in zynqmp_disp_probe()
1666 disp->pclk_from_ps = false; in zynqmp_disp_probe()
1667 else if (PTR_ERR(disp->pclk) == -EPROBE_DEFER) in zynqmp_disp_probe()
1668 return PTR_ERR(disp->pclk); in zynqmp_disp_probe()
1671 if (IS_ERR_OR_NULL(disp->pclk)) { in zynqmp_disp_probe()
1672 disp->pclk = devm_clk_get(disp->dev, "dp_vtc_pixel_clk_in"); in zynqmp_disp_probe()
1673 if (IS_ERR(disp->pclk)) { in zynqmp_disp_probe()
1674 dev_err(disp->dev, "failed to init any video clock\n"); in zynqmp_disp_probe()
1675 return PTR_ERR(disp->pclk); in zynqmp_disp_probe()
1677 disp->pclk_from_ps = true; in zynqmp_disp_probe()
1686 layer = &disp->layers[ZYNQMP_DISP_LAYER_VID]; in zynqmp_disp_probe()
1687 dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align; in zynqmp_disp_probe()
1694 struct zynqmp_disp *disp = dpsub->disp; in zynqmp_disp_remove()