1453 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * ZynqMP Display Controller Driver4 *5 * Copyright (C) 2017 - 2020 Xilinx, Inc.6 *7 * Authors:8 * - Hyun Woo Kwon <hyun.kwon@xilinx.com>9 * - Laurent Pinchart <laurent.pinchart@ideasonboard.com>10 */11 12#include <drm/drm_fb_dma_helper.h>13#include <drm/drm_fourcc.h>14#include <drm/drm_framebuffer.h>15#include <drm/drm_plane.h>16 17#include <linux/clk.h>18#include <linux/dma/xilinx_dpdma.h>19#include <linux/dma-mapping.h>20#include <linux/dmaengine.h>21#include <linux/media-bus-format.h>22#include <linux/module.h>23#include <linux/of.h>24#include <linux/platform_device.h>25#include <linux/slab.h>26 27#include "zynqmp_disp.h"28#include "zynqmp_disp_regs.h"29#include "zynqmp_dp.h"30#include "zynqmp_dpsub.h"31 32/*33 * Overview34 * --------35 *36 * The display controller part of ZynqMP DP subsystem, made of the Audio/Video37 * Buffer Manager, the Video Rendering Pipeline (blender) and the Audio Mixer.38 *39 * +------------------------------------------------------------+40 * +--------+ | +----------------+ +-----------+ |41 * | DPDMA | --->| | --> | Video | Video +-------------+ |42 * | 4x vid | | | | | Rendering | -+--> | | | +------+43 * | 2x aud | | | Audio/Video | --> | Pipeline | | | DisplayPort |---> | PHY0 |44 * +--------+ | | Buffer Manager | +-----------+ | | Source | | +------+45 * | | and STC | +-----------+ | | Controller | | +------+46 * Live Video --->| | --> | Audio | Audio | |---> | PHY1 |47 * | | | | Mixer | --+-> | | | +------+48 * Live Audio --->| | --> | | || +-------------+ |49 * | +----------------+ +-----------+ || |50 * +---------------------------------------||-------------------+51 * vv52 * Blended Video and53 * Mixed Audio to PL54 *55 * Only non-live input from the DPDMA and output to the DisplayPort Source56 * Controller are currently supported. Interface with the programmable logic57 * for live streams is not implemented.58 *59 * The display controller code creates planes for the DPDMA video and graphics60 * layers, and a CRTC for the Video Rendering Pipeline.61 */62 63#define ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS 464#define ZYNQMP_DISP_AV_BUF_NUM_BUFFERS 665 66#define ZYNQMP_DISP_MAX_NUM_SUB_PLANES 367 68/**69 * enum zynqmp_dpsub_layer_mode - Layer mode70 * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode71 * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode72 */73enum zynqmp_dpsub_layer_mode {74 ZYNQMP_DPSUB_LAYER_NONLIVE,75 ZYNQMP_DPSUB_LAYER_LIVE,76};77 78/**79 * struct zynqmp_disp_format - Display subsystem format information80 * @drm_fmt: DRM format (4CC)81 * @bus_fmt: Media bus format82 * @buf_fmt: AV buffer format83 * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats84 * @sf: Scaling factors for color components85 */86struct zynqmp_disp_format {87 u32 drm_fmt;88 u32 bus_fmt;89 u32 buf_fmt;90 bool swap;91 const u32 *sf;92};93 94/**95 * struct zynqmp_disp_layer_dma - DMA channel for one data plane of a layer96 * @chan: DMA channel97 * @xt: Interleaved DMA descriptor template98 * @sgl: Data chunk for dma_interleaved_template99 */100struct zynqmp_disp_layer_dma {101 struct dma_chan *chan;102 struct dma_interleaved_template xt;103 struct data_chunk sgl;104};105 106/**107 * struct zynqmp_disp_layer_info - Static layer information108 * @formats: Array of supported formats109 * @num_formats: Number of formats in @formats array110 * @num_channels: Number of DMA channels111 */112struct zynqmp_disp_layer_info {113 const struct zynqmp_disp_format *formats;114 unsigned int num_formats;115 unsigned int num_channels;116};117 118/**119 * struct zynqmp_disp_layer - Display layer120 * @id: Layer ID121 * @disp: Back pointer to struct zynqmp_disp122 * @info: Static layer information123 * @dmas: DMA channels124 * @disp_fmt: Current format information125 * @drm_fmt: Current DRM format information126 * @mode: Current operation mode127 */128struct zynqmp_disp_layer {129 enum zynqmp_dpsub_layer_id id;130 struct zynqmp_disp *disp;131 const struct zynqmp_disp_layer_info *info;132 133 struct zynqmp_disp_layer_dma dmas[ZYNQMP_DISP_MAX_NUM_SUB_PLANES];134 135 const struct zynqmp_disp_format *disp_fmt;136 const struct drm_format_info *drm_fmt;137 enum zynqmp_dpsub_layer_mode mode;138};139 140/**141 * struct zynqmp_disp - Display controller142 * @dev: Device structure143 * @dpsub: Display subsystem144 * @blend: Register I/O base address for the blender145 * @avbuf: Register I/O base address for the audio/video buffer manager146 * @audio: Registers I/O base address for the audio mixer147 * @layers: Layers (planes)148 */149struct zynqmp_disp {150 struct device *dev;151 struct zynqmp_dpsub *dpsub;152 153 void __iomem *blend;154 void __iomem *avbuf;155 void __iomem *audio;156 157 struct zynqmp_disp_layer layers[ZYNQMP_DPSUB_NUM_LAYERS];158};159 160/* -----------------------------------------------------------------------------161 * Audio/Video Buffer Manager162 */163 164static const u32 scaling_factors_444[] = {165 ZYNQMP_DISP_AV_BUF_4BIT_SF,166 ZYNQMP_DISP_AV_BUF_4BIT_SF,167 ZYNQMP_DISP_AV_BUF_4BIT_SF,168};169 170static const u32 scaling_factors_555[] = {171 ZYNQMP_DISP_AV_BUF_5BIT_SF,172 ZYNQMP_DISP_AV_BUF_5BIT_SF,173 ZYNQMP_DISP_AV_BUF_5BIT_SF,174};175 176static const u32 scaling_factors_565[] = {177 ZYNQMP_DISP_AV_BUF_5BIT_SF,178 ZYNQMP_DISP_AV_BUF_6BIT_SF,179 ZYNQMP_DISP_AV_BUF_5BIT_SF,180};181 182static const u32 scaling_factors_666[] = {183 ZYNQMP_DISP_AV_BUF_6BIT_SF,184 ZYNQMP_DISP_AV_BUF_6BIT_SF,185 ZYNQMP_DISP_AV_BUF_6BIT_SF,186};187 188static const u32 scaling_factors_888[] = {189 ZYNQMP_DISP_AV_BUF_8BIT_SF,190 ZYNQMP_DISP_AV_BUF_8BIT_SF,191 ZYNQMP_DISP_AV_BUF_8BIT_SF,192};193 194static const u32 scaling_factors_101010[] = {195 ZYNQMP_DISP_AV_BUF_10BIT_SF,196 ZYNQMP_DISP_AV_BUF_10BIT_SF,197 ZYNQMP_DISP_AV_BUF_10BIT_SF,198};199 200/* List of video layer formats */201static const struct zynqmp_disp_format avbuf_vid_fmts[] = {202 {203 .drm_fmt = DRM_FORMAT_VYUY,204 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY,205 .swap = true,206 .sf = scaling_factors_888,207 }, {208 .drm_fmt = DRM_FORMAT_UYVY,209 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY,210 .swap = false,211 .sf = scaling_factors_888,212 }, {213 .drm_fmt = DRM_FORMAT_YUYV,214 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV,215 .swap = false,216 .sf = scaling_factors_888,217 }, {218 .drm_fmt = DRM_FORMAT_YVYU,219 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV,220 .swap = true,221 .sf = scaling_factors_888,222 }, {223 .drm_fmt = DRM_FORMAT_YUV422,224 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16,225 .swap = false,226 .sf = scaling_factors_888,227 }, {228 .drm_fmt = DRM_FORMAT_YVU422,229 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16,230 .swap = true,231 .sf = scaling_factors_888,232 }, {233 .drm_fmt = DRM_FORMAT_YUV444,234 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24,235 .swap = false,236 .sf = scaling_factors_888,237 }, {238 .drm_fmt = DRM_FORMAT_YVU444,239 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24,240 .swap = true,241 .sf = scaling_factors_888,242 }, {243 .drm_fmt = DRM_FORMAT_NV16,244 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI,245 .swap = false,246 .sf = scaling_factors_888,247 }, {248 .drm_fmt = DRM_FORMAT_NV61,249 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI,250 .swap = true,251 .sf = scaling_factors_888,252 }, {253 .drm_fmt = DRM_FORMAT_BGR888,254 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888,255 .swap = false,256 .sf = scaling_factors_888,257 }, {258 .drm_fmt = DRM_FORMAT_RGB888,259 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888,260 .swap = true,261 .sf = scaling_factors_888,262 }, {263 .drm_fmt = DRM_FORMAT_XBGR8888,264 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880,265 .swap = false,266 .sf = scaling_factors_888,267 }, {268 .drm_fmt = DRM_FORMAT_XRGB8888,269 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880,270 .swap = true,271 .sf = scaling_factors_888,272 }, {273 .drm_fmt = DRM_FORMAT_XBGR2101010,274 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10,275 .swap = false,276 .sf = scaling_factors_101010,277 }, {278 .drm_fmt = DRM_FORMAT_XRGB2101010,279 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10,280 .swap = true,281 .sf = scaling_factors_101010,282 }, {283 .drm_fmt = DRM_FORMAT_YUV420,284 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420,285 .swap = false,286 .sf = scaling_factors_888,287 }, {288 .drm_fmt = DRM_FORMAT_YVU420,289 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420,290 .swap = true,291 .sf = scaling_factors_888,292 }, {293 .drm_fmt = DRM_FORMAT_NV12,294 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420,295 .swap = false,296 .sf = scaling_factors_888,297 }, {298 .drm_fmt = DRM_FORMAT_NV21,299 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420,300 .swap = true,301 .sf = scaling_factors_888,302 },303};304 305/* List of graphics layer formats */306static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {307 {308 .drm_fmt = DRM_FORMAT_ABGR8888,309 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888,310 .swap = false,311 .sf = scaling_factors_888,312 }, {313 .drm_fmt = DRM_FORMAT_ARGB8888,314 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888,315 .swap = true,316 .sf = scaling_factors_888,317 }, {318 .drm_fmt = DRM_FORMAT_RGBA8888,319 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888,320 .swap = false,321 .sf = scaling_factors_888,322 }, {323 .drm_fmt = DRM_FORMAT_BGRA8888,324 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888,325 .swap = true,326 .sf = scaling_factors_888,327 }, {328 .drm_fmt = DRM_FORMAT_BGR888,329 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB888,330 .swap = false,331 .sf = scaling_factors_888,332 }, {333 .drm_fmt = DRM_FORMAT_RGB888,334 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_BGR888,335 .swap = false,336 .sf = scaling_factors_888,337 }, {338 .drm_fmt = DRM_FORMAT_RGBA5551,339 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551,340 .swap = false,341 .sf = scaling_factors_555,342 }, {343 .drm_fmt = DRM_FORMAT_BGRA5551,344 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551,345 .swap = true,346 .sf = scaling_factors_555,347 }, {348 .drm_fmt = DRM_FORMAT_RGBA4444,349 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444,350 .swap = false,351 .sf = scaling_factors_444,352 }, {353 .drm_fmt = DRM_FORMAT_BGRA4444,354 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444,355 .swap = true,356 .sf = scaling_factors_444,357 }, {358 .drm_fmt = DRM_FORMAT_RGB565,359 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565,360 .swap = false,361 .sf = scaling_factors_565,362 }, {363 .drm_fmt = DRM_FORMAT_BGR565,364 .buf_fmt = ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565,365 .swap = true,366 .sf = scaling_factors_565,367 },368};369 370/* List of live video layer formats */371static const struct zynqmp_disp_format avbuf_live_fmts[] = {372 {373 .drm_fmt = DRM_FORMAT_RGB565,374 .bus_fmt = MEDIA_BUS_FMT_RGB666_1X18,375 .buf_fmt = ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_6 |376 ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,377 .sf = scaling_factors_666,378 }, {379 .drm_fmt = DRM_FORMAT_RGB888,380 .bus_fmt = MEDIA_BUS_FMT_RGB888_1X24,381 .buf_fmt = ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |382 ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,383 .sf = scaling_factors_888,384 }, {385 .drm_fmt = DRM_FORMAT_YUV422,386 .bus_fmt = MEDIA_BUS_FMT_UYVY8_1X16,387 .buf_fmt = ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |388 ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,389 .sf = scaling_factors_888,390 }, {391 .drm_fmt = DRM_FORMAT_YUV444,392 .bus_fmt = MEDIA_BUS_FMT_VUY8_1X24,393 .buf_fmt = ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |394 ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444,395 .sf = scaling_factors_888,396 }, {397 .drm_fmt = DRM_FORMAT_P210,398 .bus_fmt = MEDIA_BUS_FMT_UYVY10_1X20,399 .buf_fmt = ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10 |400 ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,401 .sf = scaling_factors_101010,402 },403};404 405static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)406{407 return readl(disp->avbuf + reg);408}409 410static void zynqmp_disp_avbuf_write(struct zynqmp_disp *disp, int reg, u32 val)411{412 writel(val, disp->avbuf + reg);413}414 415static bool zynqmp_disp_layer_is_video(const struct zynqmp_disp_layer *layer)416{417 return layer->id == ZYNQMP_DPSUB_LAYER_VID;418}419 420/**421 * zynqmp_disp_avbuf_set_format - Set the input format for a layer422 * @disp: Display controller423 * @layer: The layer424 * @fmt: The format information425 *426 * Set the video buffer manager format for @layer to @fmt.427 */428static void zynqmp_disp_avbuf_set_format(struct zynqmp_disp *disp,429 struct zynqmp_disp_layer *layer,430 const struct zynqmp_disp_format *fmt)431{432 unsigned int i;433 u32 val, reg;434 435 layer->disp_fmt = fmt;436 if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {437 reg = ZYNQMP_DISP_AV_BUF_FMT;438 val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);439 val &= zynqmp_disp_layer_is_video(layer)440 ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK441 : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;442 val |= fmt->buf_fmt;443 zynqmp_disp_avbuf_write(disp, reg, val);444 } else {445 reg = zynqmp_disp_layer_is_video(layer)446 ? ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG447 : ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG;448 val = fmt->buf_fmt;449 zynqmp_disp_avbuf_write(disp, reg, val);450 }451 452 for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; i++) {453 reg = zynqmp_disp_layer_is_video(layer)454 ? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)455 : ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);456 457 zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);458 }459}460 461/**462 * zynqmp_disp_avbuf_set_clocks_sources - Set the clocks sources463 * @disp: Display controller464 * @video_from_ps: True if the video clock originates from the PS465 * @audio_from_ps: True if the audio clock originates from the PS466 * @timings_internal: True if video timings are generated internally467 *468 * Set the source for the video and audio clocks, as well as for the video469 * timings. Clocks can originate from the PS or PL, and timings can be470 * generated internally or externally.471 */472static void473zynqmp_disp_avbuf_set_clocks_sources(struct zynqmp_disp *disp,474 bool video_from_ps, bool audio_from_ps,475 bool timings_internal)476{477 u32 val = 0;478 479 if (video_from_ps)480 val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_FROM_PS;481 if (audio_from_ps)482 val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_AUD_FROM_PS;483 if (timings_internal)484 val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING;485 486 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CLK_SRC, val);487}488 489/**490 * zynqmp_disp_avbuf_enable_channels - Enable buffer channels491 * @disp: Display controller492 *493 * Enable all (video and audio) buffer channels.494 */495static void zynqmp_disp_avbuf_enable_channels(struct zynqmp_disp *disp)496{497 unsigned int i;498 u32 val;499 500 val = ZYNQMP_DISP_AV_BUF_CHBUF_EN |501 (ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_MAX <<502 ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT);503 504 for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS; i++)505 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),506 val);507 508 val = ZYNQMP_DISP_AV_BUF_CHBUF_EN |509 (ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_AUD_MAX <<510 ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT);511 512 for (; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++)513 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),514 val);515}516 517/**518 * zynqmp_disp_avbuf_disable_channels - Disable buffer channels519 * @disp: Display controller520 *521 * Disable all (video and audio) buffer channels.522 */523static void zynqmp_disp_avbuf_disable_channels(struct zynqmp_disp *disp)524{525 unsigned int i;526 527 for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++)528 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),529 ZYNQMP_DISP_AV_BUF_CHBUF_FLUSH);530}531 532/**533 * zynqmp_disp_avbuf_enable_audio - Enable audio534 * @disp: Display controller535 *536 * Enable all audio buffers with a non-live (memory) source.537 */538static void zynqmp_disp_avbuf_enable_audio(struct zynqmp_disp *disp)539{540 u32 val;541 542 val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);543 val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK;544 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MEM;545 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN;546 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);547}548 549/**550 * zynqmp_disp_avbuf_disable_audio - Disable audio551 * @disp: Display controller552 *553 * Disable all audio buffers.554 */555static void zynqmp_disp_avbuf_disable_audio(struct zynqmp_disp *disp)556{557 u32 val;558 559 val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);560 val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK;561 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_DISABLE;562 val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN;563 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);564}565 566/**567 * zynqmp_disp_avbuf_enable_video - Enable a video layer568 * @disp: Display controller569 * @layer: The layer570 *571 * Enable the video/graphics buffer for @layer.572 */573static void zynqmp_disp_avbuf_enable_video(struct zynqmp_disp *disp,574 struct zynqmp_disp_layer *layer)575{576 u32 val;577 578 val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);579 if (zynqmp_disp_layer_is_video(layer)) {580 val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK;581 if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE)582 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MEM;583 else584 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_LIVE;585 } else {586 val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK;587 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM;588 if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE)589 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM;590 else591 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_LIVE;592 }593 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);594}595 596/**597 * zynqmp_disp_avbuf_disable_video - Disable a video layer598 * @disp: Display controller599 * @layer: The layer600 *601 * Disable the video/graphics buffer for @layer.602 */603static void zynqmp_disp_avbuf_disable_video(struct zynqmp_disp *disp,604 struct zynqmp_disp_layer *layer)605{606 u32 val;607 608 val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);609 if (zynqmp_disp_layer_is_video(layer)) {610 val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK;611 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_NONE;612 } else {613 val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK;614 val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_DISABLE;615 }616 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);617}618 619/**620 * zynqmp_disp_avbuf_enable - Enable the video pipe621 * @disp: Display controller622 *623 * De-assert the video pipe reset.624 */625static void zynqmp_disp_avbuf_enable(struct zynqmp_disp *disp)626{627 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG, 0);628}629 630/**631 * zynqmp_disp_avbuf_disable - Disable the video pipe632 * @disp: Display controller633 *634 * Assert the video pipe reset.635 */636static void zynqmp_disp_avbuf_disable(struct zynqmp_disp *disp)637{638 zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG,639 ZYNQMP_DISP_AV_BUF_SRST_REG_VID_RST);640}641 642/* -----------------------------------------------------------------------------643 * Blender (Video Pipeline)644 */645 646static void zynqmp_disp_blend_write(struct zynqmp_disp *disp, int reg, u32 val)647{648 writel(val, disp->blend + reg);649}650 651/*652 * Colorspace conversion matrices.653 *654 * Hardcode RGB <-> YUV conversion to full-range SDTV for now.655 */656static const u16 csc_zero_matrix[] = {657 0x0, 0x0, 0x0,658 0x0, 0x0, 0x0,659 0x0, 0x0, 0x0660};661 662static const u16 csc_identity_matrix[] = {663 0x1000, 0x0, 0x0,664 0x0, 0x1000, 0x0,665 0x0, 0x0, 0x1000666};667 668static const u32 csc_zero_offsets[] = {669 0, 0, 0670};671 672static const u16 csc_rgb_to_sdtv_matrix[] = {673 0x4c9, 0x864, 0x1d3,674 0x7d4d, 0x7ab3, 0x800,675 0x800, 0x794d, 0x7eb3676};677 678static const u32 csc_rgb_to_sdtv_offsets[] = {679 0x0, 0x8000000, 0x8000000680};681 682static const u16 csc_sdtv_to_rgb_matrix[] = {683 0x1000, 0x166f, 0x0,684 0x1000, 0x7483, 0x7a7f,685 0x1000, 0x0, 0x1c5a686};687 688static const u32 csc_sdtv_to_rgb_offsets[] = {689 0x0, 0x1800, 0x1800690};691 692/**693 * zynqmp_disp_blend_set_output_format - Set the output format of the blender694 * @disp: Display controller695 * @format: Output format696 *697 * Set the output format of the blender to @format.698 */699static void zynqmp_disp_blend_set_output_format(struct zynqmp_disp *disp,700 enum zynqmp_dpsub_format format)701{702 static const unsigned int blend_output_fmts[] = {703 [ZYNQMP_DPSUB_FORMAT_RGB] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB,704 [ZYNQMP_DPSUB_FORMAT_YCRCB444] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR444,705 [ZYNQMP_DPSUB_FORMAT_YCRCB422] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR422706 | ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_EN_DOWNSAMPLE,707 [ZYNQMP_DPSUB_FORMAT_YONLY] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YONLY,708 };709 710 u32 fmt = blend_output_fmts[format];711 const u16 *coeffs;712 const u32 *offsets;713 unsigned int i;714 715 zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT, fmt);716 if (fmt == ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB) {717 coeffs = csc_identity_matrix;718 offsets = csc_zero_offsets;719 } else {720 coeffs = csc_rgb_to_sdtv_matrix;721 offsets = csc_rgb_to_sdtv_offsets;722 }723 724 for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i++)725 zynqmp_disp_blend_write(disp,726 ZYNQMP_DISP_V_BLEND_RGB2YCBCR_COEFF(i),727 coeffs[i]);728 729 for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++)730 zynqmp_disp_blend_write(disp,731 ZYNQMP_DISP_V_BLEND_OUTCSC_OFFSET(i),732 offsets[i]);733}734 735/**736 * zynqmp_disp_blend_set_bg_color - Set the background color737 * @disp: Display controller738 * @rcr: Red/Cr color component739 * @gy: Green/Y color component740 * @bcb: Blue/Cb color component741 *742 * Set the background color to (@rcr, @gy, @bcb), corresponding to the R, G and743 * B or Cr, Y and Cb components respectively depending on the selected output744 * format.745 */746static void zynqmp_disp_blend_set_bg_color(struct zynqmp_disp *disp,747 u32 rcr, u32 gy, u32 bcb)748{749 zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_0, rcr);750 zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_1, gy);751 zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_2, bcb);752}753 754/**755 * zynqmp_disp_blend_set_global_alpha - Configure global alpha blending756 * @disp: Display controller757 * @enable: True to enable global alpha blending758 * @alpha: Global alpha value (ignored if @enabled is false)759 */760void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp,761 bool enable, u32 alpha)762{763 zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA,764 ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_VALUE(alpha) |765 (enable ? ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_EN : 0));766}767 768/**769 * zynqmp_disp_blend_layer_set_csc - Configure colorspace conversion for layer770 * @disp: Display controller771 * @layer: The layer772 * @coeffs: Colorspace conversion matrix773 * @offsets: Colorspace conversion offsets774 *775 * Configure the input colorspace conversion matrix and offsets for the @layer.776 * Columns of the matrix are automatically swapped based on the input format to777 * handle RGB and YCrCb components permutations.778 */779static void zynqmp_disp_blend_layer_set_csc(struct zynqmp_disp *disp,780 struct zynqmp_disp_layer *layer,781 const u16 *coeffs,782 const u32 *offsets)783{784 unsigned int swap[3] = { 0, 1, 2 };785 unsigned int reg;786 unsigned int i;787 788 if (layer->disp_fmt->swap) {789 if (layer->drm_fmt->is_yuv) {790 /* Swap U and V. */791 swap[1] = 2;792 swap[2] = 1;793 } else {794 /* Swap R and B. */795 swap[0] = 2;796 swap[2] = 0;797 }798 }799 800 if (zynqmp_disp_layer_is_video(layer))801 reg = ZYNQMP_DISP_V_BLEND_IN1CSC_COEFF(0);802 else803 reg = ZYNQMP_DISP_V_BLEND_IN2CSC_COEFF(0);804 805 for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i += 3, reg += 12) {806 zynqmp_disp_blend_write(disp, reg + 0, coeffs[i + swap[0]]);807 zynqmp_disp_blend_write(disp, reg + 4, coeffs[i + swap[1]]);808 zynqmp_disp_blend_write(disp, reg + 8, coeffs[i + swap[2]]);809 }810 811 if (zynqmp_disp_layer_is_video(layer))812 reg = ZYNQMP_DISP_V_BLEND_IN1CSC_OFFSET(0);813 else814 reg = ZYNQMP_DISP_V_BLEND_IN2CSC_OFFSET(0);815 816 for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++)817 zynqmp_disp_blend_write(disp, reg + i * 4, offsets[i]);818}819 820/**821 * zynqmp_disp_blend_layer_enable - Enable a layer822 * @disp: Display controller823 * @layer: The layer824 */825static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp *disp,826 struct zynqmp_disp_layer *layer)827{828 const u16 *coeffs;829 const u32 *offsets;830 u32 val;831 832 val = (layer->drm_fmt->is_yuv ?833 0 : ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_RGB) |834 (layer->drm_fmt->hsub > 1 ?835 ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_EN_US : 0);836 837 zynqmp_disp_blend_write(disp,838 ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),839 val);840 841 if (layer->drm_fmt->is_yuv) {842 coeffs = csc_sdtv_to_rgb_matrix;843 offsets = csc_sdtv_to_rgb_offsets;844 } else {845 coeffs = csc_identity_matrix;846 offsets = csc_zero_offsets;847 }848 849 zynqmp_disp_blend_layer_set_csc(disp, layer, coeffs, offsets);850}851 852/**853 * zynqmp_disp_blend_layer_disable - Disable a layer854 * @disp: Display controller855 * @layer: The layer856 */857static void zynqmp_disp_blend_layer_disable(struct zynqmp_disp *disp,858 struct zynqmp_disp_layer *layer)859{860 zynqmp_disp_blend_write(disp,861 ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),862 0);863 864 zynqmp_disp_blend_layer_set_csc(disp, layer, csc_zero_matrix,865 csc_zero_offsets);866}867 868/* -----------------------------------------------------------------------------869 * Audio Mixer870 */871 872static void zynqmp_disp_audio_write(struct zynqmp_disp *disp, int reg, u32 val)873{874 writel(val, disp->audio + reg);875}876 877/**878 * zynqmp_disp_audio_enable - Enable the audio mixer879 * @disp: Display controller880 *881 * Enable the audio mixer by de-asserting the soft reset. The audio state is set to882 * default values by the reset, set the default mixer volume explicitly.883 */884static void zynqmp_disp_audio_enable(struct zynqmp_disp *disp)885{886 /* Clear the audio soft reset register as it's an non-reset flop. */887 zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET, 0);888 zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_MIXER_VOLUME,889 ZYNQMP_DISP_AUD_MIXER_VOLUME_NO_SCALE);890}891 892/**893 * zynqmp_disp_audio_disable - Disable the audio mixer894 * @disp: Display controller895 *896 * Disable the audio mixer by asserting its soft reset.897 */898static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp)899{900 zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET,901 ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST);902}903 904/* -----------------------------------------------------------------------------905 * ZynqMP Display Layer & DRM Plane906 */907 908/**909 * zynqmp_disp_layer_find_format - Find format information for a DRM format910 * @layer: The layer911 * @drm_fmt: DRM format to search912 *913 * Search display subsystem format information corresponding to the given DRM914 * format @drm_fmt for the @layer, and return a pointer to the format915 * descriptor.916 *917 * Return: A pointer to the format descriptor if found, NULL otherwise918 */919static const struct zynqmp_disp_format *920zynqmp_disp_layer_find_format(struct zynqmp_disp_layer *layer,921 u32 drm_fmt)922{923 unsigned int i;924 925 for (i = 0; i < layer->info->num_formats; i++) {926 if (layer->info->formats[i].drm_fmt == drm_fmt)927 return &layer->info->formats[i];928 }929 930 return NULL;931}932 933/**934 * zynqmp_disp_layer_find_live_format - Find format information for given935 * media bus format936 * @layer: The layer937 * @media_bus_format: Media bus format to search938 *939 * Search display subsystem format information corresponding to the given media940 * bus format @media_bus_format for the @layer, and return a pointer to the941 * format descriptor.942 *943 * Return: A pointer to the format descriptor if found, NULL otherwise944 */945static const struct zynqmp_disp_format *946zynqmp_disp_layer_find_live_format(struct zynqmp_disp_layer *layer,947 u32 media_bus_format)948{949 unsigned int i;950 951 for (i = 0; i < layer->info->num_formats; i++)952 if (layer->info->formats[i].bus_fmt == media_bus_format)953 return &layer->info->formats[i];954 955 return NULL;956}957 958/**959 * zynqmp_disp_layer_drm_formats - Return the DRM formats supported by the layer960 * @layer: The layer961 * @num_formats: Pointer to the returned number of formats962 *963 * NOTE: This function doesn't make sense for live video layers and will964 * always return an empty list in such cases. zynqmp_disp_live_layer_formats()965 * should be used to query a list of media bus formats supported by the live966 * video input layer.967 *968 * Return: A newly allocated u32 array that stores all the DRM formats969 * supported by the layer. The number of formats in the array is returned970 * through the num_formats argument.971 */972u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,973 unsigned int *num_formats)974{975 unsigned int i;976 u32 *formats;977 978 if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_NONLIVE)) {979 *num_formats = 0;980 return NULL;981 }982 983 formats = kcalloc(layer->info->num_formats, sizeof(*formats),984 GFP_KERNEL);985 if (!formats) {986 *num_formats = 0;987 return NULL;988 }989 990 for (i = 0; i < layer->info->num_formats; ++i)991 formats[i] = layer->info->formats[i].drm_fmt;992 993 *num_formats = layer->info->num_formats;994 return formats;995}996 997/**998 * zynqmp_disp_live_layer_formats - Return the media bus formats supported by999 * the live video layer1000 * @layer: The layer1001 * @num_formats: Pointer to the returned number of formats1002 *1003 * NOTE: This function should be used only for live video input layers.1004 *1005 * Return: A newly allocated u32 array of media bus formats supported by the1006 * layer. The number of formats in the array is returned through the1007 * @num_formats argument.1008 */1009u32 *zynqmp_disp_live_layer_formats(struct zynqmp_disp_layer *layer,1010 unsigned int *num_formats)1011{1012 unsigned int i;1013 u32 *formats;1014 1015 if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_LIVE)) {1016 *num_formats = 0;1017 return NULL;1018 }1019 1020 formats = kcalloc(layer->info->num_formats, sizeof(*formats),1021 GFP_KERNEL);1022 if (!formats) {1023 *num_formats = 0;1024 return NULL;1025 }1026 1027 for (i = 0; i < layer->info->num_formats; ++i)1028 formats[i] = layer->info->formats[i].bus_fmt;1029 1030 *num_formats = layer->info->num_formats;1031 return formats;1032}1033 1034/**1035 * zynqmp_disp_layer_enable - Enable a layer1036 * @layer: The layer1037 *1038 * Enable the @layer in the audio/video buffer manager and the blender. DMA1039 * channels are started separately by zynqmp_disp_layer_update().1040 */1041void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)1042{1043 zynqmp_disp_avbuf_enable_video(layer->disp, layer);1044 zynqmp_disp_blend_layer_enable(layer->disp, layer);1045}1046 1047/**1048 * zynqmp_disp_layer_disable - Disable the layer1049 * @layer: The layer1050 *1051 * Disable the layer by stopping its DMA channels and disabling it in the1052 * audio/video buffer manager and the blender.1053 */1054void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer)1055{1056 unsigned int i;1057 1058 if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {1059 for (i = 0; i < layer->drm_fmt->num_planes; i++)1060 dmaengine_terminate_sync(layer->dmas[i].chan);1061 }1062 1063 zynqmp_disp_avbuf_disable_video(layer->disp, layer);1064 zynqmp_disp_blend_layer_disable(layer->disp, layer);1065}1066 1067/**1068 * zynqmp_disp_layer_set_format - Set the layer format1069 * @layer: The layer1070 * @info: The format info1071 *1072 * NOTE: Use zynqmp_disp_layer_set_live_format() to set media bus format for1073 * live video layers.1074 *1075 * Set the format for @layer to @info. The layer must be disabled.1076 */1077void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,1078 const struct drm_format_info *info)1079{1080 unsigned int i;1081 1082 if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_NONLIVE))1083 return;1084 1085 layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format);1086 if (WARN_ON(!layer->disp_fmt))1087 return;1088 layer->drm_fmt = info;1089 1090 zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);1091 1092 /*1093 * Set pconfig for each DMA channel to indicate they're part of a1094 * video group.1095 */1096 for (i = 0; i < info->num_planes; i++) {1097 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];1098 struct xilinx_dpdma_peripheral_config pconfig = {1099 .video_group = true,1100 };1101 struct dma_slave_config config = {1102 .direction = DMA_MEM_TO_DEV,1103 .peripheral_config = &pconfig,1104 .peripheral_size = sizeof(pconfig),1105 };1106 1107 dmaengine_slave_config(dma->chan, &config);1108 }1109}1110 1111/**1112 * zynqmp_disp_layer_set_live_format - Set the live video layer format1113 * @layer: The layer1114 * @media_bus_format: Media bus format to set1115 *1116 * NOTE: This function should not be used to set format for non-live video1117 * layer. Use zynqmp_disp_layer_set_format() instead.1118 *1119 * Set the display format for the live @layer. The layer must be disabled.1120 */1121void zynqmp_disp_layer_set_live_format(struct zynqmp_disp_layer *layer,1122 u32 media_bus_format)1123{1124 if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_LIVE))1125 return;1126 1127 layer->disp_fmt = zynqmp_disp_layer_find_live_format(layer,1128 media_bus_format);1129 if (WARN_ON(!layer->disp_fmt))1130 return;1131 1132 zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);1133 1134 layer->drm_fmt = drm_format_info(layer->disp_fmt->drm_fmt);1135}1136 1137/**1138 * zynqmp_disp_layer_update - Update the layer framebuffer1139 * @layer: The layer1140 * @state: The plane state1141 *1142 * Update the framebuffer for the layer by issuing a new DMA engine transaction1143 * for the new framebuffer.1144 *1145 * Return: 0 on success, or the DMA descriptor failure error otherwise1146 */1147int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,1148 struct drm_plane_state *state)1149{1150 const struct drm_format_info *info = layer->drm_fmt;1151 unsigned int i;1152 1153 if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)1154 return 0;1155 1156 for (i = 0; i < info->num_planes; i++) {1157 unsigned int width = state->crtc_w / (i ? info->hsub : 1);1158 unsigned int height = state->crtc_h / (i ? info->vsub : 1);1159 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];1160 struct dma_async_tx_descriptor *desc;1161 dma_addr_t dma_addr;1162 1163 dma_addr = drm_fb_dma_get_gem_addr(state->fb, state, i);1164 1165 dma->xt.numf = height;1166 dma->sgl.size = width * info->cpp[i];1167 dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size;1168 dma->xt.src_start = dma_addr;1169 dma->xt.frame_size = 1;1170 dma->xt.dir = DMA_MEM_TO_DEV;1171 dma->xt.src_sgl = true;1172 dma->xt.dst_sgl = false;1173 1174 desc = dmaengine_prep_interleaved_dma(dma->chan, &dma->xt,1175 DMA_CTRL_ACK |1176 DMA_PREP_REPEAT |1177 DMA_PREP_LOAD_EOT);1178 if (!desc) {1179 dev_err(layer->disp->dev,1180 "failed to prepare DMA descriptor\n");1181 return -ENOMEM;1182 }1183 1184 dmaengine_submit(desc);1185 dma_async_issue_pending(dma->chan);1186 }1187 1188 return 0;1189}1190 1191/**1192 * zynqmp_disp_layer_release_dma - Release DMA channels for a layer1193 * @disp: Display controller1194 * @layer: The layer1195 *1196 * Release the DMA channels associated with @layer.1197 */1198static void zynqmp_disp_layer_release_dma(struct zynqmp_disp *disp,1199 struct zynqmp_disp_layer *layer)1200{1201 unsigned int i;1202 1203 for (i = 0; i < layer->info->num_channels; i++) {1204 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];1205 1206 if (!dma->chan)1207 continue;1208 1209 /* Make sure the channel is terminated before release. */1210 dmaengine_terminate_sync(dma->chan);1211 dma_release_channel(dma->chan);1212 }1213}1214 1215/**1216 * zynqmp_disp_destroy_layers - Destroy all layers1217 * @disp: Display controller1218 */1219static void zynqmp_disp_destroy_layers(struct zynqmp_disp *disp)1220{1221 unsigned int i;1222 1223 for (i = 0; i < ARRAY_SIZE(disp->layers); i++)1224 zynqmp_disp_layer_release_dma(disp, &disp->layers[i]);1225}1226 1227/**1228 * zynqmp_disp_layer_request_dma - Request DMA channels for a layer1229 * @disp: Display controller1230 * @layer: The layer1231 *1232 * Request all DMA engine channels needed by @layer.1233 *1234 * Return: 0 on success, or the DMA channel request error otherwise1235 */1236static int zynqmp_disp_layer_request_dma(struct zynqmp_disp *disp,1237 struct zynqmp_disp_layer *layer)1238{1239 static const char * const dma_names[] = { "vid", "gfx" };1240 unsigned int i;1241 int ret;1242 1243 for (i = 0; i < layer->info->num_channels; i++) {1244 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];1245 char dma_channel_name[16];1246 1247 snprintf(dma_channel_name, sizeof(dma_channel_name),1248 "%s%u", dma_names[layer->id], i);1249 dma->chan = dma_request_chan(disp->dev, dma_channel_name);1250 if (IS_ERR(dma->chan)) {1251 ret = dev_err_probe(disp->dev, PTR_ERR(dma->chan),1252 "failed to request dma channel\n");1253 dma->chan = NULL;1254 return ret;1255 }1256 }1257 1258 return 0;1259}1260 1261/**1262 * zynqmp_disp_create_layers - Create and initialize all layers1263 * @disp: Display controller1264 *1265 * Return: 0 on success, or the DMA channel request error otherwise1266 */1267static int zynqmp_disp_create_layers(struct zynqmp_disp *disp)1268{1269 static const struct zynqmp_disp_layer_info layer_info[] = {1270 [ZYNQMP_DPSUB_LAYER_VID] = {1271 .formats = avbuf_vid_fmts,1272 .num_formats = ARRAY_SIZE(avbuf_vid_fmts),1273 .num_channels = 3,1274 },1275 [ZYNQMP_DPSUB_LAYER_GFX] = {1276 .formats = avbuf_gfx_fmts,1277 .num_formats = ARRAY_SIZE(avbuf_gfx_fmts),1278 .num_channels = 1,1279 },1280 };1281 static const struct zynqmp_disp_layer_info live_layer_info = {1282 .formats = avbuf_live_fmts,1283 .num_formats = ARRAY_SIZE(avbuf_live_fmts),1284 .num_channels = 0,1285 };1286 1287 unsigned int i;1288 int ret;1289 1290 for (i = 0; i < ARRAY_SIZE(disp->layers); i++) {1291 struct zynqmp_disp_layer *layer = &disp->layers[i];1292 1293 layer->id = i;1294 layer->disp = disp;1295 /*1296 * For now assume dpsub works in either live or non-live mode for both layers.1297 * Hybrid mode is not supported yet.1298 */1299 if (disp->dpsub->dma_enabled) {1300 layer->mode = ZYNQMP_DPSUB_LAYER_NONLIVE;1301 layer->info = &layer_info[i];1302 } else {1303 layer->mode = ZYNQMP_DPSUB_LAYER_LIVE;1304 layer->info = &live_layer_info;1305 }1306 1307 ret = zynqmp_disp_layer_request_dma(disp, layer);1308 if (ret)1309 goto err;1310 1311 disp->dpsub->layers[i] = layer;1312 }1313 1314 return 0;1315 1316err:1317 zynqmp_disp_destroy_layers(disp);1318 return ret;1319}1320 1321/* -----------------------------------------------------------------------------1322 * ZynqMP Display1323 */1324 1325/**1326 * zynqmp_disp_enable - Enable the display controller1327 * @disp: Display controller1328 */1329void zynqmp_disp_enable(struct zynqmp_disp *disp)1330{1331 zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB);1332 zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0);1333 1334 zynqmp_disp_avbuf_enable(disp);1335 /* Choose clock source based on the DT clock handle. */1336 zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps,1337 disp->dpsub->aud_clk_from_ps,1338 disp->dpsub->vid_clk_from_ps);1339 zynqmp_disp_avbuf_enable_channels(disp);1340 zynqmp_disp_avbuf_enable_audio(disp);1341 1342 zynqmp_disp_audio_enable(disp);1343}1344 1345/**1346 * zynqmp_disp_disable - Disable the display controller1347 * @disp: Display controller1348 */1349void zynqmp_disp_disable(struct zynqmp_disp *disp)1350{1351 zynqmp_disp_audio_disable(disp);1352 1353 zynqmp_disp_avbuf_disable_audio(disp);1354 zynqmp_disp_avbuf_disable_channels(disp);1355 zynqmp_disp_avbuf_disable(disp);1356}1357 1358/**1359 * zynqmp_disp_setup_clock - Configure the display controller pixel clock rate1360 * @disp: Display controller1361 * @mode_clock: The pixel clock rate, in Hz1362 *1363 * Return: 0 on success, or a negative error clock otherwise1364 */1365int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,1366 unsigned long mode_clock)1367{1368 unsigned long rate;1369 long diff;1370 int ret;1371 1372 ret = clk_set_rate(disp->dpsub->vid_clk, mode_clock);1373 if (ret) {1374 dev_err(disp->dev, "failed to set the video clock\n");1375 return ret;1376 }1377 1378 rate = clk_get_rate(disp->dpsub->vid_clk);1379 diff = rate - mode_clock;1380 if (abs(diff) > mode_clock / 20)1381 dev_info(disp->dev,1382 "requested pixel rate: %lu actual rate: %lu\n",1383 mode_clock, rate);1384 else1385 dev_dbg(disp->dev,1386 "requested pixel rate: %lu actual rate: %lu\n",1387 mode_clock, rate);1388 1389 return 0;1390}1391 1392/* -----------------------------------------------------------------------------1393 * Initialization & Cleanup1394 */1395 1396int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub)1397{1398 struct platform_device *pdev = to_platform_device(dpsub->dev);1399 struct zynqmp_disp *disp;1400 int ret;1401 1402 disp = kzalloc(sizeof(*disp), GFP_KERNEL);1403 if (!disp)1404 return -ENOMEM;1405 1406 disp->dev = &pdev->dev;1407 disp->dpsub = dpsub;1408 1409 disp->blend = devm_platform_ioremap_resource_byname(pdev, "blend");1410 if (IS_ERR(disp->blend)) {1411 ret = PTR_ERR(disp->blend);1412 goto error;1413 }1414 1415 disp->avbuf = devm_platform_ioremap_resource_byname(pdev, "av_buf");1416 if (IS_ERR(disp->avbuf)) {1417 ret = PTR_ERR(disp->avbuf);1418 goto error;1419 }1420 1421 disp->audio = devm_platform_ioremap_resource_byname(pdev, "aud");1422 if (IS_ERR(disp->audio)) {1423 ret = PTR_ERR(disp->audio);1424 goto error;1425 }1426 1427 ret = zynqmp_disp_create_layers(disp);1428 if (ret)1429 goto error;1430 1431 if (disp->dpsub->dma_enabled) {1432 struct zynqmp_disp_layer *layer;1433 1434 layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID];1435 dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align;1436 }1437 1438 dpsub->disp = disp;1439 1440 return 0;1441 1442error:1443 kfree(disp);1444 return ret;1445}1446 1447void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub)1448{1449 struct zynqmp_disp *disp = dpsub->disp;1450 1451 zynqmp_disp_destroy_layers(disp);1452}1453