1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2783ad972SXinliang Liu /* 3783ad972SXinliang Liu * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver 4783ad972SXinliang Liu * 5783ad972SXinliang Liu * Copyright (c) 2016 Linaro Limited. 6783ad972SXinliang Liu * Copyright (c) 2014-2016 Hisilicon Limited. 7783ad972SXinliang Liu * 8783ad972SXinliang Liu * Author: 9783ad972SXinliang Liu * Xinliang Liu <z.liuxinliang@hisilicon.com> 10783ad972SXinliang Liu * Xinliang Liu <xinliang.liu@linaro.org> 11783ad972SXinliang Liu * Xinwei Kong <kong.kongxinwei@hisilicon.com> 12783ad972SXinliang Liu */ 13783ad972SXinliang Liu 14783ad972SXinliang Liu #include <linux/bitops.h> 15783ad972SXinliang Liu #include <linux/clk.h> 16783ad972SXinliang Liu #include <linux/mfd/syscon.h> 1740b4db43SSam Ravnborg #include <linux/platform_device.h> 18783ad972SXinliang Liu #include <linux/regmap.h> 19783ad972SXinliang Liu #include <linux/reset.h> 20783ad972SXinliang Liu 2140b4db43SSam Ravnborg #include <video/display_timing.h> 2240b4db43SSam Ravnborg 23783ad972SXinliang Liu #include <drm/drm_atomic.h> 24783ad972SXinliang Liu #include <drm/drm_atomic_helper.h> 25fcd70cd3SDaniel Vetter #include <drm/drm_crtc.h> 2640b4db43SSam Ravnborg #include <drm/drm_drv.h> 27d3c9a738SXinliang Liu #include <drm/drm_fb_cma_helper.h> 2840b4db43SSam Ravnborg #include <drm/drm_fourcc.h> 29fcd70cd3SDaniel Vetter #include <drm/drm_gem_cma_helper.h> 30fcd70cd3SDaniel Vetter #include <drm/drm_plane_helper.h> 31fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 3240b4db43SSam Ravnborg #include <drm/drm_vblank.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 41ada7f67dSXu YiPing #define to_kirin_crtc(crtc) \ 42ada7f67dSXu YiPing container_of(crtc, struct kirin_crtc, base) 43783ad972SXinliang Liu 440ae622c5SXu YiPing #define to_kirin_plane(plane) \ 450ae622c5SXu YiPing container_of(plane, struct kirin_plane, base) 460ae622c5SXu YiPing 47d3c9a738SXinliang Liu 48783ad972SXinliang Liu struct ade_hw_ctx { 49783ad972SXinliang Liu void __iomem *base; 50783ad972SXinliang Liu struct regmap *noc_regmap; 51783ad972SXinliang Liu struct clk *ade_core_clk; 52783ad972SXinliang Liu struct clk *media_noc_clk; 53783ad972SXinliang Liu struct clk *ade_pix_clk; 54783ad972SXinliang Liu struct reset_control *reset; 55783ad972SXinliang Liu bool power_on; 56783ad972SXinliang Liu int irq; 57783ad972SXinliang Liu }; 58783ad972SXinliang Liu 59ada7f67dSXu YiPing struct kirin_crtc { 60783ad972SXinliang Liu struct drm_crtc base; 61ada7f67dSXu YiPing void *hw_ctx; 62ff57c651SDa Lv struct work_struct display_reset_wq; 63783ad972SXinliang Liu bool enable; 64783ad972SXinliang Liu }; 65783ad972SXinliang Liu 660ae622c5SXu YiPing struct kirin_plane { 67d3c9a738SXinliang Liu struct drm_plane base; 680ae622c5SXu YiPing void *hw_ctx; 690ae622c5SXu YiPing u32 ch; 70d3c9a738SXinliang Liu }; 71d3c9a738SXinliang Liu 72783ad972SXinliang Liu struct ade_data { 73ada7f67dSXu YiPing struct kirin_crtc crtc; 740ae622c5SXu YiPing struct kirin_plane planes[ADE_CH_NUM]; 75783ad972SXinliang Liu struct ade_hw_ctx ctx; 76783ad972SXinliang Liu }; 77783ad972SXinliang Liu 78d3c9a738SXinliang Liu /* ade-format info: */ 79d3c9a738SXinliang Liu struct ade_format { 80d3c9a738SXinliang Liu u32 pixel_format; 81d3c9a738SXinliang Liu enum ade_fb_format ade_format; 82d3c9a738SXinliang Liu }; 83d3c9a738SXinliang Liu 84d3c9a738SXinliang Liu static const struct ade_format ade_formats[] = { 85d3c9a738SXinliang Liu /* 16bpp RGB: */ 86d3c9a738SXinliang Liu { DRM_FORMAT_RGB565, ADE_RGB_565 }, 87d3c9a738SXinliang Liu { DRM_FORMAT_BGR565, ADE_BGR_565 }, 88d3c9a738SXinliang Liu /* 24bpp RGB: */ 89d3c9a738SXinliang Liu { DRM_FORMAT_RGB888, ADE_RGB_888 }, 90d3c9a738SXinliang Liu { DRM_FORMAT_BGR888, ADE_BGR_888 }, 91d3c9a738SXinliang Liu /* 32bpp [A]RGB: */ 92d3c9a738SXinliang Liu { DRM_FORMAT_XRGB8888, ADE_XRGB_8888 }, 93d3c9a738SXinliang Liu { DRM_FORMAT_XBGR8888, ADE_XBGR_8888 }, 94d3c9a738SXinliang Liu { DRM_FORMAT_RGBA8888, ADE_RGBA_8888 }, 95d3c9a738SXinliang Liu { DRM_FORMAT_BGRA8888, ADE_BGRA_8888 }, 96d3c9a738SXinliang Liu { DRM_FORMAT_ARGB8888, ADE_ARGB_8888 }, 97d3c9a738SXinliang Liu { DRM_FORMAT_ABGR8888, ADE_ABGR_8888 }, 98d3c9a738SXinliang Liu }; 99d3c9a738SXinliang Liu 100d3c9a738SXinliang Liu static const u32 channel_formats1[] = { 101d3c9a738SXinliang Liu /* channel 1,2,3,4 */ 102d3c9a738SXinliang Liu DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888, 103d3c9a738SXinliang Liu DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, 104d3c9a738SXinliang Liu DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888, 105d3c9a738SXinliang Liu DRM_FORMAT_ABGR8888 106d3c9a738SXinliang Liu }; 107d3c9a738SXinliang Liu 108d3c9a738SXinliang Liu u32 ade_get_channel_formats(u8 ch, const u32 **formats) 109d3c9a738SXinliang Liu { 110d3c9a738SXinliang Liu switch (ch) { 111d3c9a738SXinliang Liu case ADE_CH1: 112d3c9a738SXinliang Liu *formats = channel_formats1; 113d3c9a738SXinliang Liu return ARRAY_SIZE(channel_formats1); 114d3c9a738SXinliang Liu default: 115d3c9a738SXinliang Liu DRM_ERROR("no this channel %d\n", ch); 116d3c9a738SXinliang Liu *formats = NULL; 117d3c9a738SXinliang Liu return 0; 118d3c9a738SXinliang Liu } 119d3c9a738SXinliang Liu } 120d3c9a738SXinliang Liu 121d3c9a738SXinliang Liu /* convert from fourcc format to ade format */ 122d3c9a738SXinliang Liu static u32 ade_get_format(u32 pixel_format) 123d3c9a738SXinliang Liu { 124d3c9a738SXinliang Liu int i; 125d3c9a738SXinliang Liu 126d3c9a738SXinliang Liu for (i = 0; i < ARRAY_SIZE(ade_formats); i++) 127d3c9a738SXinliang Liu if (ade_formats[i].pixel_format == pixel_format) 128d3c9a738SXinliang Liu return ade_formats[i].ade_format; 129d3c9a738SXinliang Liu 130d3c9a738SXinliang Liu /* not found */ 131d3c9a738SXinliang Liu DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", 132d3c9a738SXinliang Liu pixel_format); 133d3c9a738SXinliang Liu return ADE_FORMAT_UNSUPPORT; 134d3c9a738SXinliang Liu } 135d3c9a738SXinliang Liu 136783ad972SXinliang Liu static void ade_update_reload_bit(void __iomem *base, u32 bit_num, u32 val) 137783ad972SXinliang Liu { 138783ad972SXinliang Liu u32 bit_ofst, reg_num; 139783ad972SXinliang Liu 140783ad972SXinliang Liu bit_ofst = bit_num % 32; 141783ad972SXinliang Liu reg_num = bit_num / 32; 142783ad972SXinliang Liu 143783ad972SXinliang Liu ade_update_bits(base + ADE_RELOAD_DIS(reg_num), bit_ofst, 144783ad972SXinliang Liu MASK(1), !!val); 145783ad972SXinliang Liu } 146783ad972SXinliang Liu 147783ad972SXinliang Liu static u32 ade_read_reload_bit(void __iomem *base, u32 bit_num) 148783ad972SXinliang Liu { 149783ad972SXinliang Liu u32 tmp, bit_ofst, reg_num; 150783ad972SXinliang Liu 151783ad972SXinliang Liu bit_ofst = bit_num % 32; 152783ad972SXinliang Liu reg_num = bit_num / 32; 153783ad972SXinliang Liu 154783ad972SXinliang Liu tmp = readl(base + ADE_RELOAD_DIS(reg_num)); 155783ad972SXinliang Liu return !!(BIT(bit_ofst) & tmp); 156783ad972SXinliang Liu } 157783ad972SXinliang Liu 158783ad972SXinliang Liu static void ade_init(struct ade_hw_ctx *ctx) 159783ad972SXinliang Liu { 160783ad972SXinliang Liu void __iomem *base = ctx->base; 161783ad972SXinliang Liu 162783ad972SXinliang Liu /* enable clk gate */ 163783ad972SXinliang Liu ade_update_bits(base + ADE_CTRL1, AUTO_CLK_GATE_EN_OFST, 164783ad972SXinliang Liu AUTO_CLK_GATE_EN, ADE_ENABLE); 165783ad972SXinliang Liu /* clear overlay */ 166783ad972SXinliang Liu writel(0, base + ADE_OVLY1_TRANS_CFG); 167783ad972SXinliang Liu writel(0, base + ADE_OVLY_CTL); 168d3c9a738SXinliang Liu writel(0, base + ADE_OVLYX_CTL(OUT_OVLY)); 169783ad972SXinliang Liu /* clear reset and reload regs */ 170783ad972SXinliang Liu writel(MASK(32), base + ADE_SOFT_RST_SEL(0)); 171783ad972SXinliang Liu writel(MASK(32), base + ADE_SOFT_RST_SEL(1)); 172783ad972SXinliang Liu writel(MASK(32), base + ADE_RELOAD_DIS(0)); 173783ad972SXinliang Liu writel(MASK(32), base + ADE_RELOAD_DIS(1)); 174783ad972SXinliang Liu /* 175783ad972SXinliang Liu * for video mode, all the ade registers should 176783ad972SXinliang Liu * become effective at frame end. 177783ad972SXinliang Liu */ 178783ad972SXinliang Liu ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST, 179783ad972SXinliang Liu FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND); 180ff57c651SDa Lv ade_update_bits(base + LDI_INT_EN, UNDERFLOW_INT_EN_OFST, MASK(1), 1); 181783ad972SXinliang Liu } 182783ad972SXinliang Liu 18371f23543SJohn Stultz static bool ade_crtc_mode_fixup(struct drm_crtc *crtc, 18471f23543SJohn Stultz const struct drm_display_mode *mode, 18571f23543SJohn Stultz struct drm_display_mode *adjusted_mode) 18671f23543SJohn Stultz { 187ada7f67dSXu YiPing struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); 188ada7f67dSXu YiPing struct ade_hw_ctx *ctx = kcrtc->hw_ctx; 18971f23543SJohn Stultz 19071f23543SJohn Stultz adjusted_mode->clock = 19171f23543SJohn Stultz clk_round_rate(ctx->ade_pix_clk, mode->clock * 1000) / 1000; 19271f23543SJohn Stultz return true; 19371f23543SJohn Stultz } 19471f23543SJohn Stultz 19571f23543SJohn Stultz 196783ad972SXinliang Liu static void ade_set_pix_clk(struct ade_hw_ctx *ctx, 197783ad972SXinliang Liu struct drm_display_mode *mode, 198783ad972SXinliang Liu struct drm_display_mode *adj_mode) 199783ad972SXinliang Liu { 200783ad972SXinliang Liu u32 clk_Hz = mode->clock * 1000; 201783ad972SXinliang Liu int ret; 202783ad972SXinliang Liu 203783ad972SXinliang Liu /* 204783ad972SXinliang Liu * Success should be guaranteed in mode_valid call back, 205783ad972SXinliang Liu * so failure shouldn't happen here 206783ad972SXinliang Liu */ 207783ad972SXinliang Liu ret = clk_set_rate(ctx->ade_pix_clk, clk_Hz); 208783ad972SXinliang Liu if (ret) 209783ad972SXinliang Liu DRM_ERROR("failed to set pixel clk %dHz (%d)\n", clk_Hz, ret); 210783ad972SXinliang Liu adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000; 211783ad972SXinliang Liu } 212783ad972SXinliang Liu 213e0d8eba5SXu YiPing static void ade_ldi_set_mode(struct ade_hw_ctx *ctx, 214783ad972SXinliang Liu struct drm_display_mode *mode, 215783ad972SXinliang Liu struct drm_display_mode *adj_mode) 216783ad972SXinliang Liu { 217783ad972SXinliang Liu void __iomem *base = ctx->base; 218783ad972SXinliang Liu u32 width = mode->hdisplay; 219783ad972SXinliang Liu u32 height = mode->vdisplay; 220783ad972SXinliang Liu u32 hfp, hbp, hsw, vfp, vbp, vsw; 221783ad972SXinliang Liu u32 plr_flags; 222783ad972SXinliang Liu 223783ad972SXinliang Liu plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? FLAG_NVSYNC : 0; 224783ad972SXinliang Liu plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC) ? FLAG_NHSYNC : 0; 225783ad972SXinliang Liu hfp = mode->hsync_start - mode->hdisplay; 226783ad972SXinliang Liu hbp = mode->htotal - mode->hsync_end; 227783ad972SXinliang Liu hsw = mode->hsync_end - mode->hsync_start; 228783ad972SXinliang Liu vfp = mode->vsync_start - mode->vdisplay; 229783ad972SXinliang Liu vbp = mode->vtotal - mode->vsync_end; 230783ad972SXinliang Liu vsw = mode->vsync_end - mode->vsync_start; 231783ad972SXinliang Liu if (vsw > 15) { 232783ad972SXinliang Liu DRM_DEBUG_DRIVER("vsw exceeded 15\n"); 233783ad972SXinliang Liu vsw = 15; 234783ad972SXinliang Liu } 235783ad972SXinliang Liu 236783ad972SXinliang Liu writel((hbp << HBP_OFST) | hfp, base + LDI_HRZ_CTRL0); 237783ad972SXinliang Liu /* the configured value is actual value - 1 */ 238783ad972SXinliang Liu writel(hsw - 1, base + LDI_HRZ_CTRL1); 239783ad972SXinliang Liu writel((vbp << VBP_OFST) | vfp, base + LDI_VRT_CTRL0); 240783ad972SXinliang Liu /* the configured value is actual value - 1 */ 241783ad972SXinliang Liu writel(vsw - 1, base + LDI_VRT_CTRL1); 242783ad972SXinliang Liu /* the configured value is actual value - 1 */ 243783ad972SXinliang Liu writel(((height - 1) << VSIZE_OFST) | (width - 1), 244783ad972SXinliang Liu base + LDI_DSP_SIZE); 245783ad972SXinliang Liu writel(plr_flags, base + LDI_PLR_CTRL); 246783ad972SXinliang Liu 247d3c9a738SXinliang Liu /* set overlay compositor output size */ 248d3c9a738SXinliang Liu writel(((width - 1) << OUTPUT_XSIZE_OFST) | (height - 1), 249d3c9a738SXinliang Liu base + ADE_OVLY_OUTPUT_SIZE(OUT_OVLY)); 250d3c9a738SXinliang Liu 251783ad972SXinliang Liu /* ctran6 setting */ 252783ad972SXinliang Liu writel(CTRAN_BYPASS_ON, base + ADE_CTRAN_DIS(ADE_CTRAN6)); 253783ad972SXinliang Liu /* the configured value is actual value - 1 */ 254783ad972SXinliang Liu writel(width * height - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6)); 255783ad972SXinliang Liu ade_update_reload_bit(base, CTRAN_OFST + ADE_CTRAN6, 0); 256783ad972SXinliang Liu 257783ad972SXinliang Liu ade_set_pix_clk(ctx, mode, adj_mode); 258783ad972SXinliang Liu 259783ad972SXinliang Liu DRM_DEBUG_DRIVER("set mode: %dx%d\n", width, height); 260783ad972SXinliang Liu } 261783ad972SXinliang Liu 262783ad972SXinliang Liu static int ade_power_up(struct ade_hw_ctx *ctx) 263783ad972SXinliang Liu { 264783ad972SXinliang Liu int ret; 265783ad972SXinliang Liu 266783ad972SXinliang Liu ret = clk_prepare_enable(ctx->media_noc_clk); 267783ad972SXinliang Liu if (ret) { 268783ad972SXinliang Liu DRM_ERROR("failed to enable media_noc_clk (%d)\n", ret); 269783ad972SXinliang Liu return ret; 270783ad972SXinliang Liu } 271783ad972SXinliang Liu 272783ad972SXinliang Liu ret = reset_control_deassert(ctx->reset); 273783ad972SXinliang Liu if (ret) { 274783ad972SXinliang Liu DRM_ERROR("failed to deassert reset\n"); 275783ad972SXinliang Liu return ret; 276783ad972SXinliang Liu } 277783ad972SXinliang Liu 278783ad972SXinliang Liu ret = clk_prepare_enable(ctx->ade_core_clk); 279783ad972SXinliang Liu if (ret) { 280783ad972SXinliang Liu DRM_ERROR("failed to enable ade_core_clk (%d)\n", ret); 281783ad972SXinliang Liu return ret; 282783ad972SXinliang Liu } 283783ad972SXinliang Liu 284783ad972SXinliang Liu ade_init(ctx); 285783ad972SXinliang Liu ctx->power_on = true; 286783ad972SXinliang Liu return 0; 287783ad972SXinliang Liu } 288783ad972SXinliang Liu 289783ad972SXinliang Liu static void ade_power_down(struct ade_hw_ctx *ctx) 290783ad972SXinliang Liu { 291783ad972SXinliang Liu void __iomem *base = ctx->base; 292783ad972SXinliang Liu 293783ad972SXinliang Liu writel(ADE_DISABLE, base + LDI_CTRL); 294783ad972SXinliang Liu /* dsi pixel off */ 295783ad972SXinliang Liu writel(DSI_PCLK_OFF, base + LDI_HDMI_DSI_GT); 296783ad972SXinliang Liu 297783ad972SXinliang Liu clk_disable_unprepare(ctx->ade_core_clk); 298783ad972SXinliang Liu reset_control_assert(ctx->reset); 299783ad972SXinliang Liu clk_disable_unprepare(ctx->media_noc_clk); 300783ad972SXinliang Liu ctx->power_on = false; 301783ad972SXinliang Liu } 302783ad972SXinliang Liu 303e0d8eba5SXu YiPing static void ade_set_medianoc_qos(struct ade_hw_ctx *ctx) 304783ad972SXinliang Liu { 305783ad972SXinliang Liu struct regmap *map = ctx->noc_regmap; 306783ad972SXinliang Liu 307783ad972SXinliang Liu regmap_update_bits(map, ADE0_QOSGENERATOR_MODE, 308783ad972SXinliang Liu QOSGENERATOR_MODE_MASK, BYPASS_MODE); 309783ad972SXinliang Liu regmap_update_bits(map, ADE0_QOSGENERATOR_EXTCONTROL, 310783ad972SXinliang Liu SOCKET_QOS_EN, SOCKET_QOS_EN); 311783ad972SXinliang Liu 312783ad972SXinliang Liu regmap_update_bits(map, ADE1_QOSGENERATOR_MODE, 313783ad972SXinliang Liu QOSGENERATOR_MODE_MASK, BYPASS_MODE); 314783ad972SXinliang Liu regmap_update_bits(map, ADE1_QOSGENERATOR_EXTCONTROL, 315783ad972SXinliang Liu SOCKET_QOS_EN, SOCKET_QOS_EN); 316783ad972SXinliang Liu } 317783ad972SXinliang Liu 318d4f6750fSShawn Guo static int ade_crtc_enable_vblank(struct drm_crtc *crtc) 319bc4611e8SXinliang Liu { 320ada7f67dSXu YiPing struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); 321ada7f67dSXu YiPing struct ade_hw_ctx *ctx = kcrtc->hw_ctx; 322bc4611e8SXinliang Liu void __iomem *base = ctx->base; 323bc4611e8SXinliang Liu 324bc4611e8SXinliang Liu if (!ctx->power_on) 325bc4611e8SXinliang Liu (void)ade_power_up(ctx); 326bc4611e8SXinliang Liu 327bc4611e8SXinliang Liu ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST, 328bc4611e8SXinliang Liu MASK(1), 1); 329bc4611e8SXinliang Liu 330bc4611e8SXinliang Liu return 0; 331bc4611e8SXinliang Liu } 332bc4611e8SXinliang Liu 333d4f6750fSShawn Guo static void ade_crtc_disable_vblank(struct drm_crtc *crtc) 334bc4611e8SXinliang Liu { 335ada7f67dSXu YiPing struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); 336ada7f67dSXu YiPing struct ade_hw_ctx *ctx = kcrtc->hw_ctx; 337bc4611e8SXinliang Liu void __iomem *base = ctx->base; 338bc4611e8SXinliang Liu 339bc4611e8SXinliang Liu if (!ctx->power_on) { 340bc4611e8SXinliang Liu DRM_ERROR("power is down! vblank disable fail\n"); 341bc4611e8SXinliang Liu return; 342bc4611e8SXinliang Liu } 343bc4611e8SXinliang Liu 344bc4611e8SXinliang Liu ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST, 345bc4611e8SXinliang Liu MASK(1), 0); 346bc4611e8SXinliang Liu } 347bc4611e8SXinliang Liu 348ff57c651SDa Lv static void drm_underflow_wq(struct work_struct *work) 349ff57c651SDa Lv { 350ada7f67dSXu YiPing struct kirin_crtc *acrtc = container_of(work, struct kirin_crtc, 351ff57c651SDa Lv display_reset_wq); 352ff57c651SDa Lv struct drm_device *drm_dev = (&acrtc->base)->dev; 353ff57c651SDa Lv struct drm_atomic_state *state; 354ff57c651SDa Lv 355ff57c651SDa Lv state = drm_atomic_helper_suspend(drm_dev); 356ff57c651SDa Lv drm_atomic_helper_resume(drm_dev, state); 357ff57c651SDa Lv } 358ff57c651SDa Lv 359bc4611e8SXinliang Liu static irqreturn_t ade_irq_handler(int irq, void *data) 360bc4611e8SXinliang Liu { 361ada7f67dSXu YiPing struct kirin_crtc *kcrtc = data; 362ada7f67dSXu YiPing struct ade_hw_ctx *ctx = kcrtc->hw_ctx; 363ada7f67dSXu YiPing struct drm_crtc *crtc = &kcrtc->base; 364bc4611e8SXinliang Liu void __iomem *base = ctx->base; 365bc4611e8SXinliang Liu u32 status; 366bc4611e8SXinliang Liu 367bc4611e8SXinliang Liu status = readl(base + LDI_MSK_INT); 368bc4611e8SXinliang Liu DRM_DEBUG_VBL("LDI IRQ: status=0x%X\n", status); 369bc4611e8SXinliang Liu 370bc4611e8SXinliang Liu /* vblank irq */ 371bc4611e8SXinliang Liu if (status & BIT(FRAME_END_INT_EN_OFST)) { 372bc4611e8SXinliang Liu ade_update_bits(base + LDI_INT_CLR, FRAME_END_INT_EN_OFST, 373bc4611e8SXinliang Liu MASK(1), 1); 374bc4611e8SXinliang Liu drm_crtc_handle_vblank(crtc); 375bc4611e8SXinliang Liu } 376ff57c651SDa Lv if (status & BIT(UNDERFLOW_INT_EN_OFST)) { 377ff57c651SDa Lv ade_update_bits(base + LDI_INT_CLR, UNDERFLOW_INT_EN_OFST, 378ff57c651SDa Lv MASK(1), 1); 379ff57c651SDa Lv DRM_ERROR("LDI underflow!"); 380ada7f67dSXu YiPing schedule_work(&kcrtc->display_reset_wq); 381ff57c651SDa Lv } 382bc4611e8SXinliang Liu 383bc4611e8SXinliang Liu return IRQ_HANDLED; 384bc4611e8SXinliang Liu } 385bc4611e8SXinliang Liu 386a202da16SXu YiPing static void ade_display_enable(struct ade_hw_ctx *ctx) 387783ad972SXinliang Liu { 388783ad972SXinliang Liu void __iomem *base = ctx->base; 389a202da16SXu YiPing u32 out_fmt = LDI_OUT_RGB_888; 390783ad972SXinliang Liu 391d3c9a738SXinliang Liu /* enable output overlay compositor */ 392d3c9a738SXinliang Liu writel(ADE_ENABLE, base + ADE_OVLYX_CTL(OUT_OVLY)); 393d3c9a738SXinliang Liu ade_update_reload_bit(base, OVLY_OFST + OUT_OVLY, 0); 394d3c9a738SXinliang Liu 395783ad972SXinliang Liu /* display source setting */ 396783ad972SXinliang Liu writel(DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG); 397783ad972SXinliang Liu 398783ad972SXinliang Liu /* enable ade */ 399783ad972SXinliang Liu writel(ADE_ENABLE, base + ADE_EN); 400783ad972SXinliang Liu /* enable ldi */ 401783ad972SXinliang Liu writel(NORMAL_MODE, base + LDI_WORK_MODE); 402783ad972SXinliang Liu writel((out_fmt << BPP_OFST) | DATA_GATE_EN | LDI_EN, 403783ad972SXinliang Liu base + LDI_CTRL); 404783ad972SXinliang Liu /* dsi pixel on */ 405783ad972SXinliang Liu writel(DSI_PCLK_ON, base + LDI_HDMI_DSI_GT); 406783ad972SXinliang Liu } 407783ad972SXinliang Liu 408d3c9a738SXinliang Liu #if ADE_DEBUG 409d3c9a738SXinliang Liu static void ade_rdma_dump_regs(void __iomem *base, u32 ch) 410d3c9a738SXinliang Liu { 411d3c9a738SXinliang Liu u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en; 412d3c9a738SXinliang Liu u32 val; 413d3c9a738SXinliang Liu 414d3c9a738SXinliang Liu reg_ctrl = RD_CH_CTRL(ch); 415d3c9a738SXinliang Liu reg_addr = RD_CH_ADDR(ch); 416d3c9a738SXinliang Liu reg_size = RD_CH_SIZE(ch); 417d3c9a738SXinliang Liu reg_stride = RD_CH_STRIDE(ch); 418d3c9a738SXinliang Liu reg_space = RD_CH_SPACE(ch); 419d3c9a738SXinliang Liu reg_en = RD_CH_EN(ch); 420d3c9a738SXinliang Liu 421d3c9a738SXinliang Liu val = ade_read_reload_bit(base, RDMA_OFST + ch); 422d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reload(%d)\n", ch + 1, val); 423d3c9a738SXinliang Liu val = readl(base + reg_ctrl); 424d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_ctrl(0x%08x)\n", ch + 1, val); 425d3c9a738SXinliang Liu val = readl(base + reg_addr); 426d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_addr(0x%08x)\n", ch + 1, val); 427d3c9a738SXinliang Liu val = readl(base + reg_size); 428d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_size(0x%08x)\n", ch + 1, val); 429d3c9a738SXinliang Liu val = readl(base + reg_stride); 430d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_stride(0x%08x)\n", ch + 1, val); 431d3c9a738SXinliang Liu val = readl(base + reg_space); 432d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_space(0x%08x)\n", ch + 1, val); 433d3c9a738SXinliang Liu val = readl(base + reg_en); 434d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[rdma%d]: reg_en(0x%08x)\n", ch + 1, val); 435d3c9a738SXinliang Liu } 436d3c9a738SXinliang Liu 437d3c9a738SXinliang Liu static void ade_clip_dump_regs(void __iomem *base, u32 ch) 438d3c9a738SXinliang Liu { 439d3c9a738SXinliang Liu u32 val; 440d3c9a738SXinliang Liu 441d3c9a738SXinliang Liu val = ade_read_reload_bit(base, CLIP_OFST + ch); 442d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[clip%d]: reload(%d)\n", ch + 1, val); 443d3c9a738SXinliang Liu val = readl(base + ADE_CLIP_DISABLE(ch)); 444d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[clip%d]: reg_clip_disable(0x%08x)\n", ch + 1, val); 445d3c9a738SXinliang Liu val = readl(base + ADE_CLIP_SIZE0(ch)); 446d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size0(0x%08x)\n", ch + 1, val); 447d3c9a738SXinliang Liu val = readl(base + ADE_CLIP_SIZE1(ch)); 448d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size1(0x%08x)\n", ch + 1, val); 449d3c9a738SXinliang Liu } 450d3c9a738SXinliang Liu 451d3c9a738SXinliang Liu static void ade_compositor_routing_dump_regs(void __iomem *base, u32 ch) 452d3c9a738SXinliang Liu { 453d3c9a738SXinliang Liu u8 ovly_ch = 0; /* TODO: Only primary plane now */ 454d3c9a738SXinliang Liu u32 val; 455d3c9a738SXinliang Liu 456d3c9a738SXinliang Liu val = readl(base + ADE_OVLY_CH_XY0(ovly_ch)); 457d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy0(0x%08x)\n", ovly_ch, val); 458d3c9a738SXinliang Liu val = readl(base + ADE_OVLY_CH_XY1(ovly_ch)); 459d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy1(0x%08x)\n", ovly_ch, val); 460d3c9a738SXinliang Liu val = readl(base + ADE_OVLY_CH_CTL(ovly_ch)); 461d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_ctl(0x%08x)\n", ovly_ch, val); 462d3c9a738SXinliang Liu } 463d3c9a738SXinliang Liu 464d3c9a738SXinliang Liu static void ade_dump_overlay_compositor_regs(void __iomem *base, u32 comp) 465d3c9a738SXinliang Liu { 466d3c9a738SXinliang Liu u32 val; 467d3c9a738SXinliang Liu 468d3c9a738SXinliang Liu val = ade_read_reload_bit(base, OVLY_OFST + comp); 469d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay%d]: reload(%d)\n", comp + 1, val); 470d3c9a738SXinliang Liu writel(ADE_ENABLE, base + ADE_OVLYX_CTL(comp)); 471d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("[overlay%d]: reg_ctl(0x%08x)\n", comp + 1, val); 472d3c9a738SXinliang Liu val = readl(base + ADE_OVLY_CTL); 473d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("ovly_ctl(0x%08x)\n", val); 474d3c9a738SXinliang Liu } 475d3c9a738SXinliang Liu 476d3c9a738SXinliang Liu static void ade_dump_regs(void __iomem *base) 477d3c9a738SXinliang Liu { 478d3c9a738SXinliang Liu u32 i; 479d3c9a738SXinliang Liu 480d3c9a738SXinliang Liu /* dump channel regs */ 481d3c9a738SXinliang Liu for (i = 0; i < ADE_CH_NUM; i++) { 482d3c9a738SXinliang Liu /* dump rdma regs */ 483d3c9a738SXinliang Liu ade_rdma_dump_regs(base, i); 484d3c9a738SXinliang Liu 485d3c9a738SXinliang Liu /* dump clip regs */ 486d3c9a738SXinliang Liu ade_clip_dump_regs(base, i); 487d3c9a738SXinliang Liu 488d3c9a738SXinliang Liu /* dump compositor routing regs */ 489d3c9a738SXinliang Liu ade_compositor_routing_dump_regs(base, i); 490d3c9a738SXinliang Liu } 491d3c9a738SXinliang Liu 492d3c9a738SXinliang Liu /* dump overlay compositor regs */ 493d3c9a738SXinliang Liu ade_dump_overlay_compositor_regs(base, OUT_OVLY); 494d3c9a738SXinliang Liu } 495d3c9a738SXinliang Liu #else 496d3c9a738SXinliang Liu static void ade_dump_regs(void __iomem *base) { } 497d3c9a738SXinliang Liu #endif 498d3c9a738SXinliang Liu 4990b20a0f8SLaurent Pinchart static void ade_crtc_atomic_enable(struct drm_crtc *crtc, 5000b20a0f8SLaurent Pinchart struct drm_crtc_state *old_state) 501783ad972SXinliang Liu { 502ada7f67dSXu YiPing struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); 503ada7f67dSXu YiPing struct ade_hw_ctx *ctx = kcrtc->hw_ctx; 504783ad972SXinliang Liu int ret; 505783ad972SXinliang Liu 506ada7f67dSXu YiPing if (kcrtc->enable) 507783ad972SXinliang Liu return; 508783ad972SXinliang Liu 509783ad972SXinliang Liu if (!ctx->power_on) { 510783ad972SXinliang Liu ret = ade_power_up(ctx); 511783ad972SXinliang Liu if (ret) 512783ad972SXinliang Liu return; 513783ad972SXinliang Liu } 514783ad972SXinliang Liu 515e0d8eba5SXu YiPing ade_set_medianoc_qos(ctx); 516a202da16SXu YiPing ade_display_enable(ctx); 517d3c9a738SXinliang Liu ade_dump_regs(ctx->base); 51885d8747dSXinliang Liu drm_crtc_vblank_on(crtc); 519ada7f67dSXu YiPing kcrtc->enable = true; 520783ad972SXinliang Liu } 521783ad972SXinliang Liu 52264581714SLaurent Pinchart static void ade_crtc_atomic_disable(struct drm_crtc *crtc, 52364581714SLaurent Pinchart struct drm_crtc_state *old_state) 524783ad972SXinliang Liu { 525ada7f67dSXu YiPing struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); 526ada7f67dSXu YiPing struct ade_hw_ctx *ctx = kcrtc->hw_ctx; 527783ad972SXinliang Liu 528ada7f67dSXu YiPing if (!kcrtc->enable) 529783ad972SXinliang Liu return; 530783ad972SXinliang Liu 53185d8747dSXinliang Liu drm_crtc_vblank_off(crtc); 532783ad972SXinliang Liu ade_power_down(ctx); 533ada7f67dSXu YiPing kcrtc->enable = false; 534783ad972SXinliang Liu } 535783ad972SXinliang Liu 536783ad972SXinliang Liu static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc) 537783ad972SXinliang Liu { 538ada7f67dSXu YiPing struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); 539ada7f67dSXu YiPing struct ade_hw_ctx *ctx = kcrtc->hw_ctx; 540783ad972SXinliang Liu struct drm_display_mode *mode = &crtc->state->mode; 541783ad972SXinliang Liu struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode; 542783ad972SXinliang Liu 543783ad972SXinliang Liu if (!ctx->power_on) 544783ad972SXinliang Liu (void)ade_power_up(ctx); 545e0d8eba5SXu YiPing ade_ldi_set_mode(ctx, mode, adj_mode); 546783ad972SXinliang Liu } 547783ad972SXinliang Liu 548783ad972SXinliang Liu static void ade_crtc_atomic_begin(struct drm_crtc *crtc, 549783ad972SXinliang Liu struct drm_crtc_state *old_state) 550783ad972SXinliang Liu { 551ada7f67dSXu YiPing struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); 552ada7f67dSXu YiPing struct ade_hw_ctx *ctx = kcrtc->hw_ctx; 553a2f04243SPeter Griffin struct drm_display_mode *mode = &crtc->state->mode; 554a2f04243SPeter Griffin struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode; 555783ad972SXinliang Liu 556783ad972SXinliang Liu if (!ctx->power_on) 557783ad972SXinliang Liu (void)ade_power_up(ctx); 558e0d8eba5SXu YiPing ade_ldi_set_mode(ctx, mode, adj_mode); 559783ad972SXinliang Liu } 560783ad972SXinliang Liu 561783ad972SXinliang Liu static void ade_crtc_atomic_flush(struct drm_crtc *crtc, 562783ad972SXinliang Liu struct drm_crtc_state *old_state) 563783ad972SXinliang Liu 564783ad972SXinliang Liu { 565ada7f67dSXu YiPing struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); 566ada7f67dSXu YiPing struct ade_hw_ctx *ctx = kcrtc->hw_ctx; 56730bb70eeSDaniel Vetter struct drm_pending_vblank_event *event = crtc->state->event; 568783ad972SXinliang Liu void __iomem *base = ctx->base; 569783ad972SXinliang Liu 570783ad972SXinliang Liu /* only crtc is enabled regs take effect */ 571ada7f67dSXu YiPing if (kcrtc->enable) { 572d3c9a738SXinliang Liu ade_dump_regs(base); 573783ad972SXinliang Liu /* flush ade registers */ 574783ad972SXinliang Liu writel(ADE_ENABLE, base + ADE_EN); 575783ad972SXinliang Liu } 57630bb70eeSDaniel Vetter 57730bb70eeSDaniel Vetter if (event) { 57830bb70eeSDaniel Vetter crtc->state->event = NULL; 57930bb70eeSDaniel Vetter 58030bb70eeSDaniel Vetter spin_lock_irq(&crtc->dev->event_lock); 58130bb70eeSDaniel Vetter if (drm_crtc_vblank_get(crtc) == 0) 58230bb70eeSDaniel Vetter drm_crtc_arm_vblank_event(crtc, event); 58330bb70eeSDaniel Vetter else 58430bb70eeSDaniel Vetter drm_crtc_send_vblank_event(crtc, event); 58530bb70eeSDaniel Vetter spin_unlock_irq(&crtc->dev->event_lock); 58630bb70eeSDaniel Vetter } 587783ad972SXinliang Liu } 588783ad972SXinliang Liu 589783ad972SXinliang Liu static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = { 59071f23543SJohn Stultz .mode_fixup = ade_crtc_mode_fixup, 591783ad972SXinliang Liu .mode_set_nofb = ade_crtc_mode_set_nofb, 592783ad972SXinliang Liu .atomic_begin = ade_crtc_atomic_begin, 593783ad972SXinliang Liu .atomic_flush = ade_crtc_atomic_flush, 5940b20a0f8SLaurent Pinchart .atomic_enable = ade_crtc_atomic_enable, 59564581714SLaurent Pinchart .atomic_disable = ade_crtc_atomic_disable, 596783ad972SXinliang Liu }; 597783ad972SXinliang Liu 598783ad972SXinliang Liu static const struct drm_crtc_funcs ade_crtc_funcs = { 599783ad972SXinliang Liu .destroy = drm_crtc_cleanup, 600783ad972SXinliang Liu .set_config = drm_atomic_helper_set_config, 601783ad972SXinliang Liu .page_flip = drm_atomic_helper_page_flip, 602783ad972SXinliang Liu .reset = drm_atomic_helper_crtc_reset, 603783ad972SXinliang Liu .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 604783ad972SXinliang Liu .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 605d4f6750fSShawn Guo .enable_vblank = ade_crtc_enable_vblank, 606d4f6750fSShawn Guo .disable_vblank = ade_crtc_disable_vblank, 607783ad972SXinliang Liu }; 608783ad972SXinliang Liu 609783ad972SXinliang Liu static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, 610783ad972SXinliang Liu struct drm_plane *plane) 611783ad972SXinliang Liu { 612783ad972SXinliang Liu struct device_node *port; 613783ad972SXinliang Liu int ret; 614783ad972SXinliang Liu 615783ad972SXinliang Liu /* set crtc port so that 616783ad972SXinliang Liu * drm_of_find_possible_crtcs call works 617783ad972SXinliang Liu */ 618783ad972SXinliang Liu port = of_get_child_by_name(dev->dev->of_node, "port"); 619783ad972SXinliang Liu if (!port) { 6204bf99144SRob Herring DRM_ERROR("no port node found in %pOF\n", dev->dev->of_node); 621783ad972SXinliang Liu return -EINVAL; 622783ad972SXinliang Liu } 623783ad972SXinliang Liu of_node_put(port); 624783ad972SXinliang Liu crtc->port = port; 625783ad972SXinliang Liu 626783ad972SXinliang Liu ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 627783ad972SXinliang Liu &ade_crtc_funcs, NULL); 628783ad972SXinliang Liu if (ret) { 629783ad972SXinliang Liu DRM_ERROR("failed to init crtc.\n"); 630783ad972SXinliang Liu return ret; 631783ad972SXinliang Liu } 632783ad972SXinliang Liu 633783ad972SXinliang Liu drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs); 634783ad972SXinliang Liu 635783ad972SXinliang Liu return 0; 636783ad972SXinliang Liu } 637783ad972SXinliang Liu 638d3c9a738SXinliang Liu static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb, 639d3c9a738SXinliang Liu u32 ch, u32 y, u32 in_h, u32 fmt) 640d3c9a738SXinliang Liu { 641d3c9a738SXinliang Liu struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0); 642b3c11ac2SEric Engestrom struct drm_format_name_buf format_name; 643d3c9a738SXinliang Liu u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en; 644d3c9a738SXinliang Liu u32 stride = fb->pitches[0]; 645d3c9a738SXinliang Liu u32 addr = (u32)obj->paddr + y * stride; 646d3c9a738SXinliang Liu 647d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n", 648d3c9a738SXinliang Liu ch + 1, y, in_h, stride, (u32)obj->paddr); 649d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n", 650b3c11ac2SEric Engestrom addr, fb->width, fb->height, fmt, 651438b74a5SVille Syrjälä drm_get_format_name(fb->format->format, &format_name)); 652d3c9a738SXinliang Liu 653d3c9a738SXinliang Liu /* get reg offset */ 654d3c9a738SXinliang Liu reg_ctrl = RD_CH_CTRL(ch); 655d3c9a738SXinliang Liu reg_addr = RD_CH_ADDR(ch); 656d3c9a738SXinliang Liu reg_size = RD_CH_SIZE(ch); 657d3c9a738SXinliang Liu reg_stride = RD_CH_STRIDE(ch); 658d3c9a738SXinliang Liu reg_space = RD_CH_SPACE(ch); 659d3c9a738SXinliang Liu reg_en = RD_CH_EN(ch); 660d3c9a738SXinliang Liu 661d3c9a738SXinliang Liu /* 662d3c9a738SXinliang Liu * TODO: set rotation 663d3c9a738SXinliang Liu */ 664d3c9a738SXinliang Liu writel((fmt << 16) & 0x1f0000, base + reg_ctrl); 665d3c9a738SXinliang Liu writel(addr, base + reg_addr); 666d3c9a738SXinliang Liu writel((in_h << 16) | stride, base + reg_size); 667d3c9a738SXinliang Liu writel(stride, base + reg_stride); 668d3c9a738SXinliang Liu writel(in_h * stride, base + reg_space); 669d3c9a738SXinliang Liu writel(ADE_ENABLE, base + reg_en); 670d3c9a738SXinliang Liu ade_update_reload_bit(base, RDMA_OFST + ch, 0); 671d3c9a738SXinliang Liu } 672d3c9a738SXinliang Liu 673d3c9a738SXinliang Liu static void ade_rdma_disable(void __iomem *base, u32 ch) 674d3c9a738SXinliang Liu { 675d3c9a738SXinliang Liu u32 reg_en; 676d3c9a738SXinliang Liu 677d3c9a738SXinliang Liu /* get reg offset */ 678d3c9a738SXinliang Liu reg_en = RD_CH_EN(ch); 679d3c9a738SXinliang Liu writel(0, base + reg_en); 680d3c9a738SXinliang Liu ade_update_reload_bit(base, RDMA_OFST + ch, 1); 681d3c9a738SXinliang Liu } 682d3c9a738SXinliang Liu 683d3c9a738SXinliang Liu static void ade_clip_set(void __iomem *base, u32 ch, u32 fb_w, u32 x, 684d3c9a738SXinliang Liu u32 in_w, u32 in_h) 685d3c9a738SXinliang Liu { 686d3c9a738SXinliang Liu u32 disable_val; 687d3c9a738SXinliang Liu u32 clip_left; 688d3c9a738SXinliang Liu u32 clip_right; 689d3c9a738SXinliang Liu 690d3c9a738SXinliang Liu /* 691d3c9a738SXinliang Liu * clip width, no need to clip height 692d3c9a738SXinliang Liu */ 693d3c9a738SXinliang Liu if (fb_w == in_w) { /* bypass */ 694d3c9a738SXinliang Liu disable_val = 1; 695d3c9a738SXinliang Liu clip_left = 0; 696d3c9a738SXinliang Liu clip_right = 0; 697d3c9a738SXinliang Liu } else { 698d3c9a738SXinliang Liu disable_val = 0; 699d3c9a738SXinliang Liu clip_left = x; 700d3c9a738SXinliang Liu clip_right = fb_w - (x + in_w) - 1; 701d3c9a738SXinliang Liu } 702d3c9a738SXinliang Liu 703d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n", 704d3c9a738SXinliang Liu ch + 1, clip_left, clip_right); 705d3c9a738SXinliang Liu 706d3c9a738SXinliang Liu writel(disable_val, base + ADE_CLIP_DISABLE(ch)); 707d3c9a738SXinliang Liu writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch)); 708d3c9a738SXinliang Liu writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch)); 709d3c9a738SXinliang Liu ade_update_reload_bit(base, CLIP_OFST + ch, 0); 710d3c9a738SXinliang Liu } 711d3c9a738SXinliang Liu 712d3c9a738SXinliang Liu static void ade_clip_disable(void __iomem *base, u32 ch) 713d3c9a738SXinliang Liu { 714d3c9a738SXinliang Liu writel(1, base + ADE_CLIP_DISABLE(ch)); 715d3c9a738SXinliang Liu ade_update_reload_bit(base, CLIP_OFST + ch, 1); 716d3c9a738SXinliang Liu } 717d3c9a738SXinliang Liu 718d3c9a738SXinliang Liu static bool has_Alpha_channel(int format) 719d3c9a738SXinliang Liu { 720d3c9a738SXinliang Liu switch (format) { 721d3c9a738SXinliang Liu case ADE_ARGB_8888: 722d3c9a738SXinliang Liu case ADE_ABGR_8888: 723d3c9a738SXinliang Liu case ADE_RGBA_8888: 724d3c9a738SXinliang Liu case ADE_BGRA_8888: 725d3c9a738SXinliang Liu return true; 726d3c9a738SXinliang Liu default: 727d3c9a738SXinliang Liu return false; 728d3c9a738SXinliang Liu } 729d3c9a738SXinliang Liu } 730d3c9a738SXinliang Liu 731d3c9a738SXinliang Liu static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode, 732d3c9a738SXinliang Liu u8 *alp_sel, u8 *under_alp_sel) 733d3c9a738SXinliang Liu { 734d3c9a738SXinliang Liu bool has_alpha = has_Alpha_channel(fmt); 735d3c9a738SXinliang Liu 736d3c9a738SXinliang Liu /* 737d3c9a738SXinliang Liu * get alp_mode 738d3c9a738SXinliang Liu */ 739d3c9a738SXinliang Liu if (has_alpha && glb_alpha < 255) 740d3c9a738SXinliang Liu *alp_mode = ADE_ALP_PIXEL_AND_GLB; 741d3c9a738SXinliang Liu else if (has_alpha) 742d3c9a738SXinliang Liu *alp_mode = ADE_ALP_PIXEL; 743d3c9a738SXinliang Liu else 744d3c9a738SXinliang Liu *alp_mode = ADE_ALP_GLOBAL; 745d3c9a738SXinliang Liu 746d3c9a738SXinliang Liu /* 747d3c9a738SXinliang Liu * get alp sel 748d3c9a738SXinliang Liu */ 749d3c9a738SXinliang Liu *alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */ 750d3c9a738SXinliang Liu *under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */ 751d3c9a738SXinliang Liu } 752d3c9a738SXinliang Liu 753d3c9a738SXinliang Liu static void ade_compositor_routing_set(void __iomem *base, u8 ch, 754d3c9a738SXinliang Liu u32 x0, u32 y0, 755d3c9a738SXinliang Liu u32 in_w, u32 in_h, u32 fmt) 756d3c9a738SXinliang Liu { 757d3c9a738SXinliang Liu u8 ovly_ch = 0; /* TODO: This is the zpos, only one plane now */ 758d3c9a738SXinliang Liu u8 glb_alpha = 255; 759d3c9a738SXinliang Liu u32 x1 = x0 + in_w - 1; 760d3c9a738SXinliang Liu u32 y1 = y0 + in_h - 1; 761d3c9a738SXinliang Liu u32 val; 762d3c9a738SXinliang Liu u8 alp_sel; 763d3c9a738SXinliang Liu u8 under_alp_sel; 764d3c9a738SXinliang Liu u8 alp_mode; 765d3c9a738SXinliang Liu 766d3c9a738SXinliang Liu ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel, 767d3c9a738SXinliang Liu &under_alp_sel); 768d3c9a738SXinliang Liu 769d3c9a738SXinliang Liu /* overlay routing setting 770d3c9a738SXinliang Liu */ 771d3c9a738SXinliang Liu writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch)); 772d3c9a738SXinliang Liu writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch)); 773d3c9a738SXinliang Liu val = (ch + 1) << CH_SEL_OFST | BIT(CH_EN_OFST) | 774d3c9a738SXinliang Liu alp_sel << CH_ALP_SEL_OFST | 775d3c9a738SXinliang Liu under_alp_sel << CH_UNDER_ALP_SEL_OFST | 776d3c9a738SXinliang Liu glb_alpha << CH_ALP_GBL_OFST | 777d3c9a738SXinliang Liu alp_mode << CH_ALP_MODE_OFST; 778d3c9a738SXinliang Liu writel(val, base + ADE_OVLY_CH_CTL(ovly_ch)); 779d3c9a738SXinliang Liu /* connect this plane/channel to overlay2 compositor */ 780d3c9a738SXinliang Liu ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch), 781d3c9a738SXinliang Liu CH_OVLY_SEL_MASK, CH_OVLY_SEL_VAL(OUT_OVLY)); 782d3c9a738SXinliang Liu } 783d3c9a738SXinliang Liu 784d3c9a738SXinliang Liu static void ade_compositor_routing_disable(void __iomem *base, u32 ch) 785d3c9a738SXinliang Liu { 786d3c9a738SXinliang Liu u8 ovly_ch = 0; /* TODO: Only primary plane now */ 787d3c9a738SXinliang Liu 788d3c9a738SXinliang Liu /* disable this plane/channel */ 789d3c9a738SXinliang Liu ade_update_bits(base + ADE_OVLY_CH_CTL(ovly_ch), CH_EN_OFST, 790d3c9a738SXinliang Liu MASK(1), 0); 791d3c9a738SXinliang Liu /* dis-connect this plane/channel of overlay2 compositor */ 792d3c9a738SXinliang Liu ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch), 793d3c9a738SXinliang Liu CH_OVLY_SEL_MASK, 0); 794d3c9a738SXinliang Liu } 795d3c9a738SXinliang Liu 796d3c9a738SXinliang Liu /* 797d3c9a738SXinliang Liu * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->compositor 798d3c9a738SXinliang Liu */ 7990ae622c5SXu YiPing static void ade_update_channel(struct kirin_plane *kplane, 800d3c9a738SXinliang Liu struct drm_framebuffer *fb, int crtc_x, 801d3c9a738SXinliang Liu int crtc_y, unsigned int crtc_w, 802d3c9a738SXinliang Liu unsigned int crtc_h, u32 src_x, 803d3c9a738SXinliang Liu u32 src_y, u32 src_w, u32 src_h) 804d3c9a738SXinliang Liu { 8050ae622c5SXu YiPing struct ade_hw_ctx *ctx = kplane->hw_ctx; 806d3c9a738SXinliang Liu void __iomem *base = ctx->base; 807438b74a5SVille Syrjälä u32 fmt = ade_get_format(fb->format->format); 8080ae622c5SXu YiPing u32 ch = kplane->ch; 809d3c9a738SXinliang Liu u32 in_w; 810d3c9a738SXinliang Liu u32 in_h; 811d3c9a738SXinliang Liu 812d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d", 813d3c9a738SXinliang Liu ch + 1, src_x, src_y, src_w, src_h, 814d3c9a738SXinliang Liu crtc_x, crtc_y, crtc_w, crtc_h); 815d3c9a738SXinliang Liu 816d3c9a738SXinliang Liu /* 1) DMA setting */ 817d3c9a738SXinliang Liu in_w = src_w; 818d3c9a738SXinliang Liu in_h = src_h; 819d3c9a738SXinliang Liu ade_rdma_set(base, fb, ch, src_y, in_h, fmt); 820d3c9a738SXinliang Liu 821d3c9a738SXinliang Liu /* 2) clip setting */ 822d3c9a738SXinliang Liu ade_clip_set(base, ch, fb->width, src_x, in_w, in_h); 823d3c9a738SXinliang Liu 824d3c9a738SXinliang Liu /* 3) TODO: scale setting for overlay planes */ 825d3c9a738SXinliang Liu 826d3c9a738SXinliang Liu /* 4) TODO: ctran/csc setting for overlay planes */ 827d3c9a738SXinliang Liu 828d3c9a738SXinliang Liu /* 5) compositor routing setting */ 829d3c9a738SXinliang Liu ade_compositor_routing_set(base, ch, crtc_x, crtc_y, in_w, in_h, fmt); 830d3c9a738SXinliang Liu } 831d3c9a738SXinliang Liu 8320ae622c5SXu YiPing static void ade_disable_channel(struct kirin_plane *kplane) 833d3c9a738SXinliang Liu { 8340ae622c5SXu YiPing struct ade_hw_ctx *ctx = kplane->hw_ctx; 835d3c9a738SXinliang Liu void __iomem *base = ctx->base; 8360ae622c5SXu YiPing u32 ch = kplane->ch; 837d3c9a738SXinliang Liu 838d3c9a738SXinliang Liu DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1); 839d3c9a738SXinliang Liu 840d3c9a738SXinliang Liu /* disable read DMA */ 841d3c9a738SXinliang Liu ade_rdma_disable(base, ch); 842d3c9a738SXinliang Liu 843d3c9a738SXinliang Liu /* disable clip */ 844d3c9a738SXinliang Liu ade_clip_disable(base, ch); 845d3c9a738SXinliang Liu 846d3c9a738SXinliang Liu /* disable compositor routing */ 847d3c9a738SXinliang Liu ade_compositor_routing_disable(base, ch); 848d3c9a738SXinliang Liu } 849d3c9a738SXinliang Liu 850d3c9a738SXinliang Liu static int ade_plane_atomic_check(struct drm_plane *plane, 851d3c9a738SXinliang Liu struct drm_plane_state *state) 852d3c9a738SXinliang Liu { 853d3c9a738SXinliang Liu struct drm_framebuffer *fb = state->fb; 854d3c9a738SXinliang Liu struct drm_crtc *crtc = state->crtc; 855d3c9a738SXinliang Liu struct drm_crtc_state *crtc_state; 856d3c9a738SXinliang Liu u32 src_x = state->src_x >> 16; 857d3c9a738SXinliang Liu u32 src_y = state->src_y >> 16; 858d3c9a738SXinliang Liu u32 src_w = state->src_w >> 16; 859d3c9a738SXinliang Liu u32 src_h = state->src_h >> 16; 860d3c9a738SXinliang Liu int crtc_x = state->crtc_x; 861d3c9a738SXinliang Liu int crtc_y = state->crtc_y; 862d3c9a738SXinliang Liu u32 crtc_w = state->crtc_w; 863d3c9a738SXinliang Liu u32 crtc_h = state->crtc_h; 864d3c9a738SXinliang Liu u32 fmt; 865d3c9a738SXinliang Liu 866d3c9a738SXinliang Liu if (!crtc || !fb) 867d3c9a738SXinliang Liu return 0; 868d3c9a738SXinliang Liu 869438b74a5SVille Syrjälä fmt = ade_get_format(fb->format->format); 870d3c9a738SXinliang Liu if (fmt == ADE_FORMAT_UNSUPPORT) 871d3c9a738SXinliang Liu return -EINVAL; 872d3c9a738SXinliang Liu 873d3c9a738SXinliang Liu crtc_state = drm_atomic_get_crtc_state(state->state, crtc); 874d3c9a738SXinliang Liu if (IS_ERR(crtc_state)) 875d3c9a738SXinliang Liu return PTR_ERR(crtc_state); 876d3c9a738SXinliang Liu 877d3c9a738SXinliang Liu if (src_w != crtc_w || src_h != crtc_h) { 878d3c9a738SXinliang Liu return -EINVAL; 879d3c9a738SXinliang Liu } 880d3c9a738SXinliang Liu 881d3c9a738SXinliang Liu if (src_x + src_w > fb->width || 882d3c9a738SXinliang Liu src_y + src_h > fb->height) 883d3c9a738SXinliang Liu return -EINVAL; 884d3c9a738SXinliang Liu 885d3c9a738SXinliang Liu if (crtc_x < 0 || crtc_y < 0) 886d3c9a738SXinliang Liu return -EINVAL; 887d3c9a738SXinliang Liu 888d3c9a738SXinliang Liu if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay || 889d3c9a738SXinliang Liu crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay) 890d3c9a738SXinliang Liu return -EINVAL; 891d3c9a738SXinliang Liu 892d3c9a738SXinliang Liu return 0; 893d3c9a738SXinliang Liu } 894d3c9a738SXinliang Liu 895d3c9a738SXinliang Liu static void ade_plane_atomic_update(struct drm_plane *plane, 896d3c9a738SXinliang Liu struct drm_plane_state *old_state) 897d3c9a738SXinliang Liu { 898d3c9a738SXinliang Liu struct drm_plane_state *state = plane->state; 8990ae622c5SXu YiPing struct kirin_plane *kplane = to_kirin_plane(plane); 900d3c9a738SXinliang Liu 9010ae622c5SXu YiPing ade_update_channel(kplane, state->fb, state->crtc_x, state->crtc_y, 902d3c9a738SXinliang Liu state->crtc_w, state->crtc_h, 903d3c9a738SXinliang Liu state->src_x >> 16, state->src_y >> 16, 904d3c9a738SXinliang Liu state->src_w >> 16, state->src_h >> 16); 905d3c9a738SXinliang Liu } 906d3c9a738SXinliang Liu 907d3c9a738SXinliang Liu static void ade_plane_atomic_disable(struct drm_plane *plane, 908d3c9a738SXinliang Liu struct drm_plane_state *old_state) 909d3c9a738SXinliang Liu { 9100ae622c5SXu YiPing struct kirin_plane *kplane = to_kirin_plane(plane); 911d3c9a738SXinliang Liu 9120ae622c5SXu YiPing ade_disable_channel(kplane); 913d3c9a738SXinliang Liu } 914d3c9a738SXinliang Liu 915d3c9a738SXinliang Liu static const struct drm_plane_helper_funcs ade_plane_helper_funcs = { 916d3c9a738SXinliang Liu .atomic_check = ade_plane_atomic_check, 917d3c9a738SXinliang Liu .atomic_update = ade_plane_atomic_update, 918d3c9a738SXinliang Liu .atomic_disable = ade_plane_atomic_disable, 919d3c9a738SXinliang Liu }; 920d3c9a738SXinliang Liu 921d3c9a738SXinliang Liu static struct drm_plane_funcs ade_plane_funcs = { 922d3c9a738SXinliang Liu .update_plane = drm_atomic_helper_update_plane, 923d3c9a738SXinliang Liu .disable_plane = drm_atomic_helper_disable_plane, 924d3c9a738SXinliang Liu .destroy = drm_plane_cleanup, 925d3c9a738SXinliang Liu .reset = drm_atomic_helper_plane_reset, 926d3c9a738SXinliang Liu .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 927d3c9a738SXinliang Liu .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 928d3c9a738SXinliang Liu }; 929d3c9a738SXinliang Liu 9300ae622c5SXu YiPing static int ade_plane_init(struct drm_device *dev, struct kirin_plane *kplane, 931d3c9a738SXinliang Liu enum drm_plane_type type) 932d3c9a738SXinliang Liu { 933d3c9a738SXinliang Liu const u32 *fmts; 934d3c9a738SXinliang Liu u32 fmts_cnt; 935d3c9a738SXinliang Liu int ret = 0; 936d3c9a738SXinliang Liu 937d3c9a738SXinliang Liu /* get properties */ 9380ae622c5SXu YiPing fmts_cnt = ade_get_channel_formats(kplane->ch, &fmts); 939d3c9a738SXinliang Liu if (ret) 940d3c9a738SXinliang Liu return ret; 941d3c9a738SXinliang Liu 9420ae622c5SXu YiPing ret = drm_universal_plane_init(dev, &kplane->base, 1, &ade_plane_funcs, 943e6fc3b68SBen Widawsky fmts, fmts_cnt, NULL, type, NULL); 944d3c9a738SXinliang Liu if (ret) { 9450ae622c5SXu YiPing DRM_ERROR("fail to init plane, ch=%d\n", kplane->ch); 946d3c9a738SXinliang Liu return ret; 947d3c9a738SXinliang Liu } 948d3c9a738SXinliang Liu 9490ae622c5SXu YiPing drm_plane_helper_add(&kplane->base, &ade_plane_helper_funcs); 950d3c9a738SXinliang Liu 951d3c9a738SXinliang Liu return 0; 952d3c9a738SXinliang Liu } 953d3c9a738SXinliang Liu 954783ad972SXinliang Liu static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx) 955783ad972SXinliang Liu { 956783ad972SXinliang Liu struct resource *res; 957783ad972SXinliang Liu struct device *dev = &pdev->dev; 958783ad972SXinliang Liu struct device_node *np = pdev->dev.of_node; 959783ad972SXinliang Liu 960783ad972SXinliang Liu res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 961783ad972SXinliang Liu ctx->base = devm_ioremap_resource(dev, res); 962783ad972SXinliang Liu if (IS_ERR(ctx->base)) { 963783ad972SXinliang Liu DRM_ERROR("failed to remap ade io base\n"); 964783ad972SXinliang Liu return PTR_ERR(ctx->base); 965783ad972SXinliang Liu } 966783ad972SXinliang Liu 967783ad972SXinliang Liu ctx->reset = devm_reset_control_get(dev, NULL); 968783ad972SXinliang Liu if (IS_ERR(ctx->reset)) 969783ad972SXinliang Liu return PTR_ERR(ctx->reset); 970783ad972SXinliang Liu 971783ad972SXinliang Liu ctx->noc_regmap = 972783ad972SXinliang Liu syscon_regmap_lookup_by_phandle(np, "hisilicon,noc-syscon"); 973783ad972SXinliang Liu if (IS_ERR(ctx->noc_regmap)) { 974783ad972SXinliang Liu DRM_ERROR("failed to get noc regmap\n"); 975783ad972SXinliang Liu return PTR_ERR(ctx->noc_regmap); 976783ad972SXinliang Liu } 977783ad972SXinliang Liu 978783ad972SXinliang Liu ctx->irq = platform_get_irq(pdev, 0); 979783ad972SXinliang Liu if (ctx->irq < 0) { 980783ad972SXinliang Liu DRM_ERROR("failed to get irq\n"); 981783ad972SXinliang Liu return -ENODEV; 982783ad972SXinliang Liu } 983783ad972SXinliang Liu 984783ad972SXinliang Liu ctx->ade_core_clk = devm_clk_get(dev, "clk_ade_core"); 98543fd0d92SWei Yongjun if (IS_ERR(ctx->ade_core_clk)) { 986783ad972SXinliang Liu DRM_ERROR("failed to parse clk ADE_CORE\n"); 98743fd0d92SWei Yongjun return PTR_ERR(ctx->ade_core_clk); 988783ad972SXinliang Liu } 989783ad972SXinliang Liu 990783ad972SXinliang Liu ctx->media_noc_clk = devm_clk_get(dev, "clk_codec_jpeg"); 99143fd0d92SWei Yongjun if (IS_ERR(ctx->media_noc_clk)) { 992783ad972SXinliang Liu DRM_ERROR("failed to parse clk CODEC_JPEG\n"); 99343fd0d92SWei Yongjun return PTR_ERR(ctx->media_noc_clk); 994783ad972SXinliang Liu } 995783ad972SXinliang Liu 996783ad972SXinliang Liu ctx->ade_pix_clk = devm_clk_get(dev, "clk_ade_pix"); 99743fd0d92SWei Yongjun if (IS_ERR(ctx->ade_pix_clk)) { 998783ad972SXinliang Liu DRM_ERROR("failed to parse clk ADE_PIX\n"); 99943fd0d92SWei Yongjun return PTR_ERR(ctx->ade_pix_clk); 1000783ad972SXinliang Liu } 1001783ad972SXinliang Liu 1002783ad972SXinliang Liu return 0; 1003783ad972SXinliang Liu } 1004783ad972SXinliang Liu 100538bf57faSDaniel Vetter static int ade_drm_init(struct platform_device *pdev) 1006783ad972SXinliang Liu { 100738bf57faSDaniel Vetter struct drm_device *dev = platform_get_drvdata(pdev); 1008783ad972SXinliang Liu struct ade_data *ade; 1009783ad972SXinliang Liu struct ade_hw_ctx *ctx; 1010ada7f67dSXu YiPing struct kirin_crtc *kcrtc; 10110ae622c5SXu YiPing struct kirin_plane *kplane; 1012d3c9a738SXinliang Liu enum drm_plane_type type; 1013783ad972SXinliang Liu int ret; 1014d3c9a738SXinliang Liu int i; 1015783ad972SXinliang Liu 1016783ad972SXinliang Liu ade = devm_kzalloc(dev->dev, sizeof(*ade), GFP_KERNEL); 1017783ad972SXinliang Liu if (!ade) { 1018783ad972SXinliang Liu DRM_ERROR("failed to alloc ade_data\n"); 1019783ad972SXinliang Liu return -ENOMEM; 1020783ad972SXinliang Liu } 1021783ad972SXinliang Liu platform_set_drvdata(pdev, ade); 1022783ad972SXinliang Liu 1023783ad972SXinliang Liu ctx = &ade->ctx; 1024ada7f67dSXu YiPing kcrtc = &ade->crtc; 1025ada7f67dSXu YiPing kcrtc->hw_ctx = ctx; 1026783ad972SXinliang Liu 1027783ad972SXinliang Liu ret = ade_dts_parse(pdev, ctx); 1028783ad972SXinliang Liu if (ret) 1029783ad972SXinliang Liu return ret; 1030783ad972SXinliang Liu 1031d3c9a738SXinliang Liu /* 1032d3c9a738SXinliang Liu * plane init 1033d3c9a738SXinliang Liu * TODO: Now only support primary plane, overlay planes 1034d3c9a738SXinliang Liu * need to do. 1035d3c9a738SXinliang Liu */ 1036d3c9a738SXinliang Liu for (i = 0; i < ADE_CH_NUM; i++) { 10370ae622c5SXu YiPing kplane = &ade->planes[i]; 10380ae622c5SXu YiPing kplane->ch = i; 10390ae622c5SXu YiPing kplane->hw_ctx = ctx; 1040d3c9a738SXinliang Liu type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY : 1041d3c9a738SXinliang Liu DRM_PLANE_TYPE_OVERLAY; 1042d3c9a738SXinliang Liu 10430ae622c5SXu YiPing ret = ade_plane_init(dev, kplane, type); 1044d3c9a738SXinliang Liu if (ret) 1045d3c9a738SXinliang Liu return ret; 1046d3c9a738SXinliang Liu } 1047d3c9a738SXinliang Liu 1048d3c9a738SXinliang Liu /* crtc init */ 1049ada7f67dSXu YiPing ret = ade_crtc_init(dev, &kcrtc->base, &ade->planes[PRIMARY_CH].base); 1050d3c9a738SXinliang Liu if (ret) 1051d3c9a738SXinliang Liu return ret; 1052d3c9a738SXinliang Liu 1053bc4611e8SXinliang Liu /* vblank irq init */ 1054bc4611e8SXinliang Liu ret = devm_request_irq(dev->dev, ctx->irq, ade_irq_handler, 1055ada7f67dSXu YiPing IRQF_SHARED, dev->driver->name, kcrtc); 1056ff57c651SDa Lv 1057ada7f67dSXu YiPing INIT_WORK(&kcrtc->display_reset_wq, drm_underflow_wq); 1058ff57c651SDa Lv 1059bc4611e8SXinliang Liu if (ret) 1060bc4611e8SXinliang Liu return ret; 1061bc4611e8SXinliang Liu 1062783ad972SXinliang Liu return 0; 1063783ad972SXinliang Liu } 1064783ad972SXinliang Liu 106538bf57faSDaniel Vetter static void ade_drm_cleanup(struct platform_device *pdev) 1066783ad972SXinliang Liu { 1067783ad972SXinliang Liu } 1068783ad972SXinliang Liu 1069783ad972SXinliang Liu const struct kirin_dc_ops ade_dc_ops = { 1070783ad972SXinliang Liu .init = ade_drm_init, 1071783ad972SXinliang Liu .cleanup = ade_drm_cleanup 10729cd2e854SDaniel Vetter }; 1073