1 /* 2 * Copyright (C) 2016 BayLibre, SAS 3 * Author: Neil Armstrong <narmstrong@baylibre.com> 4 * Copyright (C) 2015 Amlogic, Inc. All rights reserved. 5 * Copyright (C) 2014 Endless Mobile 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, see <http://www.gnu.org/licenses/>. 19 * 20 * Written by: 21 * Jasper St. Pierre <jstpierre@mecheye.net> 22 */ 23 24 #include <linux/kernel.h> 25 #include <linux/module.h> 26 #include <linux/mutex.h> 27 #include <linux/platform_device.h> 28 #include <linux/bitfield.h> 29 #include <drm/drmP.h> 30 #include <drm/drm_atomic.h> 31 #include <drm/drm_atomic_helper.h> 32 #include <drm/drm_flip_work.h> 33 #include <drm/drm_probe_helper.h> 34 35 #include "meson_crtc.h" 36 #include "meson_plane.h" 37 #include "meson_venc.h" 38 #include "meson_vpp.h" 39 #include "meson_viu.h" 40 #include "meson_canvas.h" 41 #include "meson_registers.h" 42 43 /* CRTC definition */ 44 45 struct meson_crtc { 46 struct drm_crtc base; 47 struct drm_pending_vblank_event *event; 48 struct meson_drm *priv; 49 }; 50 #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) 51 52 /* CRTC */ 53 54 static int meson_crtc_enable_vblank(struct drm_crtc *crtc) 55 { 56 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 57 struct meson_drm *priv = meson_crtc->priv; 58 59 meson_venc_enable_vsync(priv); 60 61 return 0; 62 } 63 64 static void meson_crtc_disable_vblank(struct drm_crtc *crtc) 65 { 66 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 67 struct meson_drm *priv = meson_crtc->priv; 68 69 meson_venc_disable_vsync(priv); 70 } 71 72 static const struct drm_crtc_funcs meson_crtc_funcs = { 73 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 74 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 75 .destroy = drm_crtc_cleanup, 76 .page_flip = drm_atomic_helper_page_flip, 77 .reset = drm_atomic_helper_crtc_reset, 78 .set_config = drm_atomic_helper_set_config, 79 .enable_vblank = meson_crtc_enable_vblank, 80 .disable_vblank = meson_crtc_disable_vblank, 81 82 }; 83 84 static void meson_crtc_atomic_enable(struct drm_crtc *crtc, 85 struct drm_crtc_state *old_state) 86 { 87 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 88 struct drm_crtc_state *crtc_state = crtc->state; 89 struct meson_drm *priv = meson_crtc->priv; 90 91 DRM_DEBUG_DRIVER("\n"); 92 93 if (!crtc_state) { 94 DRM_ERROR("Invalid crtc_state\n"); 95 return; 96 } 97 98 /* Enable VPP Postblend */ 99 writel(crtc_state->mode.hdisplay, 100 priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); 101 102 /* VD1 Preblend vertical start/end */ 103 writel(FIELD_PREP(GENMASK(11, 0), 2303), 104 priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END)); 105 106 writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE, 107 priv->io_base + _REG(VPP_MISC)); 108 109 drm_crtc_vblank_on(crtc); 110 111 priv->viu.osd1_enabled = true; 112 } 113 114 static void meson_crtc_atomic_disable(struct drm_crtc *crtc, 115 struct drm_crtc_state *old_state) 116 { 117 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 118 struct meson_drm *priv = meson_crtc->priv; 119 120 DRM_DEBUG_DRIVER("\n"); 121 122 drm_crtc_vblank_off(crtc); 123 124 priv->viu.osd1_enabled = false; 125 priv->viu.osd1_commit = false; 126 127 priv->viu.vd1_enabled = false; 128 priv->viu.vd1_commit = false; 129 130 /* Disable VPP Postblend */ 131 writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_VD1_POSTBLEND | 132 VPP_VD1_PREBLEND | VPP_POSTBLEND_ENABLE, 0, 133 priv->io_base + _REG(VPP_MISC)); 134 135 if (crtc->state->event && !crtc->state->active) { 136 spin_lock_irq(&crtc->dev->event_lock); 137 drm_crtc_send_vblank_event(crtc, crtc->state->event); 138 spin_unlock_irq(&crtc->dev->event_lock); 139 140 crtc->state->event = NULL; 141 } 142 } 143 144 static void meson_crtc_atomic_begin(struct drm_crtc *crtc, 145 struct drm_crtc_state *state) 146 { 147 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 148 unsigned long flags; 149 150 if (crtc->state->event) { 151 WARN_ON(drm_crtc_vblank_get(crtc) != 0); 152 153 spin_lock_irqsave(&crtc->dev->event_lock, flags); 154 meson_crtc->event = crtc->state->event; 155 spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 156 crtc->state->event = NULL; 157 } 158 } 159 160 static void meson_crtc_atomic_flush(struct drm_crtc *crtc, 161 struct drm_crtc_state *old_crtc_state) 162 { 163 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 164 struct meson_drm *priv = meson_crtc->priv; 165 166 priv->viu.osd1_commit = true; 167 priv->viu.vd1_commit = true; 168 } 169 170 static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { 171 .atomic_begin = meson_crtc_atomic_begin, 172 .atomic_flush = meson_crtc_atomic_flush, 173 .atomic_enable = meson_crtc_atomic_enable, 174 .atomic_disable = meson_crtc_atomic_disable, 175 }; 176 177 void meson_crtc_irq(struct meson_drm *priv) 178 { 179 struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc); 180 unsigned long flags; 181 182 /* Update the OSD registers */ 183 if (priv->viu.osd1_enabled && priv->viu.osd1_commit) { 184 writel_relaxed(priv->viu.osd1_ctrl_stat, 185 priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); 186 writel_relaxed(priv->viu.osd1_blk0_cfg[0], 187 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0)); 188 writel_relaxed(priv->viu.osd1_blk0_cfg[1], 189 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1)); 190 writel_relaxed(priv->viu.osd1_blk0_cfg[2], 191 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2)); 192 writel_relaxed(priv->viu.osd1_blk0_cfg[3], 193 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3)); 194 writel_relaxed(priv->viu.osd1_blk0_cfg[4], 195 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4)); 196 writel_relaxed(priv->viu.osd_sc_ctrl0, 197 priv->io_base + _REG(VPP_OSD_SC_CTRL0)); 198 writel_relaxed(priv->viu.osd_sc_i_wh_m1, 199 priv->io_base + _REG(VPP_OSD_SCI_WH_M1)); 200 writel_relaxed(priv->viu.osd_sc_o_h_start_end, 201 priv->io_base + _REG(VPP_OSD_SCO_H_START_END)); 202 writel_relaxed(priv->viu.osd_sc_o_v_start_end, 203 priv->io_base + _REG(VPP_OSD_SCO_V_START_END)); 204 writel_relaxed(priv->viu.osd_sc_v_ini_phase, 205 priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE)); 206 writel_relaxed(priv->viu.osd_sc_v_phase_step, 207 priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP)); 208 writel_relaxed(priv->viu.osd_sc_h_ini_phase, 209 priv->io_base + _REG(VPP_OSD_HSC_INI_PHASE)); 210 writel_relaxed(priv->viu.osd_sc_h_phase_step, 211 priv->io_base + _REG(VPP_OSD_HSC_PHASE_STEP)); 212 writel_relaxed(priv->viu.osd_sc_h_ctrl0, 213 priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); 214 writel_relaxed(priv->viu.osd_sc_v_ctrl0, 215 priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); 216 217 if (priv->canvas) 218 meson_canvas_config(priv->canvas, priv->canvas_id_osd1, 219 priv->viu.osd1_addr, priv->viu.osd1_stride, 220 priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, 221 MESON_CANVAS_BLKMODE_LINEAR, 0); 222 else 223 meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, 224 priv->viu.osd1_addr, priv->viu.osd1_stride, 225 priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, 226 MESON_CANVAS_BLKMODE_LINEAR, 0); 227 228 /* Enable OSD1 */ 229 writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, 230 priv->io_base + _REG(VPP_MISC)); 231 232 priv->viu.osd1_commit = false; 233 } 234 235 /* Update the VD1 registers */ 236 if (priv->viu.vd1_enabled && priv->viu.vd1_commit) { 237 238 switch (priv->viu.vd1_planes) { 239 case 3: 240 if (priv->canvas) 241 meson_canvas_config(priv->canvas, 242 priv->canvas_id_vd1_2, 243 priv->viu.vd1_addr2, 244 priv->viu.vd1_stride2, 245 priv->viu.vd1_height2, 246 MESON_CANVAS_WRAP_NONE, 247 MESON_CANVAS_BLKMODE_LINEAR, 248 MESON_CANVAS_ENDIAN_SWAP64); 249 else 250 meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_2, 251 priv->viu.vd1_addr2, 252 priv->viu.vd1_stride2, 253 priv->viu.vd1_height2, 254 MESON_CANVAS_WRAP_NONE, 255 MESON_CANVAS_BLKMODE_LINEAR, 256 MESON_CANVAS_ENDIAN_SWAP64); 257 /* fallthrough */ 258 case 2: 259 if (priv->canvas) 260 meson_canvas_config(priv->canvas, 261 priv->canvas_id_vd1_1, 262 priv->viu.vd1_addr1, 263 priv->viu.vd1_stride1, 264 priv->viu.vd1_height1, 265 MESON_CANVAS_WRAP_NONE, 266 MESON_CANVAS_BLKMODE_LINEAR, 267 MESON_CANVAS_ENDIAN_SWAP64); 268 else 269 meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_1, 270 priv->viu.vd1_addr2, 271 priv->viu.vd1_stride2, 272 priv->viu.vd1_height2, 273 MESON_CANVAS_WRAP_NONE, 274 MESON_CANVAS_BLKMODE_LINEAR, 275 MESON_CANVAS_ENDIAN_SWAP64); 276 /* fallthrough */ 277 case 1: 278 if (priv->canvas) 279 meson_canvas_config(priv->canvas, 280 priv->canvas_id_vd1_0, 281 priv->viu.vd1_addr0, 282 priv->viu.vd1_stride0, 283 priv->viu.vd1_height0, 284 MESON_CANVAS_WRAP_NONE, 285 MESON_CANVAS_BLKMODE_LINEAR, 286 MESON_CANVAS_ENDIAN_SWAP64); 287 else 288 meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_0, 289 priv->viu.vd1_addr2, 290 priv->viu.vd1_stride2, 291 priv->viu.vd1_height2, 292 MESON_CANVAS_WRAP_NONE, 293 MESON_CANVAS_BLKMODE_LINEAR, 294 MESON_CANVAS_ENDIAN_SWAP64); 295 }; 296 297 writel_relaxed(priv->viu.vd1_if0_gen_reg, 298 priv->io_base + _REG(VD1_IF0_GEN_REG)); 299 writel_relaxed(priv->viu.vd1_if0_gen_reg, 300 priv->io_base + _REG(VD2_IF0_GEN_REG)); 301 writel_relaxed(priv->viu.vd1_if0_gen_reg2, 302 priv->io_base + _REG(VD1_IF0_GEN_REG2)); 303 writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, 304 priv->io_base + _REG(VIU_VD1_FMT_CTRL)); 305 writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, 306 priv->io_base + _REG(VIU_VD2_FMT_CTRL)); 307 writel_relaxed(priv->viu.viu_vd1_fmt_w, 308 priv->io_base + _REG(VIU_VD1_FMT_W)); 309 writel_relaxed(priv->viu.viu_vd1_fmt_w, 310 priv->io_base + _REG(VIU_VD2_FMT_W)); 311 writel_relaxed(priv->viu.vd1_if0_canvas0, 312 priv->io_base + _REG(VD1_IF0_CANVAS0)); 313 writel_relaxed(priv->viu.vd1_if0_canvas0, 314 priv->io_base + _REG(VD1_IF0_CANVAS1)); 315 writel_relaxed(priv->viu.vd1_if0_canvas0, 316 priv->io_base + _REG(VD2_IF0_CANVAS0)); 317 writel_relaxed(priv->viu.vd1_if0_canvas0, 318 priv->io_base + _REG(VD2_IF0_CANVAS1)); 319 writel_relaxed(priv->viu.vd1_if0_luma_x0, 320 priv->io_base + _REG(VD1_IF0_LUMA_X0)); 321 writel_relaxed(priv->viu.vd1_if0_luma_x0, 322 priv->io_base + _REG(VD1_IF0_LUMA_X1)); 323 writel_relaxed(priv->viu.vd1_if0_luma_x0, 324 priv->io_base + _REG(VD2_IF0_LUMA_X0)); 325 writel_relaxed(priv->viu.vd1_if0_luma_x0, 326 priv->io_base + _REG(VD2_IF0_LUMA_X1)); 327 writel_relaxed(priv->viu.vd1_if0_luma_y0, 328 priv->io_base + _REG(VD1_IF0_LUMA_Y0)); 329 writel_relaxed(priv->viu.vd1_if0_luma_y0, 330 priv->io_base + _REG(VD1_IF0_LUMA_Y1)); 331 writel_relaxed(priv->viu.vd1_if0_luma_y0, 332 priv->io_base + _REG(VD2_IF0_LUMA_Y0)); 333 writel_relaxed(priv->viu.vd1_if0_luma_y0, 334 priv->io_base + _REG(VD2_IF0_LUMA_Y1)); 335 writel_relaxed(priv->viu.vd1_if0_chroma_x0, 336 priv->io_base + _REG(VD1_IF0_CHROMA_X0)); 337 writel_relaxed(priv->viu.vd1_if0_chroma_x0, 338 priv->io_base + _REG(VD1_IF0_CHROMA_X1)); 339 writel_relaxed(priv->viu.vd1_if0_chroma_x0, 340 priv->io_base + _REG(VD2_IF0_CHROMA_X0)); 341 writel_relaxed(priv->viu.vd1_if0_chroma_x0, 342 priv->io_base + _REG(VD2_IF0_CHROMA_X1)); 343 writel_relaxed(priv->viu.vd1_if0_chroma_y0, 344 priv->io_base + _REG(VD1_IF0_CHROMA_Y0)); 345 writel_relaxed(priv->viu.vd1_if0_chroma_y0, 346 priv->io_base + _REG(VD1_IF0_CHROMA_Y1)); 347 writel_relaxed(priv->viu.vd1_if0_chroma_y0, 348 priv->io_base + _REG(VD2_IF0_CHROMA_Y0)); 349 writel_relaxed(priv->viu.vd1_if0_chroma_y0, 350 priv->io_base + _REG(VD2_IF0_CHROMA_Y1)); 351 writel_relaxed(priv->viu.vd1_if0_repeat_loop, 352 priv->io_base + _REG(VD1_IF0_RPT_LOOP)); 353 writel_relaxed(priv->viu.vd1_if0_repeat_loop, 354 priv->io_base + _REG(VD2_IF0_RPT_LOOP)); 355 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, 356 priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT)); 357 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, 358 priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT)); 359 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, 360 priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT)); 361 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, 362 priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT)); 363 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, 364 priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT)); 365 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, 366 priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT)); 367 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, 368 priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT)); 369 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, 370 priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT)); 371 writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL)); 372 writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL)); 373 writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL)); 374 writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL)); 375 writel_relaxed(priv->viu.vd1_range_map_y, 376 priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y)); 377 writel_relaxed(priv->viu.vd1_range_map_cb, 378 priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB)); 379 writel_relaxed(priv->viu.vd1_range_map_cr, 380 priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR)); 381 writel_relaxed(0x78404, 382 priv->io_base + _REG(VPP_SC_MISC)); 383 writel_relaxed(priv->viu.vpp_pic_in_height, 384 priv->io_base + _REG(VPP_PIC_IN_HEIGHT)); 385 writel_relaxed(priv->viu.vpp_postblend_vd1_h_start_end, 386 priv->io_base + _REG(VPP_POSTBLEND_VD1_H_START_END)); 387 writel_relaxed(priv->viu.vpp_blend_vd2_h_start_end, 388 priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); 389 writel_relaxed(priv->viu.vpp_postblend_vd1_v_start_end, 390 priv->io_base + _REG(VPP_POSTBLEND_VD1_V_START_END)); 391 writel_relaxed(priv->viu.vpp_blend_vd2_v_start_end, 392 priv->io_base + _REG(VPP_BLEND_VD2_V_START_END)); 393 writel_relaxed(priv->viu.vpp_hsc_region12_startp, 394 priv->io_base + _REG(VPP_HSC_REGION12_STARTP)); 395 writel_relaxed(priv->viu.vpp_hsc_region34_startp, 396 priv->io_base + _REG(VPP_HSC_REGION34_STARTP)); 397 writel_relaxed(priv->viu.vpp_hsc_region4_endp, 398 priv->io_base + _REG(VPP_HSC_REGION4_ENDP)); 399 writel_relaxed(priv->viu.vpp_hsc_start_phase_step, 400 priv->io_base + _REG(VPP_HSC_START_PHASE_STEP)); 401 writel_relaxed(priv->viu.vpp_hsc_region1_phase_slope, 402 priv->io_base + _REG(VPP_HSC_REGION1_PHASE_SLOPE)); 403 writel_relaxed(priv->viu.vpp_hsc_region3_phase_slope, 404 priv->io_base + _REG(VPP_HSC_REGION3_PHASE_SLOPE)); 405 writel_relaxed(priv->viu.vpp_line_in_length, 406 priv->io_base + _REG(VPP_LINE_IN_LENGTH)); 407 writel_relaxed(priv->viu.vpp_preblend_h_size, 408 priv->io_base + _REG(VPP_PREBLEND_H_SIZE)); 409 writel_relaxed(priv->viu.vpp_vsc_region12_startp, 410 priv->io_base + _REG(VPP_VSC_REGION12_STARTP)); 411 writel_relaxed(priv->viu.vpp_vsc_region34_startp, 412 priv->io_base + _REG(VPP_VSC_REGION34_STARTP)); 413 writel_relaxed(priv->viu.vpp_vsc_region4_endp, 414 priv->io_base + _REG(VPP_VSC_REGION4_ENDP)); 415 writel_relaxed(priv->viu.vpp_vsc_start_phase_step, 416 priv->io_base + _REG(VPP_VSC_START_PHASE_STEP)); 417 writel_relaxed(priv->viu.vpp_vsc_ini_phase, 418 priv->io_base + _REG(VPP_VSC_INI_PHASE)); 419 writel_relaxed(priv->viu.vpp_vsc_phase_ctrl, 420 priv->io_base + _REG(VPP_VSC_PHASE_CTRL)); 421 writel_relaxed(priv->viu.vpp_hsc_phase_ctrl, 422 priv->io_base + _REG(VPP_HSC_PHASE_CTRL)); 423 writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); 424 425 /* Enable VD1 */ 426 writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | 427 VPP_COLOR_MNG_ENABLE, 428 VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | 429 VPP_COLOR_MNG_ENABLE, 430 priv->io_base + _REG(VPP_MISC)); 431 432 priv->viu.vd1_commit = false; 433 } 434 435 drm_crtc_handle_vblank(priv->crtc); 436 437 spin_lock_irqsave(&priv->drm->event_lock, flags); 438 if (meson_crtc->event) { 439 drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event); 440 drm_crtc_vblank_put(priv->crtc); 441 meson_crtc->event = NULL; 442 } 443 spin_unlock_irqrestore(&priv->drm->event_lock, flags); 444 } 445 446 int meson_crtc_create(struct meson_drm *priv) 447 { 448 struct meson_crtc *meson_crtc; 449 struct drm_crtc *crtc; 450 int ret; 451 452 meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc), 453 GFP_KERNEL); 454 if (!meson_crtc) 455 return -ENOMEM; 456 457 meson_crtc->priv = priv; 458 crtc = &meson_crtc->base; 459 ret = drm_crtc_init_with_planes(priv->drm, crtc, 460 priv->primary_plane, NULL, 461 &meson_crtc_funcs, "meson_crtc"); 462 if (ret) { 463 dev_err(priv->drm->dev, "Failed to init CRTC\n"); 464 return ret; 465 } 466 467 drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); 468 469 priv->crtc = crtc; 470 471 return 0; 472 } 473