1783ad972SXinliang Liu /* 2783ad972SXinliang Liu * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver 3783ad972SXinliang Liu * 4783ad972SXinliang Liu * Copyright (c) 2016 Linaro Limited. 5783ad972SXinliang Liu * Copyright (c) 2014-2016 Hisilicon Limited. 6783ad972SXinliang Liu * 7783ad972SXinliang Liu * Author: 8783ad972SXinliang Liu * Xinliang Liu <z.liuxinliang@hisilicon.com> 9783ad972SXinliang Liu * Xinliang Liu <xinliang.liu@linaro.org> 10783ad972SXinliang Liu * Xinwei Kong <kong.kongxinwei@hisilicon.com> 11783ad972SXinliang Liu * 12783ad972SXinliang Liu * This program is free software; you can redistribute it and/or modify 13783ad972SXinliang Liu * it under the terms of the GNU General Public License version 2 as 14783ad972SXinliang Liu * published by the Free Software Foundation. 15783ad972SXinliang Liu * 16783ad972SXinliang Liu */ 17783ad972SXinliang Liu 18783ad972SXinliang Liu #include <linux/bitops.h> 19783ad972SXinliang Liu #include <linux/clk.h> 20783ad972SXinliang Liu #include <video/display_timing.h> 21783ad972SXinliang Liu #include <linux/mfd/syscon.h> 22783ad972SXinliang Liu #include <linux/regmap.h> 23783ad972SXinliang Liu #include <linux/reset.h> 24783ad972SXinliang Liu 25783ad972SXinliang Liu #include <drm/drmP.h> 26783ad972SXinliang Liu #include <drm/drm_crtc.h> 27783ad972SXinliang Liu #include <drm/drm_crtc_helper.h> 28783ad972SXinliang Liu #include <drm/drm_atomic.h> 29783ad972SXinliang Liu #include <drm/drm_atomic_helper.h> 30d3c9a738SXinliang Liu #include <drm/drm_plane_helper.h> 31d3c9a738SXinliang Liu #include <drm/drm_gem_cma_helper.h> 32d3c9a738SXinliang Liu #include <drm/drm_fb_cma_helper.h> 33783ad972SXinliang Liu 34783ad972SXinliang Liu #include "kirin_drm_drv.h" 35783ad972SXinliang Liu #include "kirin_ade_reg.h" 36783ad972SXinliang Liu 37d3c9a738SXinliang Liu #define PRIMARY_CH ADE_CH1 /* primary plane */ 38d3c9a738SXinliang Liu #define OUT_OVLY ADE_OVLY2 /* output overlay compositor */ 39d3c9a738SXinliang Liu #define ADE_DEBUG 1 40d3c9a738SXinliang Liu 41783ad972SXinliang Liu #define to_ade_crtc(crtc) \ 42783ad972SXinliang Liu container_of(crtc, struct ade_crtc, base) 43783ad972SXinliang Liu 44d3c9a738SXinliang Liu #define to_ade_plane(plane) \ 45d3c9a738SXinliang Liu container_of(plane, struct ade_plane, base) 46d3c9a738SXinliang Liu 47783ad972SXinliang Liu struct ade_hw_ctx { 48783ad972SXinliang Liu void __iomem *base; 49783ad972SXinliang Liu struct regmap *noc_regmap; 50783ad972SXinliang Liu struct clk *ade_core_clk; 51783ad972SXinliang Liu struct clk *media_noc_clk; 52783ad972SXinliang Liu struct clk *ade_pix_clk; 53783ad972SXinliang Liu struct reset_control *reset; 54783ad972SXinliang Liu bool power_on; 55783ad972SXinliang Liu int irq; 56783ad972SXinliang Liu }; 57783ad972SXinliang Liu 58783ad972SXinliang Liu struct ade_crtc { 59783ad972SXinliang Liu struct drm_crtc base; 60783ad972SXinliang Liu struct ade_hw_ctx *ctx; 61783ad972SXinliang Liu bool enable; 62783ad972SXinliang Liu u32 out_format; 63783ad972SXinliang Liu }; 64783ad972SXinliang Liu 65d3c9a738SXinliang Liu struct ade_plane { 66d3c9a738SXinliang Liu struct drm_plane base; 67d3c9a738SXinliang Liu void *ctx; 68d3c9a738SXinliang Liu u8 ch; /* channel */ 69d3c9a738SXinliang Liu }; 70d3c9a738SXinliang Liu 71783ad972SXinliang Liu struct ade_data { 72783ad972SXinliang Liu struct ade_crtc acrtc; 73d3c9a738SXinliang Liu struct ade_plane aplane[ADE_CH_NUM]; 74783ad972SXinliang Liu struct ade_hw_ctx ctx; 75783ad972SXinliang Liu }; 76783ad972SXinliang Liu 77d3c9a738SXinliang Liu /* ade-format info: */ 78d3c9a738SXinliang Liu struct ade_format { 79d3c9a738SXinliang Liu u32 pixel_format; 80d3c9a738SXinliang Liu enum ade_fb_format ade_format; 81d3c9a738SXinliang Liu }; 82d3c9a738SXinliang Liu 83d3c9a738SXinliang Liu static const struct ade_format ade_formats[] = { 84d3c9a738SXinliang Liu /* 16bpp RGB: */ 85d3c9a738SXinliang Liu { DRM_FORMAT_RGB565, ADE_RGB_565 }, 86d3c9a738SXinliang Liu { DRM_FORMAT_BGR565, ADE_BGR_565 }, 87d3c9a738SXinliang Liu /* 24bpp RGB: */ 88d3c9a738SXinliang Liu { DRM_FORMAT_RGB888, ADE_RGB_888 }, 89d3c9a738SXinliang Liu { DRM_FORMAT_BGR888, ADE_BGR_888 }, 90d3c9a738SXinliang Liu /* 32bpp [A]RGB: */ 91d3c9a738SXinliang Liu { DRM_FORMAT_XRGB8888, ADE_XRGB_8888 }, 92d3c9a738SXinliang Liu { DRM_FORMAT_XBGR8888, ADE_XBGR_8888 }, 93d3c9a738SXinliang Liu { DRM_FORMAT_RGBA8888, ADE_RGBA_8888 }, 94d3c9a738SXinliang Liu { DRM_FORMAT_BGRA8888, ADE_BGRA_8888 }, 95d3c9a738SXinliang Liu { DRM_FORMAT_ARGB8888, ADE_ARGB_8888 }, 96d3c9a738SXinliang Liu { DRM_FORMAT_ABGR8888, ADE_ABGR_8888 }, 97d3c9a738SXinliang Liu }; 98d3c9a738SXinliang Liu 99d3c9a738SXinliang Liu static const u32 channel_formats1[] = { 100d3c9a738SXinliang Liu /* channel 1,2,3,4 */ 101d3c9a738SXinliang Liu DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888, 102d3c9a738SXinliang Liu DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, 103d3c9a738SXinliang Liu DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888, 104d3c9a738SXinliang Liu DRM_FORMAT_ABGR8888 105d3c9a738SXinliang Liu }; 106d3c9a738SXinliang Liu 107d3c9a738SXinliang Liu u32 ade_get_channel_formats(u8 ch, const u32 **formats) 108d3c9a738SXinliang Liu { 109d3c9a738SXinliang Liu switch (ch) { 110d3c9a738SXinliang Liu case ADE_CH1: 111d3c9a738SXinliang Liu *formats = channel_formats1; 112d3c9a738SXinliang Liu return ARRAY_SIZE(channel_formats1); 113d3c9a738SXinliang Liu default: 114d3c9a738SXinliang Liu DRM_ERROR("no this channel %d\n", ch); 115d3c9a738SXinliang Liu *formats = NULL; 116d3c9a738SXinliang Liu return 0; 117d3c9a738SXinliang Liu } 118d3c9a738SXinliang Liu } 119d3c9a738SXinliang Liu 120d3c9a738SXinliang Liu /* convert from fourcc format to ade format */ 121d3c9a738SXinliang Liu static u32 ade_get_format(u32 pixel_format) 122d3c9a738SXinliang Liu { 123d3c9a738SXinliang Liu int i; 124d3c9a738SXinliang Liu 125d3c9a738SXinliang Liu for (i = 0; i < ARRAY_SIZE(ade_formats); i++) 126d3c9a738SXinliang Liu if (ade_formats[i].pixel_format == pixel_format) 127d3c9a738SXinliang Liu return ade_formats[i].ade_format; 128d3c9a738SXinliang Liu 129d3c9a738SXinliang Liu /* not found */ 130d3c9a738SXinliang Liu DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", 131d3c9a738SXinliang Liu pixel_format); 132d3c9a738SXinliang Liu return ADE_FORMAT_UNSUPPORT; 133d3c9a738SXinliang Liu } 134d3c9a738SXinliang Liu 135783ad972SXinliang Liu static void ade_update_reload_bit(void __iomem *base, u32 bit_num, u32 val) 136783ad972SXinliang Liu { 137783ad972SXinliang Liu u32 bit_ofst, reg_num; 138783ad972SXinliang Liu 139783ad972SXinliang Liu bit_ofst = bit_num % 32; 140783ad972SXinliang Liu reg_num = bit_num / 32; 141783ad972SXinliang Liu 142783ad972SXinliang Liu ade_update_bits(base + ADE_RELOAD_DIS(reg_num), bit_ofst, 143783ad972SXinliang Liu MASK(1), !!val); 144783ad972SXinliang Liu } 145783ad972SXinliang Liu 146783ad972SXinliang Liu static u32 ade_read_reload_bit(void __iomem *base, u32 bit_num) 147783ad972SXinliang Liu { 148783ad972SXinliang Liu u32 tmp, bit_ofst, reg_num; 149783ad972SXinliang Liu 150783ad972SXinliang Liu bit_ofst = bit_num % 32; 151783ad972SXinliang Liu reg_num = bit_num / 32; 152783ad972SXinliang Liu 153783ad972SXinliang Liu tmp = readl(base + ADE_RELOAD_DIS(reg_num)); 154783ad972SXinliang Liu return !!(BIT(bit_ofst) & tmp); 155783ad972SXinliang Liu } 156783ad972SXinliang Liu 157783ad972SXinliang Liu static void ade_init(struct ade_hw_ctx *ctx) 158783ad972SXinliang Liu { 159783ad972SXinliang Liu void __iomem *base = ctx->base; 160783ad972SXinliang Liu 161783ad972SXinliang Liu /* enable clk gate */ 162783ad972SXinliang Liu ade_update_bits(base + ADE_CTRL1, AUTO_CLK_GATE_EN_OFST, 163783ad972SXinliang Liu AUTO_CLK_GATE_EN, ADE_ENABLE); 164783ad972SXinliang Liu /* clear overlay */ 165783ad972SXinliang Liu writel(0, base + ADE_OVLY1_TRANS_CFG); 166783ad972SXinliang Liu writel(0, base + ADE_OVLY_CTL); 167d3c9a738SXinliang Liu writel(0, base + ADE_OVLYX_CTL(OUT_OVLY)); 168783ad972SXinliang Liu /* clear reset and reload regs */ 169783ad972SXinliang Liu writel(MASK(32), base + ADE_SOFT_RST_SEL(0)); 170783ad972SXinliang Liu writel(MASK(32), base + ADE_SOFT_RST_SEL(1)); 171783ad972SXinliang Liu writel(MASK(32), base + ADE_RELOAD_DIS(0)); 172783ad972SXinliang Liu writel(MASK(32), base + ADE_RELOAD_DIS(1)); 173783ad972SXinliang Liu /* 174783ad972SXinliang Liu * for video mode, all the ade registers should 175783ad972SXinliang Liu * become effective at frame end. 176783ad972SXinliang Liu */ 177783ad972SXinliang Liu ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST, 178783ad972SXinliang Liu FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND); 179783ad972SXinliang Liu } 180783ad972SXinliang Liu 181783ad972SXinliang Liu static void ade_set_pix_clk(struct ade_hw_ctx *ctx, 182783ad972SXinliang Liu struct drm_display_mode *mode, 183783ad972SXinliang Liu struct drm_display_mode *adj_mode) 184783ad972SXinliang Liu { 185783ad972SXinliang Liu u32 clk_Hz = mode->clock * 1000; 186783ad972SXinliang Liu int ret; 187783ad972SXinliang Liu 188783ad972SXinliang Liu /* 189783ad972SXinliang Liu * Success should be guaranteed in mode_valid call back, 190783ad972SXinliang Liu * so failure shouldn't happen here 191783ad972SXinliang Liu */ 192783ad972SXinliang Liu ret = clk_set_rate(ctx->ade_pix_clk, clk_Hz); 193783ad972SXinliang Liu if (ret) 194783ad972SXinliang Liu DRM_ERROR("failed to set pixel clk %dHz (%d)\n", clk_Hz, ret); 195783ad972SXinliang Liu adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000; 196783ad972SXinliang Liu } 197783ad972SXinliang Liu 198783ad972SXinliang Liu static void ade_ldi_set_mode(struct ade_crtc *acrtc, 199783ad972SXinliang Liu struct drm_display_mode *mode, 200783ad972SXinliang Liu struct drm_display_mode *adj_mode) 201783ad972SXinliang Liu { 202783ad972SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 203783ad972SXinliang Liu void __iomem *base = ctx->base; 204783ad972SXinliang Liu u32 width = mode->hdisplay; 205783ad972SXinliang Liu u32 height = mode->vdisplay; 206783ad972SXinliang Liu u32 hfp, hbp, hsw, vfp, vbp, vsw; 207783ad972SXinliang Liu u32 plr_flags; 208783ad972SXinliang Liu 209783ad972SXinliang Liu plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? FLAG_NVSYNC : 0; 210783ad972SXinliang Liu plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC) ? FLAG_NHSYNC : 0; 211783ad972SXinliang Liu hfp = mode->hsync_start - mode->hdisplay; 212783ad972SXinliang Liu hbp = mode->htotal - mode->hsync_end; 213783ad972SXinliang Liu hsw = mode->hsync_end - mode->hsync_start; 214783ad972SXinliang Liu vfp = mode->vsync_start - mode->vdisplay; 215783ad972SXinliang Liu vbp = mode->vtotal - mode->vsync_end; 216783ad972SXinliang Liu vsw = mode->vsync_end - mode->vsync_start; 217783ad972SXinliang Liu if (vsw > 15) { 218783ad972SXinliang Liu DRM_DEBUG_DRIVER("vsw exceeded 15\n"); 219783ad972SXinliang Liu vsw = 15; 220783ad972SXinliang Liu } 221783ad972SXinliang Liu 222783ad972SXinliang Liu writel((hbp << HBP_OFST) | hfp, base + LDI_HRZ_CTRL0); 223783ad972SXinliang Liu /* the configured value is actual value - 1 */ 224783ad972SXinliang Liu writel(hsw - 1, base + LDI_HRZ_CTRL1); 225783ad972SXinliang Liu writel((vbp << VBP_OFST) | vfp, base + LDI_VRT_CTRL0); 226783ad972SXinliang Liu /* the configured value is actual value - 1 */ 227783ad972SXinliang Liu writel(vsw - 1, base + LDI_VRT_CTRL1); 228783ad972SXinliang Liu /* the configured value is actual value - 1 */ 229783ad972SXinliang Liu writel(((height - 1) << VSIZE_OFST) | (width - 1), 230783ad972SXinliang Liu base + LDI_DSP_SIZE); 231783ad972SXinliang Liu writel(plr_flags, base + LDI_PLR_CTRL); 232783ad972SXinliang Liu 233d3c9a738SXinliang Liu /* set overlay compositor output size */ 234d3c9a738SXinliang Liu writel(((width - 1) << OUTPUT_XSIZE_OFST) | (height - 1), 235d3c9a738SXinliang Liu base + ADE_OVLY_OUTPUT_SIZE(OUT_OVLY)); 236d3c9a738SXinliang Liu 237783ad972SXinliang Liu /* ctran6 setting */ 238783ad972SXinliang Liu writel(CTRAN_BYPASS_ON, base + ADE_CTRAN_DIS(ADE_CTRAN6)); 239783ad972SXinliang Liu /* the configured value is actual value - 1 */ 240783ad972SXinliang Liu writel(width * height - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6)); 241783ad972SXinliang Liu ade_update_reload_bit(base, CTRAN_OFST + ADE_CTRAN6, 0); 242783ad972SXinliang Liu 243783ad972SXinliang Liu ade_set_pix_clk(ctx, mode, adj_mode); 244783ad972SXinliang Liu 245783ad972SXinliang Liu DRM_DEBUG_DRIVER("set mode: %dx%d\n", width, height); 246783ad972SXinliang Liu } 247783ad972SXinliang Liu 248783ad972SXinliang Liu static int ade_power_up(struct ade_hw_ctx *ctx) 249783ad972SXinliang Liu { 250783ad972SXinliang Liu int ret; 251783ad972SXinliang Liu 252783ad972SXinliang Liu ret = clk_prepare_enable(ctx->media_noc_clk); 253783ad972SXinliang Liu if (ret) { 254783ad972SXinliang Liu DRM_ERROR("failed to enable media_noc_clk (%d)\n", ret); 255783ad972SXinliang Liu return ret; 256783ad972SXinliang Liu } 257783ad972SXinliang Liu 258783ad972SXinliang Liu ret = reset_control_deassert(ctx->reset); 259783ad972SXinliang Liu if (ret) { 260783ad972SXinliang Liu DRM_ERROR("failed to deassert reset\n"); 261783ad972SXinliang Liu return ret; 262783ad972SXinliang Liu } 263783ad972SXinliang Liu 264783ad972SXinliang Liu ret = clk_prepare_enable(ctx->ade_core_clk); 265783ad972SXinliang Liu if (ret) { 266783ad972SXinliang Liu DRM_ERROR("failed to enable ade_core_clk (%d)\n", ret); 267783ad972SXinliang Liu return ret; 268783ad972SXinliang Liu } 269783ad972SXinliang Liu 270783ad972SXinliang Liu ade_init(ctx); 271783ad972SXinliang Liu ctx->power_on = true; 272783ad972SXinliang Liu return 0; 273783ad972SXinliang Liu } 274783ad972SXinliang Liu 275783ad972SXinliang Liu static void ade_power_down(struct ade_hw_ctx *ctx) 276783ad972SXinliang Liu { 277783ad972SXinliang Liu void __iomem *base = ctx->base; 278783ad972SXinliang Liu 279783ad972SXinliang Liu writel(ADE_DISABLE, base + LDI_CTRL); 280783ad972SXinliang Liu /* dsi pixel off */ 281783ad972SXinliang Liu writel(DSI_PCLK_OFF, base + LDI_HDMI_DSI_GT); 282783ad972SXinliang Liu 283783ad972SXinliang Liu clk_disable_unprepare(ctx->ade_core_clk); 284783ad972SXinliang Liu reset_control_assert(ctx->reset); 285783ad972SXinliang Liu clk_disable_unprepare(ctx->media_noc_clk); 286783ad972SXinliang Liu ctx->power_on = false; 287783ad972SXinliang Liu } 288783ad972SXinliang Liu 289783ad972SXinliang Liu static void ade_set_medianoc_qos(struct ade_crtc *acrtc) 290783ad972SXinliang Liu { 291783ad972SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 292783ad972SXinliang Liu struct regmap *map = ctx->noc_regmap; 293783ad972SXinliang Liu 294783ad972SXinliang Liu regmap_update_bits(map, ADE0_QOSGENERATOR_MODE, 295783ad972SXinliang Liu QOSGENERATOR_MODE_MASK, BYPASS_MODE); 296783ad972SXinliang Liu regmap_update_bits(map, ADE0_QOSGENERATOR_EXTCONTROL, 297783ad972SXinliang Liu SOCKET_QOS_EN, SOCKET_QOS_EN); 298783ad972SXinliang Liu 299783ad972SXinliang Liu regmap_update_bits(map, ADE1_QOSGENERATOR_MODE, 300783ad972SXinliang Liu QOSGENERATOR_MODE_MASK, BYPASS_MODE); 301783ad972SXinliang Liu regmap_update_bits(map, ADE1_QOSGENERATOR_EXTCONTROL, 302783ad972SXinliang Liu SOCKET_QOS_EN, SOCKET_QOS_EN); 303783ad972SXinliang Liu } 304783ad972SXinliang Liu 305bc4611e8SXinliang Liu static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe) 306bc4611e8SXinliang Liu { 307bc4611e8SXinliang Liu struct kirin_drm_private *priv = dev->dev_private; 308bc4611e8SXinliang Liu struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]); 309bc4611e8SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 310bc4611e8SXinliang Liu void __iomem *base = ctx->base; 311bc4611e8SXinliang Liu 312bc4611e8SXinliang Liu if (!ctx->power_on) 313bc4611e8SXinliang Liu (void)ade_power_up(ctx); 314bc4611e8SXinliang Liu 315bc4611e8SXinliang Liu ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST, 316bc4611e8SXinliang Liu MASK(1), 1); 317bc4611e8SXinliang Liu 318bc4611e8SXinliang Liu return 0; 319bc4611e8SXinliang Liu } 320bc4611e8SXinliang Liu 321bc4611e8SXinliang Liu static void ade_disable_vblank(struct drm_device *dev, unsigned int pipe) 322bc4611e8SXinliang Liu { 323bc4611e8SXinliang Liu struct kirin_drm_private *priv = dev->dev_private; 324bc4611e8SXinliang Liu struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]); 325bc4611e8SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 326bc4611e8SXinliang Liu void __iomem *base = ctx->base; 327bc4611e8SXinliang Liu 328bc4611e8SXinliang Liu if (!ctx->power_on) { 329bc4611e8SXinliang Liu DRM_ERROR("power is down! vblank disable fail\n"); 330bc4611e8SXinliang Liu return; 331bc4611e8SXinliang Liu } 332bc4611e8SXinliang Liu 333bc4611e8SXinliang Liu ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST, 334bc4611e8SXinliang Liu MASK(1), 0); 335bc4611e8SXinliang Liu } 336bc4611e8SXinliang Liu 337bc4611e8SXinliang Liu static irqreturn_t ade_irq_handler(int irq, void *data) 338bc4611e8SXinliang Liu { 339bc4611e8SXinliang Liu struct ade_crtc *acrtc = data; 340bc4611e8SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 341bc4611e8SXinliang Liu struct drm_crtc *crtc = &acrtc->base; 342bc4611e8SXinliang Liu void __iomem *base = ctx->base; 343bc4611e8SXinliang Liu u32 status; 344bc4611e8SXinliang Liu 345bc4611e8SXinliang Liu status = readl(base + LDI_MSK_INT); 346bc4611e8SXinliang Liu DRM_DEBUG_VBL("LDI IRQ: status=0x%X\n", status); 347bc4611e8SXinliang Liu 348bc4611e8SXinliang Liu /* vblank irq */ 349bc4611e8SXinliang Liu if (status & BIT(FRAME_END_INT_EN_OFST)) { 350bc4611e8SXinliang Liu ade_update_bits(base + LDI_INT_CLR, FRAME_END_INT_EN_OFST, 351bc4611e8SXinliang Liu MASK(1), 1); 352bc4611e8SXinliang Liu drm_crtc_handle_vblank(crtc); 353bc4611e8SXinliang Liu } 354bc4611e8SXinliang Liu 355bc4611e8SXinliang Liu return IRQ_HANDLED; 356bc4611e8SXinliang Liu } 357bc4611e8SXinliang Liu 358783ad972SXinliang Liu static void ade_display_enable(struct ade_crtc *acrtc) 359783ad972SXinliang Liu { 360783ad972SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 361783ad972SXinliang Liu void __iomem *base = ctx->base; 362783ad972SXinliang Liu u32 out_fmt = acrtc->out_format; 363783ad972SXinliang Liu 364d3c9a738SXinliang Liu /* enable output overlay compositor */ 365d3c9a738SXinliang Liu writel(ADE_ENABLE, base + ADE_OVLYX_CTL(OUT_OVLY)); 366d3c9a738SXinliang Liu ade_update_reload_bit(base, OVLY_OFST + OUT_OVLY, 0); 367d3c9a738SXinliang Liu 368783ad972SXinliang Liu /* display source setting */ 369783ad972SXinliang Liu writel(DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG); 370783ad972SXinliang Liu 371783ad972SXinliang Liu /* enable ade */ 372783ad972SXinliang Liu writel(ADE_ENABLE, base + ADE_EN); 373783ad972SXinliang Liu /* enable ldi */ 374783ad972SXinliang Liu writel(NORMAL_MODE, base + LDI_WORK_MODE); 375783ad972SXinliang Liu writel((out_fmt << BPP_OFST) | DATA_GATE_EN | LDI_EN, 376783ad972SXinliang Liu base + LDI_CTRL); 377783ad972SXinliang Liu /* dsi pixel on */ 378783ad972SXinliang Liu writel(DSI_PCLK_ON, base + LDI_HDMI_DSI_GT); 379783ad972SXinliang Liu } 380783ad972SXinliang Liu 381d3c9a738SXinliang Liu #if ADE_DEBUG 382d3c9a738SXinliang Liu static void ade_rdma_dump_regs(void __iomem *base, u32 ch) 383d3c9a738SXinliang Liu { 384d3c9a738SXinliang Liu u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en; 385d3c9a738SXinliang Liu u32 val; 386d3c9a738SXinliang Liu 387d3c9a738SXinliang Liu reg_ctrl = RD_CH_CTRL(ch); 388d3c9a738SXinliang Liu reg_addr = RD_CH_ADDR(ch); 389d3c9a738SXinliang Liu reg_size = RD_CH_SIZE(ch); 390d3c9a738SXinliang Liu reg_stride = RD_CH_STRIDE(ch); 391d3c9a738SXinliang Liu reg_space = RD_CH_SPACE(ch); 392d3c9a738SXinliang Liu reg_en = RD_CH_EN(ch); 393d3c9a738SXinliang Liu 394d3c9a738SXinliang Liu val = ade_read_reload_bit(base, RDMA_OFST + ch); 395d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reload(%d)\n", ch + 1, val); 396d3c9a738SXinliang Liu val = readl(base + reg_ctrl); 397d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_ctrl(0x%08x)\n", ch + 1, val); 398d3c9a738SXinliang Liu val = readl(base + reg_addr); 399d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_addr(0x%08x)\n", ch + 1, val); 400d3c9a738SXinliang Liu val = readl(base + reg_size); 401d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_size(0x%08x)\n", ch + 1, val); 402d3c9a738SXinliang Liu val = readl(base + reg_stride); 403d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_stride(0x%08x)\n", ch + 1, val); 404d3c9a738SXinliang Liu val = readl(base + reg_space); 405d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_space(0x%08x)\n", ch + 1, val); 406d3c9a738SXinliang Liu val = readl(base + reg_en); 407d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_en(0x%08x)\n", ch + 1, val); 408d3c9a738SXinliang Liu } 409d3c9a738SXinliang Liu 410d3c9a738SXinliang Liu static void ade_clip_dump_regs(void __iomem *base, u32 ch) 411d3c9a738SXinliang Liu { 412d3c9a738SXinliang Liu u32 val; 413d3c9a738SXinliang Liu 414d3c9a738SXinliang Liu val = ade_read_reload_bit(base, CLIP_OFST + ch); 415d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[clip%d]: reload(%d)\n", ch + 1, val); 416d3c9a738SXinliang Liu val = readl(base + ADE_CLIP_DISABLE(ch)); 417d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[clip%d]: reg_clip_disable(0x%08x)\n", ch + 1, val); 418d3c9a738SXinliang Liu val = readl(base + ADE_CLIP_SIZE0(ch)); 419d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size0(0x%08x)\n", ch + 1, val); 420d3c9a738SXinliang Liu val = readl(base + ADE_CLIP_SIZE1(ch)); 421d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size1(0x%08x)\n", ch + 1, val); 422d3c9a738SXinliang Liu } 423d3c9a738SXinliang Liu 424d3c9a738SXinliang Liu static void ade_compositor_routing_dump_regs(void __iomem *base, u32 ch) 425d3c9a738SXinliang Liu { 426d3c9a738SXinliang Liu u8 ovly_ch = 0; /* TODO: Only primary plane now */ 427d3c9a738SXinliang Liu u32 val; 428d3c9a738SXinliang Liu 429d3c9a738SXinliang Liu val = readl(base + ADE_OVLY_CH_XY0(ovly_ch)); 430d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy0(0x%08x)\n", ovly_ch, val); 431d3c9a738SXinliang Liu val = readl(base + ADE_OVLY_CH_XY1(ovly_ch)); 432d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy1(0x%08x)\n", ovly_ch, val); 433d3c9a738SXinliang Liu val = readl(base + ADE_OVLY_CH_CTL(ovly_ch)); 434d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_ctl(0x%08x)\n", ovly_ch, val); 435d3c9a738SXinliang Liu } 436d3c9a738SXinliang Liu 437d3c9a738SXinliang Liu static void ade_dump_overlay_compositor_regs(void __iomem *base, u32 comp) 438d3c9a738SXinliang Liu { 439d3c9a738SXinliang Liu u32 val; 440d3c9a738SXinliang Liu 441d3c9a738SXinliang Liu val = ade_read_reload_bit(base, OVLY_OFST + comp); 442d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay%d]: reload(%d)\n", comp + 1, val); 443d3c9a738SXinliang Liu writel(ADE_ENABLE, base + ADE_OVLYX_CTL(comp)); 444d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay%d]: reg_ctl(0x%08x)\n", comp + 1, val); 445d3c9a738SXinliang Liu val = readl(base + ADE_OVLY_CTL); 446d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("ovly_ctl(0x%08x)\n", val); 447d3c9a738SXinliang Liu } 448d3c9a738SXinliang Liu 449d3c9a738SXinliang Liu static void ade_dump_regs(void __iomem *base) 450d3c9a738SXinliang Liu { 451d3c9a738SXinliang Liu u32 i; 452d3c9a738SXinliang Liu 453d3c9a738SXinliang Liu /* dump channel regs */ 454d3c9a738SXinliang Liu for (i = 0; i < ADE_CH_NUM; i++) { 455d3c9a738SXinliang Liu /* dump rdma regs */ 456d3c9a738SXinliang Liu ade_rdma_dump_regs(base, i); 457d3c9a738SXinliang Liu 458d3c9a738SXinliang Liu /* dump clip regs */ 459d3c9a738SXinliang Liu ade_clip_dump_regs(base, i); 460d3c9a738SXinliang Liu 461d3c9a738SXinliang Liu /* dump compositor routing regs */ 462d3c9a738SXinliang Liu ade_compositor_routing_dump_regs(base, i); 463d3c9a738SXinliang Liu } 464d3c9a738SXinliang Liu 465d3c9a738SXinliang Liu /* dump overlay compositor regs */ 466d3c9a738SXinliang Liu ade_dump_overlay_compositor_regs(base, OUT_OVLY); 467d3c9a738SXinliang Liu } 468d3c9a738SXinliang Liu #else 469d3c9a738SXinliang Liu static void ade_dump_regs(void __iomem *base) { } 470d3c9a738SXinliang Liu #endif 471d3c9a738SXinliang Liu 472783ad972SXinliang Liu static void ade_crtc_enable(struct drm_crtc *crtc) 473783ad972SXinliang Liu { 474783ad972SXinliang Liu struct ade_crtc *acrtc = to_ade_crtc(crtc); 475783ad972SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 476783ad972SXinliang Liu int ret; 477783ad972SXinliang Liu 478783ad972SXinliang Liu if (acrtc->enable) 479783ad972SXinliang Liu return; 480783ad972SXinliang Liu 481783ad972SXinliang Liu if (!ctx->power_on) { 482783ad972SXinliang Liu ret = ade_power_up(ctx); 483783ad972SXinliang Liu if (ret) 484783ad972SXinliang Liu return; 485783ad972SXinliang Liu } 486783ad972SXinliang Liu 487783ad972SXinliang Liu ade_set_medianoc_qos(acrtc); 488783ad972SXinliang Liu ade_display_enable(acrtc); 489d3c9a738SXinliang Liu ade_dump_regs(ctx->base); 490783ad972SXinliang Liu acrtc->enable = true; 491783ad972SXinliang Liu } 492783ad972SXinliang Liu 493783ad972SXinliang Liu static void ade_crtc_disable(struct drm_crtc *crtc) 494783ad972SXinliang Liu { 495783ad972SXinliang Liu struct ade_crtc *acrtc = to_ade_crtc(crtc); 496783ad972SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 497783ad972SXinliang Liu 498783ad972SXinliang Liu if (!acrtc->enable) 499783ad972SXinliang Liu return; 500783ad972SXinliang Liu 501783ad972SXinliang Liu ade_power_down(ctx); 502783ad972SXinliang Liu acrtc->enable = false; 503783ad972SXinliang Liu } 504783ad972SXinliang Liu 505783ad972SXinliang Liu static int ade_crtc_atomic_check(struct drm_crtc *crtc, 506783ad972SXinliang Liu struct drm_crtc_state *state) 507783ad972SXinliang Liu { 508783ad972SXinliang Liu /* do nothing */ 509783ad972SXinliang Liu return 0; 510783ad972SXinliang Liu } 511783ad972SXinliang Liu 512783ad972SXinliang Liu static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc) 513783ad972SXinliang Liu { 514783ad972SXinliang Liu struct ade_crtc *acrtc = to_ade_crtc(crtc); 515783ad972SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 516783ad972SXinliang Liu struct drm_display_mode *mode = &crtc->state->mode; 517783ad972SXinliang Liu struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode; 518783ad972SXinliang Liu 519783ad972SXinliang Liu if (!ctx->power_on) 520783ad972SXinliang Liu (void)ade_power_up(ctx); 521783ad972SXinliang Liu ade_ldi_set_mode(acrtc, mode, adj_mode); 522783ad972SXinliang Liu } 523783ad972SXinliang Liu 524783ad972SXinliang Liu static void ade_crtc_atomic_begin(struct drm_crtc *crtc, 525783ad972SXinliang Liu struct drm_crtc_state *old_state) 526783ad972SXinliang Liu { 527783ad972SXinliang Liu struct ade_crtc *acrtc = to_ade_crtc(crtc); 528783ad972SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 529783ad972SXinliang Liu 530783ad972SXinliang Liu if (!ctx->power_on) 531783ad972SXinliang Liu (void)ade_power_up(ctx); 532783ad972SXinliang Liu } 533783ad972SXinliang Liu 534783ad972SXinliang Liu static void ade_crtc_atomic_flush(struct drm_crtc *crtc, 535783ad972SXinliang Liu struct drm_crtc_state *old_state) 536783ad972SXinliang Liu 537783ad972SXinliang Liu { 538783ad972SXinliang Liu struct ade_crtc *acrtc = to_ade_crtc(crtc); 539783ad972SXinliang Liu struct ade_hw_ctx *ctx = acrtc->ctx; 540783ad972SXinliang Liu void __iomem *base = ctx->base; 541783ad972SXinliang Liu 542783ad972SXinliang Liu /* only crtc is enabled regs take effect */ 543783ad972SXinliang Liu if (acrtc->enable) { 544d3c9a738SXinliang Liu ade_dump_regs(base); 545783ad972SXinliang Liu /* flush ade registers */ 546783ad972SXinliang Liu writel(ADE_ENABLE, base + ADE_EN); 547783ad972SXinliang Liu } 548783ad972SXinliang Liu } 549783ad972SXinliang Liu 550783ad972SXinliang Liu static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = { 551783ad972SXinliang Liu .enable = ade_crtc_enable, 552783ad972SXinliang Liu .disable = ade_crtc_disable, 553783ad972SXinliang Liu .atomic_check = ade_crtc_atomic_check, 554783ad972SXinliang Liu .mode_set_nofb = ade_crtc_mode_set_nofb, 555783ad972SXinliang Liu .atomic_begin = ade_crtc_atomic_begin, 556783ad972SXinliang Liu .atomic_flush = ade_crtc_atomic_flush, 557783ad972SXinliang Liu }; 558783ad972SXinliang Liu 559783ad972SXinliang Liu static const struct drm_crtc_funcs ade_crtc_funcs = { 560783ad972SXinliang Liu .destroy = drm_crtc_cleanup, 561783ad972SXinliang Liu .set_config = drm_atomic_helper_set_config, 562783ad972SXinliang Liu .page_flip = drm_atomic_helper_page_flip, 563783ad972SXinliang Liu .reset = drm_atomic_helper_crtc_reset, 564783ad972SXinliang Liu .set_property = drm_atomic_helper_crtc_set_property, 565783ad972SXinliang Liu .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 566783ad972SXinliang Liu .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 567783ad972SXinliang Liu }; 568783ad972SXinliang Liu 569783ad972SXinliang Liu static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, 570783ad972SXinliang Liu struct drm_plane *plane) 571783ad972SXinliang Liu { 572783ad972SXinliang Liu struct kirin_drm_private *priv = dev->dev_private; 573783ad972SXinliang Liu struct device_node *port; 574783ad972SXinliang Liu int ret; 575783ad972SXinliang Liu 576783ad972SXinliang Liu /* set crtc port so that 577783ad972SXinliang Liu * drm_of_find_possible_crtcs call works 578783ad972SXinliang Liu */ 579783ad972SXinliang Liu port = of_get_child_by_name(dev->dev->of_node, "port"); 580783ad972SXinliang Liu if (!port) { 581783ad972SXinliang Liu DRM_ERROR("no port node found in %s\n", 582783ad972SXinliang Liu dev->dev->of_node->full_name); 583783ad972SXinliang Liu return -EINVAL; 584783ad972SXinliang Liu } 585783ad972SXinliang Liu of_node_put(port); 586783ad972SXinliang Liu crtc->port = port; 587783ad972SXinliang Liu 588783ad972SXinliang Liu ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 589783ad972SXinliang Liu &ade_crtc_funcs, NULL); 590783ad972SXinliang Liu if (ret) { 591783ad972SXinliang Liu DRM_ERROR("failed to init crtc.\n"); 592783ad972SXinliang Liu return ret; 593783ad972SXinliang Liu } 594783ad972SXinliang Liu 595783ad972SXinliang Liu drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs); 596783ad972SXinliang Liu priv->crtc[drm_crtc_index(crtc)] = crtc; 597783ad972SXinliang Liu 598783ad972SXinliang Liu return 0; 599783ad972SXinliang Liu } 600783ad972SXinliang Liu 601d3c9a738SXinliang Liu static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb, 602d3c9a738SXinliang Liu u32 ch, u32 y, u32 in_h, u32 fmt) 603d3c9a738SXinliang Liu { 604d3c9a738SXinliang Liu struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0); 605d3c9a738SXinliang Liu u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en; 606d3c9a738SXinliang Liu u32 stride = fb->pitches[0]; 607d3c9a738SXinliang Liu u32 addr = (u32)obj->paddr + y * stride; 608d3c9a738SXinliang Liu 609d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n", 610d3c9a738SXinliang Liu ch + 1, y, in_h, stride, (u32)obj->paddr); 611d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n", 612d3c9a738SXinliang Liu addr, fb->width, fb->height, fmt, 613d3c9a738SXinliang Liu drm_get_format_name(fb->pixel_format)); 614d3c9a738SXinliang Liu 615d3c9a738SXinliang Liu /* get reg offset */ 616d3c9a738SXinliang Liu reg_ctrl = RD_CH_CTRL(ch); 617d3c9a738SXinliang Liu reg_addr = RD_CH_ADDR(ch); 618d3c9a738SXinliang Liu reg_size = RD_CH_SIZE(ch); 619d3c9a738SXinliang Liu reg_stride = RD_CH_STRIDE(ch); 620d3c9a738SXinliang Liu reg_space = RD_CH_SPACE(ch); 621d3c9a738SXinliang Liu reg_en = RD_CH_EN(ch); 622d3c9a738SXinliang Liu 623d3c9a738SXinliang Liu /* 624d3c9a738SXinliang Liu * TODO: set rotation 625d3c9a738SXinliang Liu */ 626d3c9a738SXinliang Liu writel((fmt << 16) & 0x1f0000, base + reg_ctrl); 627d3c9a738SXinliang Liu writel(addr, base + reg_addr); 628d3c9a738SXinliang Liu writel((in_h << 16) | stride, base + reg_size); 629d3c9a738SXinliang Liu writel(stride, base + reg_stride); 630d3c9a738SXinliang Liu writel(in_h * stride, base + reg_space); 631d3c9a738SXinliang Liu writel(ADE_ENABLE, base + reg_en); 632d3c9a738SXinliang Liu ade_update_reload_bit(base, RDMA_OFST + ch, 0); 633d3c9a738SXinliang Liu } 634d3c9a738SXinliang Liu 635d3c9a738SXinliang Liu static void ade_rdma_disable(void __iomem *base, u32 ch) 636d3c9a738SXinliang Liu { 637d3c9a738SXinliang Liu u32 reg_en; 638d3c9a738SXinliang Liu 639d3c9a738SXinliang Liu /* get reg offset */ 640d3c9a738SXinliang Liu reg_en = RD_CH_EN(ch); 641d3c9a738SXinliang Liu writel(0, base + reg_en); 642d3c9a738SXinliang Liu ade_update_reload_bit(base, RDMA_OFST + ch, 1); 643d3c9a738SXinliang Liu } 644d3c9a738SXinliang Liu 645d3c9a738SXinliang Liu static void ade_clip_set(void __iomem *base, u32 ch, u32 fb_w, u32 x, 646d3c9a738SXinliang Liu u32 in_w, u32 in_h) 647d3c9a738SXinliang Liu { 648d3c9a738SXinliang Liu u32 disable_val; 649d3c9a738SXinliang Liu u32 clip_left; 650d3c9a738SXinliang Liu u32 clip_right; 651d3c9a738SXinliang Liu 652d3c9a738SXinliang Liu /* 653d3c9a738SXinliang Liu * clip width, no need to clip height 654d3c9a738SXinliang Liu */ 655d3c9a738SXinliang Liu if (fb_w == in_w) { /* bypass */ 656d3c9a738SXinliang Liu disable_val = 1; 657d3c9a738SXinliang Liu clip_left = 0; 658d3c9a738SXinliang Liu clip_right = 0; 659d3c9a738SXinliang Liu } else { 660d3c9a738SXinliang Liu disable_val = 0; 661d3c9a738SXinliang Liu clip_left = x; 662d3c9a738SXinliang Liu clip_right = fb_w - (x + in_w) - 1; 663d3c9a738SXinliang Liu } 664d3c9a738SXinliang Liu 665d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n", 666d3c9a738SXinliang Liu ch + 1, clip_left, clip_right); 667d3c9a738SXinliang Liu 668d3c9a738SXinliang Liu writel(disable_val, base + ADE_CLIP_DISABLE(ch)); 669d3c9a738SXinliang Liu writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch)); 670d3c9a738SXinliang Liu writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch)); 671d3c9a738SXinliang Liu ade_update_reload_bit(base, CLIP_OFST + ch, 0); 672d3c9a738SXinliang Liu } 673d3c9a738SXinliang Liu 674d3c9a738SXinliang Liu static void ade_clip_disable(void __iomem *base, u32 ch) 675d3c9a738SXinliang Liu { 676d3c9a738SXinliang Liu writel(1, base + ADE_CLIP_DISABLE(ch)); 677d3c9a738SXinliang Liu ade_update_reload_bit(base, CLIP_OFST + ch, 1); 678d3c9a738SXinliang Liu } 679d3c9a738SXinliang Liu 680d3c9a738SXinliang Liu static bool has_Alpha_channel(int format) 681d3c9a738SXinliang Liu { 682d3c9a738SXinliang Liu switch (format) { 683d3c9a738SXinliang Liu case ADE_ARGB_8888: 684d3c9a738SXinliang Liu case ADE_ABGR_8888: 685d3c9a738SXinliang Liu case ADE_RGBA_8888: 686d3c9a738SXinliang Liu case ADE_BGRA_8888: 687d3c9a738SXinliang Liu return true; 688d3c9a738SXinliang Liu default: 689d3c9a738SXinliang Liu return false; 690d3c9a738SXinliang Liu } 691d3c9a738SXinliang Liu } 692d3c9a738SXinliang Liu 693d3c9a738SXinliang Liu static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode, 694d3c9a738SXinliang Liu u8 *alp_sel, u8 *under_alp_sel) 695d3c9a738SXinliang Liu { 696d3c9a738SXinliang Liu bool has_alpha = has_Alpha_channel(fmt); 697d3c9a738SXinliang Liu 698d3c9a738SXinliang Liu /* 699d3c9a738SXinliang Liu * get alp_mode 700d3c9a738SXinliang Liu */ 701d3c9a738SXinliang Liu if (has_alpha && glb_alpha < 255) 702d3c9a738SXinliang Liu *alp_mode = ADE_ALP_PIXEL_AND_GLB; 703d3c9a738SXinliang Liu else if (has_alpha) 704d3c9a738SXinliang Liu *alp_mode = ADE_ALP_PIXEL; 705d3c9a738SXinliang Liu else 706d3c9a738SXinliang Liu *alp_mode = ADE_ALP_GLOBAL; 707d3c9a738SXinliang Liu 708d3c9a738SXinliang Liu /* 709d3c9a738SXinliang Liu * get alp sel 710d3c9a738SXinliang Liu */ 711d3c9a738SXinliang Liu *alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */ 712d3c9a738SXinliang Liu *under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */ 713d3c9a738SXinliang Liu } 714d3c9a738SXinliang Liu 715d3c9a738SXinliang Liu static void ade_compositor_routing_set(void __iomem *base, u8 ch, 716d3c9a738SXinliang Liu u32 x0, u32 y0, 717d3c9a738SXinliang Liu u32 in_w, u32 in_h, u32 fmt) 718d3c9a738SXinliang Liu { 719d3c9a738SXinliang Liu u8 ovly_ch = 0; /* TODO: This is the zpos, only one plane now */ 720d3c9a738SXinliang Liu u8 glb_alpha = 255; 721d3c9a738SXinliang Liu u32 x1 = x0 + in_w - 1; 722d3c9a738SXinliang Liu u32 y1 = y0 + in_h - 1; 723d3c9a738SXinliang Liu u32 val; 724d3c9a738SXinliang Liu u8 alp_sel; 725d3c9a738SXinliang Liu u8 under_alp_sel; 726d3c9a738SXinliang Liu u8 alp_mode; 727d3c9a738SXinliang Liu 728d3c9a738SXinliang Liu ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel, 729d3c9a738SXinliang Liu &under_alp_sel); 730d3c9a738SXinliang Liu 731d3c9a738SXinliang Liu /* overlay routing setting 732d3c9a738SXinliang Liu */ 733d3c9a738SXinliang Liu writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch)); 734d3c9a738SXinliang Liu writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch)); 735d3c9a738SXinliang Liu val = (ch + 1) << CH_SEL_OFST | BIT(CH_EN_OFST) | 736d3c9a738SXinliang Liu alp_sel << CH_ALP_SEL_OFST | 737d3c9a738SXinliang Liu under_alp_sel << CH_UNDER_ALP_SEL_OFST | 738d3c9a738SXinliang Liu glb_alpha << CH_ALP_GBL_OFST | 739d3c9a738SXinliang Liu alp_mode << CH_ALP_MODE_OFST; 740d3c9a738SXinliang Liu writel(val, base + ADE_OVLY_CH_CTL(ovly_ch)); 741d3c9a738SXinliang Liu /* connect this plane/channel to overlay2 compositor */ 742d3c9a738SXinliang Liu ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch), 743d3c9a738SXinliang Liu CH_OVLY_SEL_MASK, CH_OVLY_SEL_VAL(OUT_OVLY)); 744d3c9a738SXinliang Liu } 745d3c9a738SXinliang Liu 746d3c9a738SXinliang Liu static void ade_compositor_routing_disable(void __iomem *base, u32 ch) 747d3c9a738SXinliang Liu { 748d3c9a738SXinliang Liu u8 ovly_ch = 0; /* TODO: Only primary plane now */ 749d3c9a738SXinliang Liu 750d3c9a738SXinliang Liu /* disable this plane/channel */ 751d3c9a738SXinliang Liu ade_update_bits(base + ADE_OVLY_CH_CTL(ovly_ch), CH_EN_OFST, 752d3c9a738SXinliang Liu MASK(1), 0); 753d3c9a738SXinliang Liu /* dis-connect this plane/channel of overlay2 compositor */ 754d3c9a738SXinliang Liu ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch), 755d3c9a738SXinliang Liu CH_OVLY_SEL_MASK, 0); 756d3c9a738SXinliang Liu } 757d3c9a738SXinliang Liu 758d3c9a738SXinliang Liu /* 759d3c9a738SXinliang Liu * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->compositor 760d3c9a738SXinliang Liu */ 761d3c9a738SXinliang Liu static void ade_update_channel(struct ade_plane *aplane, 762d3c9a738SXinliang Liu struct drm_framebuffer *fb, int crtc_x, 763d3c9a738SXinliang Liu int crtc_y, unsigned int crtc_w, 764d3c9a738SXinliang Liu unsigned int crtc_h, u32 src_x, 765d3c9a738SXinliang Liu u32 src_y, u32 src_w, u32 src_h) 766d3c9a738SXinliang Liu { 767d3c9a738SXinliang Liu struct ade_hw_ctx *ctx = aplane->ctx; 768d3c9a738SXinliang Liu void __iomem *base = ctx->base; 769d3c9a738SXinliang Liu u32 fmt = ade_get_format(fb->pixel_format); 770d3c9a738SXinliang Liu u32 ch = aplane->ch; 771d3c9a738SXinliang Liu u32 in_w; 772d3c9a738SXinliang Liu u32 in_h; 773d3c9a738SXinliang Liu 774d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d", 775d3c9a738SXinliang Liu ch + 1, src_x, src_y, src_w, src_h, 776d3c9a738SXinliang Liu crtc_x, crtc_y, crtc_w, crtc_h); 777d3c9a738SXinliang Liu 778d3c9a738SXinliang Liu /* 1) DMA setting */ 779d3c9a738SXinliang Liu in_w = src_w; 780d3c9a738SXinliang Liu in_h = src_h; 781d3c9a738SXinliang Liu ade_rdma_set(base, fb, ch, src_y, in_h, fmt); 782d3c9a738SXinliang Liu 783d3c9a738SXinliang Liu /* 2) clip setting */ 784d3c9a738SXinliang Liu ade_clip_set(base, ch, fb->width, src_x, in_w, in_h); 785d3c9a738SXinliang Liu 786d3c9a738SXinliang Liu /* 3) TODO: scale setting for overlay planes */ 787d3c9a738SXinliang Liu 788d3c9a738SXinliang Liu /* 4) TODO: ctran/csc setting for overlay planes */ 789d3c9a738SXinliang Liu 790d3c9a738SXinliang Liu /* 5) compositor routing setting */ 791d3c9a738SXinliang Liu ade_compositor_routing_set(base, ch, crtc_x, crtc_y, in_w, in_h, fmt); 792d3c9a738SXinliang Liu } 793d3c9a738SXinliang Liu 794d3c9a738SXinliang Liu static void ade_disable_channel(struct ade_plane *aplane) 795d3c9a738SXinliang Liu { 796d3c9a738SXinliang Liu struct ade_hw_ctx *ctx = aplane->ctx; 797d3c9a738SXinliang Liu void __iomem *base = ctx->base; 798d3c9a738SXinliang Liu u32 ch = aplane->ch; 799d3c9a738SXinliang Liu 800d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1); 801d3c9a738SXinliang Liu 802d3c9a738SXinliang Liu /* disable read DMA */ 803d3c9a738SXinliang Liu ade_rdma_disable(base, ch); 804d3c9a738SXinliang Liu 805d3c9a738SXinliang Liu /* disable clip */ 806d3c9a738SXinliang Liu ade_clip_disable(base, ch); 807d3c9a738SXinliang Liu 808d3c9a738SXinliang Liu /* disable compositor routing */ 809d3c9a738SXinliang Liu ade_compositor_routing_disable(base, ch); 810d3c9a738SXinliang Liu } 811d3c9a738SXinliang Liu 812d3c9a738SXinliang Liu static int ade_plane_prepare_fb(struct drm_plane *plane, 813d3c9a738SXinliang Liu const struct drm_plane_state *new_state) 814d3c9a738SXinliang Liu { 815d3c9a738SXinliang Liu /* do nothing */ 816d3c9a738SXinliang Liu return 0; 817d3c9a738SXinliang Liu } 818d3c9a738SXinliang Liu 819d3c9a738SXinliang Liu static void ade_plane_cleanup_fb(struct drm_plane *plane, 820d3c9a738SXinliang Liu const struct drm_plane_state *old_state) 821d3c9a738SXinliang Liu { 822d3c9a738SXinliang Liu /* do nothing */ 823d3c9a738SXinliang Liu } 824d3c9a738SXinliang Liu 825d3c9a738SXinliang Liu static int ade_plane_atomic_check(struct drm_plane *plane, 826d3c9a738SXinliang Liu struct drm_plane_state *state) 827d3c9a738SXinliang Liu { 828d3c9a738SXinliang Liu struct drm_framebuffer *fb = state->fb; 829d3c9a738SXinliang Liu struct drm_crtc *crtc = state->crtc; 830d3c9a738SXinliang Liu struct drm_crtc_state *crtc_state; 831d3c9a738SXinliang Liu u32 src_x = state->src_x >> 16; 832d3c9a738SXinliang Liu u32 src_y = state->src_y >> 16; 833d3c9a738SXinliang Liu u32 src_w = state->src_w >> 16; 834d3c9a738SXinliang Liu u32 src_h = state->src_h >> 16; 835d3c9a738SXinliang Liu int crtc_x = state->crtc_x; 836d3c9a738SXinliang Liu int crtc_y = state->crtc_y; 837d3c9a738SXinliang Liu u32 crtc_w = state->crtc_w; 838d3c9a738SXinliang Liu u32 crtc_h = state->crtc_h; 839d3c9a738SXinliang Liu u32 fmt; 840d3c9a738SXinliang Liu 841d3c9a738SXinliang Liu if (!crtc || !fb) 842d3c9a738SXinliang Liu return 0; 843d3c9a738SXinliang Liu 844d3c9a738SXinliang Liu fmt = ade_get_format(fb->pixel_format); 845d3c9a738SXinliang Liu if (fmt == ADE_FORMAT_UNSUPPORT) 846d3c9a738SXinliang Liu return -EINVAL; 847d3c9a738SXinliang Liu 848d3c9a738SXinliang Liu crtc_state = drm_atomic_get_crtc_state(state->state, crtc); 849d3c9a738SXinliang Liu if (IS_ERR(crtc_state)) 850d3c9a738SXinliang Liu return PTR_ERR(crtc_state); 851d3c9a738SXinliang Liu 852d3c9a738SXinliang Liu if (src_w != crtc_w || src_h != crtc_h) { 853d3c9a738SXinliang Liu DRM_ERROR("Scale not support!!!\n"); 854d3c9a738SXinliang Liu return -EINVAL; 855d3c9a738SXinliang Liu } 856d3c9a738SXinliang Liu 857d3c9a738SXinliang Liu if (src_x + src_w > fb->width || 858d3c9a738SXinliang Liu src_y + src_h > fb->height) 859d3c9a738SXinliang Liu return -EINVAL; 860d3c9a738SXinliang Liu 861d3c9a738SXinliang Liu if (crtc_x < 0 || crtc_y < 0) 862d3c9a738SXinliang Liu return -EINVAL; 863d3c9a738SXinliang Liu 864d3c9a738SXinliang Liu if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay || 865d3c9a738SXinliang Liu crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay) 866d3c9a738SXinliang Liu return -EINVAL; 867d3c9a738SXinliang Liu 868d3c9a738SXinliang Liu return 0; 869d3c9a738SXinliang Liu } 870d3c9a738SXinliang Liu 871d3c9a738SXinliang Liu static void ade_plane_atomic_update(struct drm_plane *plane, 872d3c9a738SXinliang Liu struct drm_plane_state *old_state) 873d3c9a738SXinliang Liu { 874d3c9a738SXinliang Liu struct drm_plane_state *state = plane->state; 875d3c9a738SXinliang Liu struct ade_plane *aplane = to_ade_plane(plane); 876d3c9a738SXinliang Liu 877d3c9a738SXinliang Liu ade_update_channel(aplane, state->fb, state->crtc_x, state->crtc_y, 878d3c9a738SXinliang Liu state->crtc_w, state->crtc_h, 879d3c9a738SXinliang Liu state->src_x >> 16, state->src_y >> 16, 880d3c9a738SXinliang Liu state->src_w >> 16, state->src_h >> 16); 881d3c9a738SXinliang Liu } 882d3c9a738SXinliang Liu 883d3c9a738SXinliang Liu static void ade_plane_atomic_disable(struct drm_plane *plane, 884d3c9a738SXinliang Liu struct drm_plane_state *old_state) 885d3c9a738SXinliang Liu { 886d3c9a738SXinliang Liu struct ade_plane *aplane = to_ade_plane(plane); 887d3c9a738SXinliang Liu 888d3c9a738SXinliang Liu ade_disable_channel(aplane); 889d3c9a738SXinliang Liu } 890d3c9a738SXinliang Liu 891d3c9a738SXinliang Liu static const struct drm_plane_helper_funcs ade_plane_helper_funcs = { 892d3c9a738SXinliang Liu .prepare_fb = ade_plane_prepare_fb, 893d3c9a738SXinliang Liu .cleanup_fb = ade_plane_cleanup_fb, 894d3c9a738SXinliang Liu .atomic_check = ade_plane_atomic_check, 895d3c9a738SXinliang Liu .atomic_update = ade_plane_atomic_update, 896d3c9a738SXinliang Liu .atomic_disable = ade_plane_atomic_disable, 897d3c9a738SXinliang Liu }; 898d3c9a738SXinliang Liu 899d3c9a738SXinliang Liu static struct drm_plane_funcs ade_plane_funcs = { 900d3c9a738SXinliang Liu .update_plane = drm_atomic_helper_update_plane, 901d3c9a738SXinliang Liu .disable_plane = drm_atomic_helper_disable_plane, 902d3c9a738SXinliang Liu .set_property = drm_atomic_helper_plane_set_property, 903d3c9a738SXinliang Liu .destroy = drm_plane_cleanup, 904d3c9a738SXinliang Liu .reset = drm_atomic_helper_plane_reset, 905d3c9a738SXinliang Liu .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 906d3c9a738SXinliang Liu .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 907d3c9a738SXinliang Liu }; 908d3c9a738SXinliang Liu 909d3c9a738SXinliang Liu static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane, 910d3c9a738SXinliang Liu enum drm_plane_type type) 911d3c9a738SXinliang Liu { 912d3c9a738SXinliang Liu const u32 *fmts; 913d3c9a738SXinliang Liu u32 fmts_cnt; 914d3c9a738SXinliang Liu int ret = 0; 915d3c9a738SXinliang Liu 916d3c9a738SXinliang Liu /* get properties */ 917d3c9a738SXinliang Liu fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts); 918d3c9a738SXinliang Liu if (ret) 919d3c9a738SXinliang Liu return ret; 920d3c9a738SXinliang Liu 921d3c9a738SXinliang Liu ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs, 922d3c9a738SXinliang Liu fmts, fmts_cnt, type, NULL); 923d3c9a738SXinliang Liu if (ret) { 924d3c9a738SXinliang Liu DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch); 925d3c9a738SXinliang Liu return ret; 926d3c9a738SXinliang Liu } 927d3c9a738SXinliang Liu 928d3c9a738SXinliang Liu drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs); 929d3c9a738SXinliang Liu 930d3c9a738SXinliang Liu return 0; 931d3c9a738SXinliang Liu } 932d3c9a738SXinliang Liu 933783ad972SXinliang Liu static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx) 934783ad972SXinliang Liu { 935783ad972SXinliang Liu struct resource *res; 936783ad972SXinliang Liu struct device *dev = &pdev->dev; 937783ad972SXinliang Liu struct device_node *np = pdev->dev.of_node; 938783ad972SXinliang Liu 939783ad972SXinliang Liu res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 940783ad972SXinliang Liu ctx->base = devm_ioremap_resource(dev, res); 941783ad972SXinliang Liu if (IS_ERR(ctx->base)) { 942783ad972SXinliang Liu DRM_ERROR("failed to remap ade io base\n"); 943783ad972SXinliang Liu return PTR_ERR(ctx->base); 944783ad972SXinliang Liu } 945783ad972SXinliang Liu 946783ad972SXinliang Liu ctx->reset = devm_reset_control_get(dev, NULL); 947783ad972SXinliang Liu if (IS_ERR(ctx->reset)) 948783ad972SXinliang Liu return PTR_ERR(ctx->reset); 949783ad972SXinliang Liu 950783ad972SXinliang Liu ctx->noc_regmap = 951783ad972SXinliang Liu syscon_regmap_lookup_by_phandle(np, "hisilicon,noc-syscon"); 952783ad972SXinliang Liu if (IS_ERR(ctx->noc_regmap)) { 953783ad972SXinliang Liu DRM_ERROR("failed to get noc regmap\n"); 954783ad972SXinliang Liu return PTR_ERR(ctx->noc_regmap); 955783ad972SXinliang Liu } 956783ad972SXinliang Liu 957783ad972SXinliang Liu ctx->irq = platform_get_irq(pdev, 0); 958783ad972SXinliang Liu if (ctx->irq < 0) { 959783ad972SXinliang Liu DRM_ERROR("failed to get irq\n"); 960783ad972SXinliang Liu return -ENODEV; 961783ad972SXinliang Liu } 962783ad972SXinliang Liu 963783ad972SXinliang Liu ctx->ade_core_clk = devm_clk_get(dev, "clk_ade_core"); 964783ad972SXinliang Liu if (!ctx->ade_core_clk) { 965783ad972SXinliang Liu DRM_ERROR("failed to parse clk ADE_CORE\n"); 966783ad972SXinliang Liu return -ENODEV; 967783ad972SXinliang Liu } 968783ad972SXinliang Liu 969783ad972SXinliang Liu ctx->media_noc_clk = devm_clk_get(dev, "clk_codec_jpeg"); 970783ad972SXinliang Liu if (!ctx->media_noc_clk) { 971783ad972SXinliang Liu DRM_ERROR("failed to parse clk CODEC_JPEG\n"); 972783ad972SXinliang Liu return -ENODEV; 973783ad972SXinliang Liu } 974783ad972SXinliang Liu 975783ad972SXinliang Liu ctx->ade_pix_clk = devm_clk_get(dev, "clk_ade_pix"); 976783ad972SXinliang Liu if (!ctx->ade_pix_clk) { 977783ad972SXinliang Liu DRM_ERROR("failed to parse clk ADE_PIX\n"); 978783ad972SXinliang Liu return -ENODEV; 979783ad972SXinliang Liu } 980783ad972SXinliang Liu 981783ad972SXinliang Liu return 0; 982783ad972SXinliang Liu } 983783ad972SXinliang Liu 984783ad972SXinliang Liu static int ade_drm_init(struct drm_device *dev) 985783ad972SXinliang Liu { 986783ad972SXinliang Liu struct platform_device *pdev = dev->platformdev; 987783ad972SXinliang Liu struct ade_data *ade; 988783ad972SXinliang Liu struct ade_hw_ctx *ctx; 989783ad972SXinliang Liu struct ade_crtc *acrtc; 990d3c9a738SXinliang Liu struct ade_plane *aplane; 991d3c9a738SXinliang Liu enum drm_plane_type type; 992783ad972SXinliang Liu int ret; 993d3c9a738SXinliang Liu int i; 994783ad972SXinliang Liu 995783ad972SXinliang Liu ade = devm_kzalloc(dev->dev, sizeof(*ade), GFP_KERNEL); 996783ad972SXinliang Liu if (!ade) { 997783ad972SXinliang Liu DRM_ERROR("failed to alloc ade_data\n"); 998783ad972SXinliang Liu return -ENOMEM; 999783ad972SXinliang Liu } 1000783ad972SXinliang Liu platform_set_drvdata(pdev, ade); 1001783ad972SXinliang Liu 1002783ad972SXinliang Liu ctx = &ade->ctx; 1003783ad972SXinliang Liu acrtc = &ade->acrtc; 1004783ad972SXinliang Liu acrtc->ctx = ctx; 1005783ad972SXinliang Liu acrtc->out_format = LDI_OUT_RGB_888; 1006783ad972SXinliang Liu 1007783ad972SXinliang Liu ret = ade_dts_parse(pdev, ctx); 1008783ad972SXinliang Liu if (ret) 1009783ad972SXinliang Liu return ret; 1010783ad972SXinliang Liu 1011d3c9a738SXinliang Liu /* 1012d3c9a738SXinliang Liu * plane init 1013d3c9a738SXinliang Liu * TODO: Now only support primary plane, overlay planes 1014d3c9a738SXinliang Liu * need to do. 1015d3c9a738SXinliang Liu */ 1016d3c9a738SXinliang Liu for (i = 0; i < ADE_CH_NUM; i++) { 1017d3c9a738SXinliang Liu aplane = &ade->aplane[i]; 1018d3c9a738SXinliang Liu aplane->ch = i; 1019d3c9a738SXinliang Liu aplane->ctx = ctx; 1020d3c9a738SXinliang Liu type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY : 1021d3c9a738SXinliang Liu DRM_PLANE_TYPE_OVERLAY; 1022d3c9a738SXinliang Liu 1023d3c9a738SXinliang Liu ret = ade_plane_init(dev, aplane, type); 1024d3c9a738SXinliang Liu if (ret) 1025d3c9a738SXinliang Liu return ret; 1026d3c9a738SXinliang Liu } 1027d3c9a738SXinliang Liu 1028d3c9a738SXinliang Liu /* crtc init */ 1029d3c9a738SXinliang Liu ret = ade_crtc_init(dev, &acrtc->base, &ade->aplane[PRIMARY_CH].base); 1030d3c9a738SXinliang Liu if (ret) 1031d3c9a738SXinliang Liu return ret; 1032d3c9a738SXinliang Liu 1033bc4611e8SXinliang Liu /* vblank irq init */ 1034bc4611e8SXinliang Liu ret = devm_request_irq(dev->dev, ctx->irq, ade_irq_handler, 1035bc4611e8SXinliang Liu IRQF_SHARED, dev->driver->name, acrtc); 1036bc4611e8SXinliang Liu if (ret) 1037bc4611e8SXinliang Liu return ret; 1038bc4611e8SXinliang Liu dev->driver->get_vblank_counter = drm_vblank_no_hw_counter; 1039bc4611e8SXinliang Liu dev->driver->enable_vblank = ade_enable_vblank; 1040bc4611e8SXinliang Liu dev->driver->disable_vblank = ade_disable_vblank; 1041bc4611e8SXinliang Liu 1042783ad972SXinliang Liu return 0; 1043783ad972SXinliang Liu } 1044783ad972SXinliang Liu 1045783ad972SXinliang Liu static void ade_drm_cleanup(struct drm_device *dev) 1046783ad972SXinliang Liu { 1047783ad972SXinliang Liu struct platform_device *pdev = dev->platformdev; 1048783ad972SXinliang Liu struct ade_data *ade = platform_get_drvdata(pdev); 1049783ad972SXinliang Liu struct drm_crtc *crtc = &ade->acrtc.base; 1050783ad972SXinliang Liu 1051783ad972SXinliang Liu drm_crtc_cleanup(crtc); 1052783ad972SXinliang Liu } 1053783ad972SXinliang Liu 1054783ad972SXinliang Liu const struct kirin_dc_ops ade_dc_ops = { 1055783ad972SXinliang Liu .init = ade_drm_init, 1056783ad972SXinliang Liu .cleanup = ade_drm_cleanup 1057783ad972SXinliang Liu }; 1058