Lines Matching +full:dp +full:- +full:phy0

1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2017 - 2020 Xilinx, Inc.
8 * - Hyun Woo Kwon <hyun.kwon@xilinx.com>
9 * - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
19 #include <linux/dma-mapping.h>
33 * --------
35 * The display controller part of ZynqMP DP subsystem, made of the Audio/Video
38 * +------------------------------------------------------------+
39 * +--------+ | +----------------+ +-----------+ |
40 * | DPDMA | --->| | --> | Video | Video +-------------+ |
41 * | 4x vid | | | | | Rendering | -+--> | | | +------+
42 * | 2x aud | | | Audio/Video | --> | Pipeline | | | DisplayPort |---> | PHY0 |
43 * +--------+ | | Buffer Manager | +-----------+ | | Source | | +------+
44 * | | and STC | +-----------+ | | Controller | | +------+
45 * Live Video --->| | --> | Audio | Audio | |---> | PHY1 |
46 * | | | | Mixer | --+-> | | | +------+
47 * Live Audio --->| | --> | | || +-------------+ |
48 * | +----------------+ +-----------+ || |
49 * +---------------------------------------||-------------------+
54 * Only non-live input from the DPDMA and output to the DisplayPort Source
68 * struct zynqmp_disp_format - Display subsystem format information
82 * struct zynqmp_disp_layer_dma - DMA channel for one data plane of a layer
94 * struct zynqmp_disp_layer_info - Static layer information
106 * struct zynqmp_disp_layer - Display layer
128 * struct zynqmp_disp - Display controller
153 /* -----------------------------------------------------------------------------
359 return readl(disp->avbuf.base + reg); in zynqmp_disp_avbuf_read()
364 writel(val, disp->avbuf.base + reg); in zynqmp_disp_avbuf_write()
369 return layer->id == ZYNQMP_DPSUB_LAYER_VID; in zynqmp_disp_layer_is_video()
373 * zynqmp_disp_avbuf_set_format - Set the input format for a layer
391 val |= fmt->buf_fmt; in zynqmp_disp_avbuf_set_format()
399 zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]); in zynqmp_disp_avbuf_set_format()
404 * zynqmp_disp_avbuf_set_clocks_sources - Set the clocks sources
432 * zynqmp_disp_avbuf_enable_channels - Enable buffer channels
460 * zynqmp_disp_avbuf_disable_channels - Disable buffer channels
475 * zynqmp_disp_avbuf_enable_audio - Enable audio
478 * Enable all audio buffers with a non-live (memory) source.
492 * zynqmp_disp_avbuf_disable_audio - Disable audio
509 * zynqmp_disp_avbuf_enable_video - Enable a video layer
523 if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) in zynqmp_disp_avbuf_enable_video()
530 if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) in zynqmp_disp_avbuf_enable_video()
539 * zynqmp_disp_avbuf_disable_video - Disable a video layer
562 * zynqmp_disp_avbuf_enable - Enable the video pipe
565 * De-assert the video pipe reset.
573 * zynqmp_disp_avbuf_disable - Disable the video pipe
584 /* -----------------------------------------------------------------------------
590 writel(val, disp->blend.base + reg); in zynqmp_disp_blend_write()
596 * Hardcode RGB <-> YUV conversion to full-range SDTV for now.
635 * zynqmp_disp_blend_set_output_format - Set the output format of the blender
678 * zynqmp_disp_blend_set_bg_color - Set the background color
697 * zynqmp_disp_blend_set_global_alpha - Configure global alpha blending
711 * zynqmp_disp_blend_layer_set_csc - Configure colorspace conversion for layer
730 if (layer->disp_fmt->swap) { in zynqmp_disp_blend_layer_set_csc()
731 if (layer->drm_fmt->is_yuv) { in zynqmp_disp_blend_layer_set_csc()
763 * zynqmp_disp_blend_layer_enable - Enable a layer
774 val = (layer->drm_fmt->is_yuv ? in zynqmp_disp_blend_layer_enable()
776 (layer->drm_fmt->hsub > 1 ? in zynqmp_disp_blend_layer_enable()
780 ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id), in zynqmp_disp_blend_layer_enable()
783 if (layer->drm_fmt->is_yuv) { in zynqmp_disp_blend_layer_enable()
795 * zynqmp_disp_blend_layer_disable - Disable a layer
803 ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id), in zynqmp_disp_blend_layer_disable()
810 /* -----------------------------------------------------------------------------
816 writel(val, disp->audio.base + reg); in zynqmp_disp_audio_write()
820 * zynqmp_disp_audio_enable - Enable the audio mixer
823 * Enable the audio mixer by de-asserting the soft reset. The audio state is set to
828 /* Clear the audio soft reset register as it's an non-reset flop. */ in zynqmp_disp_audio_enable()
835 * zynqmp_disp_audio_disable - Disable the audio mixer
846 /* -----------------------------------------------------------------------------
851 * zynqmp_disp_layer_find_format - Find format information for a DRM format
867 for (i = 0; i < layer->info->num_formats; i++) { in zynqmp_disp_layer_find_format()
868 if (layer->info->formats[i].drm_fmt == drm_fmt) in zynqmp_disp_layer_find_format()
869 return &layer->info->formats[i]; in zynqmp_disp_layer_find_format()
876 * zynqmp_disp_layer_drm_formats - Return the DRM formats supported by the layer
890 formats = kcalloc(layer->info->num_formats, sizeof(*formats), in zynqmp_disp_layer_drm_formats()
895 for (i = 0; i < layer->info->num_formats; ++i) in zynqmp_disp_layer_drm_formats()
896 formats[i] = layer->info->formats[i].drm_fmt; in zynqmp_disp_layer_drm_formats()
898 *num_formats = layer->info->num_formats; in zynqmp_disp_layer_drm_formats()
903 * zynqmp_disp_layer_enable - Enable a layer
913 layer->mode = mode; in zynqmp_disp_layer_enable()
914 zynqmp_disp_avbuf_enable_video(layer->disp, layer); in zynqmp_disp_layer_enable()
915 zynqmp_disp_blend_layer_enable(layer->disp, layer); in zynqmp_disp_layer_enable()
919 * zynqmp_disp_layer_disable - Disable the layer
929 if (layer->disp->dpsub->dma_enabled) { in zynqmp_disp_layer_disable()
930 for (i = 0; i < layer->drm_fmt->num_planes; i++) in zynqmp_disp_layer_disable()
931 dmaengine_terminate_sync(layer->dmas[i].chan); in zynqmp_disp_layer_disable()
934 zynqmp_disp_avbuf_disable_video(layer->disp, layer); in zynqmp_disp_layer_disable()
935 zynqmp_disp_blend_layer_disable(layer->disp, layer); in zynqmp_disp_layer_disable()
939 * zynqmp_disp_layer_set_format - Set the layer format
950 layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format); in zynqmp_disp_layer_set_format()
951 layer->drm_fmt = info; in zynqmp_disp_layer_set_format()
953 zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt); in zynqmp_disp_layer_set_format()
955 if (!layer->disp->dpsub->dma_enabled) in zynqmp_disp_layer_set_format()
962 for (i = 0; i < info->num_planes; i++) { in zynqmp_disp_layer_set_format()
963 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; in zynqmp_disp_layer_set_format()
973 dmaengine_slave_config(dma->chan, &config); in zynqmp_disp_layer_set_format()
978 * zynqmp_disp_layer_update - Update the layer framebuffer
990 const struct drm_format_info *info = layer->drm_fmt; in zynqmp_disp_layer_update()
993 if (!layer->disp->dpsub->dma_enabled) in zynqmp_disp_layer_update()
996 for (i = 0; i < info->num_planes; i++) { in zynqmp_disp_layer_update()
997 unsigned int width = state->crtc_w / (i ? info->hsub : 1); in zynqmp_disp_layer_update()
998 unsigned int height = state->crtc_h / (i ? info->vsub : 1); in zynqmp_disp_layer_update()
999 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; in zynqmp_disp_layer_update()
1003 dma_addr = drm_fb_dma_get_gem_addr(state->fb, state, i); in zynqmp_disp_layer_update()
1005 dma->xt.numf = height; in zynqmp_disp_layer_update()
1006 dma->sgl.size = width * info->cpp[i]; in zynqmp_disp_layer_update()
1007 dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size; in zynqmp_disp_layer_update()
1008 dma->xt.src_start = dma_addr; in zynqmp_disp_layer_update()
1009 dma->xt.frame_size = 1; in zynqmp_disp_layer_update()
1010 dma->xt.dir = DMA_MEM_TO_DEV; in zynqmp_disp_layer_update()
1011 dma->xt.src_sgl = true; in zynqmp_disp_layer_update()
1012 dma->xt.dst_sgl = false; in zynqmp_disp_layer_update()
1014 desc = dmaengine_prep_interleaved_dma(dma->chan, &dma->xt, in zynqmp_disp_layer_update()
1019 dev_err(layer->disp->dev, in zynqmp_disp_layer_update()
1021 return -ENOMEM; in zynqmp_disp_layer_update()
1025 dma_async_issue_pending(dma->chan); in zynqmp_disp_layer_update()
1032 * zynqmp_disp_layer_release_dma - Release DMA channels for a layer
1043 if (!layer->info || !disp->dpsub->dma_enabled) in zynqmp_disp_layer_release_dma()
1046 for (i = 0; i < layer->info->num_channels; i++) { in zynqmp_disp_layer_release_dma()
1047 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; in zynqmp_disp_layer_release_dma()
1049 if (!dma->chan) in zynqmp_disp_layer_release_dma()
1053 dmaengine_terminate_sync(dma->chan); in zynqmp_disp_layer_release_dma()
1054 dma_release_channel(dma->chan); in zynqmp_disp_layer_release_dma()
1059 * zynqmp_disp_destroy_layers - Destroy all layers
1066 for (i = 0; i < ARRAY_SIZE(disp->layers); i++) in zynqmp_disp_destroy_layers()
1067 zynqmp_disp_layer_release_dma(disp, &disp->layers[i]); in zynqmp_disp_destroy_layers()
1071 * zynqmp_disp_layer_request_dma - Request DMA channels for a layer
1086 if (!disp->dpsub->dma_enabled) in zynqmp_disp_layer_request_dma()
1089 for (i = 0; i < layer->info->num_channels; i++) { in zynqmp_disp_layer_request_dma()
1090 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; in zynqmp_disp_layer_request_dma()
1094 "%s%u", dma_names[layer->id], i); in zynqmp_disp_layer_request_dma()
1095 dma->chan = dma_request_chan(disp->dev, dma_channel_name); in zynqmp_disp_layer_request_dma()
1096 if (IS_ERR(dma->chan)) { in zynqmp_disp_layer_request_dma()
1097 ret = dev_err_probe(disp->dev, PTR_ERR(dma->chan), in zynqmp_disp_layer_request_dma()
1099 dma->chan = NULL; in zynqmp_disp_layer_request_dma()
1108 * zynqmp_disp_create_layers - Create and initialize all layers
1131 for (i = 0; i < ARRAY_SIZE(disp->layers); i++) { in zynqmp_disp_create_layers()
1132 struct zynqmp_disp_layer *layer = &disp->layers[i]; in zynqmp_disp_create_layers()
1134 layer->id = i; in zynqmp_disp_create_layers()
1135 layer->disp = disp; in zynqmp_disp_create_layers()
1136 layer->info = &layer_info[i]; in zynqmp_disp_create_layers()
1142 disp->dpsub->layers[i] = layer; in zynqmp_disp_create_layers()
1152 /* -----------------------------------------------------------------------------
1157 * zynqmp_disp_enable - Enable the display controller
1167 zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps, in zynqmp_disp_enable()
1168 disp->dpsub->aud_clk_from_ps, in zynqmp_disp_enable()
1177 * zynqmp_disp_disable - Disable the display controller
1190 * zynqmp_disp_setup_clock - Configure the display controller pixel clock rate
1203 ret = clk_set_rate(disp->dpsub->vid_clk, mode_clock); in zynqmp_disp_setup_clock()
1205 dev_err(disp->dev, "failed to set the video clock\n"); in zynqmp_disp_setup_clock()
1209 rate = clk_get_rate(disp->dpsub->vid_clk); in zynqmp_disp_setup_clock()
1210 diff = rate - mode_clock; in zynqmp_disp_setup_clock()
1212 dev_info(disp->dev, in zynqmp_disp_setup_clock()
1216 dev_dbg(disp->dev, in zynqmp_disp_setup_clock()
1223 /* -----------------------------------------------------------------------------
1229 struct platform_device *pdev = to_platform_device(dpsub->dev); in zynqmp_disp_probe()
1235 return -ENOMEM; in zynqmp_disp_probe()
1237 disp->dev = &pdev->dev; in zynqmp_disp_probe()
1238 disp->dpsub = dpsub; in zynqmp_disp_probe()
1240 disp->blend.base = devm_platform_ioremap_resource_byname(pdev, "blend"); in zynqmp_disp_probe()
1241 if (IS_ERR(disp->blend.base)) { in zynqmp_disp_probe()
1242 ret = PTR_ERR(disp->blend.base); in zynqmp_disp_probe()
1246 disp->avbuf.base = devm_platform_ioremap_resource_byname(pdev, "av_buf"); in zynqmp_disp_probe()
1247 if (IS_ERR(disp->avbuf.base)) { in zynqmp_disp_probe()
1248 ret = PTR_ERR(disp->avbuf.base); in zynqmp_disp_probe()
1252 disp->audio.base = devm_platform_ioremap_resource_byname(pdev, "aud"); in zynqmp_disp_probe()
1253 if (IS_ERR(disp->audio.base)) { in zynqmp_disp_probe()
1254 ret = PTR_ERR(disp->audio.base); in zynqmp_disp_probe()
1262 if (disp->dpsub->dma_enabled) { in zynqmp_disp_probe()
1265 layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID]; in zynqmp_disp_probe()
1266 dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align; in zynqmp_disp_probe()
1269 dpsub->disp = disp; in zynqmp_disp_probe()
1280 struct zynqmp_disp *disp = dpsub->disp; in zynqmp_disp_remove()