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_crtc_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 bool enabled; 50 }; 51 #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) 52 53 /* CRTC */ 54 55 static int meson_crtc_enable_vblank(struct drm_crtc *crtc) 56 { 57 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 58 struct meson_drm *priv = meson_crtc->priv; 59 60 meson_venc_enable_vsync(priv); 61 62 return 0; 63 } 64 65 static void meson_crtc_disable_vblank(struct drm_crtc *crtc) 66 { 67 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 68 struct meson_drm *priv = meson_crtc->priv; 69 70 meson_venc_disable_vsync(priv); 71 } 72 73 static const struct drm_crtc_funcs meson_crtc_funcs = { 74 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 75 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 76 .destroy = drm_crtc_cleanup, 77 .page_flip = drm_atomic_helper_page_flip, 78 .reset = drm_atomic_helper_crtc_reset, 79 .set_config = drm_atomic_helper_set_config, 80 .enable_vblank = meson_crtc_enable_vblank, 81 .disable_vblank = meson_crtc_disable_vblank, 82 83 }; 84 85 static void meson_crtc_enable(struct drm_crtc *crtc) 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 meson_crtc->enabled = true; 112 } 113 114 static void meson_crtc_atomic_enable(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 if (!meson_crtc->enabled) 123 meson_crtc_enable(crtc); 124 125 priv->viu.osd1_enabled = true; 126 } 127 128 static void meson_crtc_atomic_disable(struct drm_crtc *crtc, 129 struct drm_crtc_state *old_state) 130 { 131 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 132 struct meson_drm *priv = meson_crtc->priv; 133 134 DRM_DEBUG_DRIVER("\n"); 135 136 drm_crtc_vblank_off(crtc); 137 138 priv->viu.osd1_enabled = false; 139 priv->viu.osd1_commit = false; 140 141 priv->viu.vd1_enabled = false; 142 priv->viu.vd1_commit = false; 143 144 /* Disable VPP Postblend */ 145 writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_VD1_POSTBLEND | 146 VPP_VD1_PREBLEND | VPP_POSTBLEND_ENABLE, 0, 147 priv->io_base + _REG(VPP_MISC)); 148 149 if (crtc->state->event && !crtc->state->active) { 150 spin_lock_irq(&crtc->dev->event_lock); 151 drm_crtc_send_vblank_event(crtc, crtc->state->event); 152 spin_unlock_irq(&crtc->dev->event_lock); 153 154 crtc->state->event = NULL; 155 } 156 157 meson_crtc->enabled = false; 158 } 159 160 static void meson_crtc_atomic_begin(struct drm_crtc *crtc, 161 struct drm_crtc_state *state) 162 { 163 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 164 unsigned long flags; 165 166 if (crtc->state->enable && !meson_crtc->enabled) 167 meson_crtc_enable(crtc); 168 169 if (crtc->state->event) { 170 WARN_ON(drm_crtc_vblank_get(crtc) != 0); 171 172 spin_lock_irqsave(&crtc->dev->event_lock, flags); 173 meson_crtc->event = crtc->state->event; 174 spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 175 crtc->state->event = NULL; 176 } 177 } 178 179 static void meson_crtc_atomic_flush(struct drm_crtc *crtc, 180 struct drm_crtc_state *old_crtc_state) 181 { 182 struct meson_crtc *meson_crtc = to_meson_crtc(crtc); 183 struct meson_drm *priv = meson_crtc->priv; 184 185 priv->viu.osd1_commit = true; 186 priv->viu.vd1_commit = true; 187 } 188 189 static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { 190 .atomic_begin = meson_crtc_atomic_begin, 191 .atomic_flush = meson_crtc_atomic_flush, 192 .atomic_enable = meson_crtc_atomic_enable, 193 .atomic_disable = meson_crtc_atomic_disable, 194 }; 195 196 void meson_crtc_irq(struct meson_drm *priv) 197 { 198 struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc); 199 unsigned long flags; 200 201 /* Update the OSD registers */ 202 if (priv->viu.osd1_enabled && priv->viu.osd1_commit) { 203 writel_relaxed(priv->viu.osd1_ctrl_stat, 204 priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); 205 writel_relaxed(priv->viu.osd1_blk0_cfg[0], 206 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0)); 207 writel_relaxed(priv->viu.osd1_blk0_cfg[1], 208 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1)); 209 writel_relaxed(priv->viu.osd1_blk0_cfg[2], 210 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2)); 211 writel_relaxed(priv->viu.osd1_blk0_cfg[3], 212 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3)); 213 writel_relaxed(priv->viu.osd1_blk0_cfg[4], 214 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4)); 215 writel_relaxed(priv->viu.osd_sc_ctrl0, 216 priv->io_base + _REG(VPP_OSD_SC_CTRL0)); 217 writel_relaxed(priv->viu.osd_sc_i_wh_m1, 218 priv->io_base + _REG(VPP_OSD_SCI_WH_M1)); 219 writel_relaxed(priv->viu.osd_sc_o_h_start_end, 220 priv->io_base + _REG(VPP_OSD_SCO_H_START_END)); 221 writel_relaxed(priv->viu.osd_sc_o_v_start_end, 222 priv->io_base + _REG(VPP_OSD_SCO_V_START_END)); 223 writel_relaxed(priv->viu.osd_sc_v_ini_phase, 224 priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE)); 225 writel_relaxed(priv->viu.osd_sc_v_phase_step, 226 priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP)); 227 writel_relaxed(priv->viu.osd_sc_h_ini_phase, 228 priv->io_base + _REG(VPP_OSD_HSC_INI_PHASE)); 229 writel_relaxed(priv->viu.osd_sc_h_phase_step, 230 priv->io_base + _REG(VPP_OSD_HSC_PHASE_STEP)); 231 writel_relaxed(priv->viu.osd_sc_h_ctrl0, 232 priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); 233 writel_relaxed(priv->viu.osd_sc_v_ctrl0, 234 priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); 235 236 if (priv->canvas) 237 meson_canvas_config(priv->canvas, priv->canvas_id_osd1, 238 priv->viu.osd1_addr, priv->viu.osd1_stride, 239 priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, 240 MESON_CANVAS_BLKMODE_LINEAR, 0); 241 else 242 meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, 243 priv->viu.osd1_addr, priv->viu.osd1_stride, 244 priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, 245 MESON_CANVAS_BLKMODE_LINEAR, 0); 246 247 /* Enable OSD1 */ 248 writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, 249 priv->io_base + _REG(VPP_MISC)); 250 251 priv->viu.osd1_commit = false; 252 } 253 254 /* Update the VD1 registers */ 255 if (priv->viu.vd1_enabled && priv->viu.vd1_commit) { 256 257 switch (priv->viu.vd1_planes) { 258 case 3: 259 if (priv->canvas) 260 meson_canvas_config(priv->canvas, 261 priv->canvas_id_vd1_2, 262 priv->viu.vd1_addr2, 263 priv->viu.vd1_stride2, 264 priv->viu.vd1_height2, 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_2, 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 2: 278 if (priv->canvas) 279 meson_canvas_config(priv->canvas, 280 priv->canvas_id_vd1_1, 281 priv->viu.vd1_addr1, 282 priv->viu.vd1_stride1, 283 priv->viu.vd1_height1, 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_1, 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 /* fallthrough */ 296 case 1: 297 if (priv->canvas) 298 meson_canvas_config(priv->canvas, 299 priv->canvas_id_vd1_0, 300 priv->viu.vd1_addr0, 301 priv->viu.vd1_stride0, 302 priv->viu.vd1_height0, 303 MESON_CANVAS_WRAP_NONE, 304 MESON_CANVAS_BLKMODE_LINEAR, 305 MESON_CANVAS_ENDIAN_SWAP64); 306 else 307 meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_0, 308 priv->viu.vd1_addr2, 309 priv->viu.vd1_stride2, 310 priv->viu.vd1_height2, 311 MESON_CANVAS_WRAP_NONE, 312 MESON_CANVAS_BLKMODE_LINEAR, 313 MESON_CANVAS_ENDIAN_SWAP64); 314 }; 315 316 writel_relaxed(priv->viu.vd1_if0_gen_reg, 317 priv->io_base + _REG(VD1_IF0_GEN_REG)); 318 writel_relaxed(priv->viu.vd1_if0_gen_reg, 319 priv->io_base + _REG(VD2_IF0_GEN_REG)); 320 writel_relaxed(priv->viu.vd1_if0_gen_reg2, 321 priv->io_base + _REG(VD1_IF0_GEN_REG2)); 322 writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, 323 priv->io_base + _REG(VIU_VD1_FMT_CTRL)); 324 writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, 325 priv->io_base + _REG(VIU_VD2_FMT_CTRL)); 326 writel_relaxed(priv->viu.viu_vd1_fmt_w, 327 priv->io_base + _REG(VIU_VD1_FMT_W)); 328 writel_relaxed(priv->viu.viu_vd1_fmt_w, 329 priv->io_base + _REG(VIU_VD2_FMT_W)); 330 writel_relaxed(priv->viu.vd1_if0_canvas0, 331 priv->io_base + _REG(VD1_IF0_CANVAS0)); 332 writel_relaxed(priv->viu.vd1_if0_canvas0, 333 priv->io_base + _REG(VD1_IF0_CANVAS1)); 334 writel_relaxed(priv->viu.vd1_if0_canvas0, 335 priv->io_base + _REG(VD2_IF0_CANVAS0)); 336 writel_relaxed(priv->viu.vd1_if0_canvas0, 337 priv->io_base + _REG(VD2_IF0_CANVAS1)); 338 writel_relaxed(priv->viu.vd1_if0_luma_x0, 339 priv->io_base + _REG(VD1_IF0_LUMA_X0)); 340 writel_relaxed(priv->viu.vd1_if0_luma_x0, 341 priv->io_base + _REG(VD1_IF0_LUMA_X1)); 342 writel_relaxed(priv->viu.vd1_if0_luma_x0, 343 priv->io_base + _REG(VD2_IF0_LUMA_X0)); 344 writel_relaxed(priv->viu.vd1_if0_luma_x0, 345 priv->io_base + _REG(VD2_IF0_LUMA_X1)); 346 writel_relaxed(priv->viu.vd1_if0_luma_y0, 347 priv->io_base + _REG(VD1_IF0_LUMA_Y0)); 348 writel_relaxed(priv->viu.vd1_if0_luma_y0, 349 priv->io_base + _REG(VD1_IF0_LUMA_Y1)); 350 writel_relaxed(priv->viu.vd1_if0_luma_y0, 351 priv->io_base + _REG(VD2_IF0_LUMA_Y0)); 352 writel_relaxed(priv->viu.vd1_if0_luma_y0, 353 priv->io_base + _REG(VD2_IF0_LUMA_Y1)); 354 writel_relaxed(priv->viu.vd1_if0_chroma_x0, 355 priv->io_base + _REG(VD1_IF0_CHROMA_X0)); 356 writel_relaxed(priv->viu.vd1_if0_chroma_x0, 357 priv->io_base + _REG(VD1_IF0_CHROMA_X1)); 358 writel_relaxed(priv->viu.vd1_if0_chroma_x0, 359 priv->io_base + _REG(VD2_IF0_CHROMA_X0)); 360 writel_relaxed(priv->viu.vd1_if0_chroma_x0, 361 priv->io_base + _REG(VD2_IF0_CHROMA_X1)); 362 writel_relaxed(priv->viu.vd1_if0_chroma_y0, 363 priv->io_base + _REG(VD1_IF0_CHROMA_Y0)); 364 writel_relaxed(priv->viu.vd1_if0_chroma_y0, 365 priv->io_base + _REG(VD1_IF0_CHROMA_Y1)); 366 writel_relaxed(priv->viu.vd1_if0_chroma_y0, 367 priv->io_base + _REG(VD2_IF0_CHROMA_Y0)); 368 writel_relaxed(priv->viu.vd1_if0_chroma_y0, 369 priv->io_base + _REG(VD2_IF0_CHROMA_Y1)); 370 writel_relaxed(priv->viu.vd1_if0_repeat_loop, 371 priv->io_base + _REG(VD1_IF0_RPT_LOOP)); 372 writel_relaxed(priv->viu.vd1_if0_repeat_loop, 373 priv->io_base + _REG(VD2_IF0_RPT_LOOP)); 374 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, 375 priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT)); 376 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, 377 priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT)); 378 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, 379 priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT)); 380 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, 381 priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT)); 382 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, 383 priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT)); 384 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, 385 priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT)); 386 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, 387 priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT)); 388 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, 389 priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT)); 390 writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL)); 391 writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL)); 392 writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL)); 393 writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL)); 394 writel_relaxed(priv->viu.vd1_range_map_y, 395 priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y)); 396 writel_relaxed(priv->viu.vd1_range_map_cb, 397 priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB)); 398 writel_relaxed(priv->viu.vd1_range_map_cr, 399 priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR)); 400 writel_relaxed(0x78404, 401 priv->io_base + _REG(VPP_SC_MISC)); 402 writel_relaxed(priv->viu.vpp_pic_in_height, 403 priv->io_base + _REG(VPP_PIC_IN_HEIGHT)); 404 writel_relaxed(priv->viu.vpp_postblend_vd1_h_start_end, 405 priv->io_base + _REG(VPP_POSTBLEND_VD1_H_START_END)); 406 writel_relaxed(priv->viu.vpp_blend_vd2_h_start_end, 407 priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); 408 writel_relaxed(priv->viu.vpp_postblend_vd1_v_start_end, 409 priv->io_base + _REG(VPP_POSTBLEND_VD1_V_START_END)); 410 writel_relaxed(priv->viu.vpp_blend_vd2_v_start_end, 411 priv->io_base + _REG(VPP_BLEND_VD2_V_START_END)); 412 writel_relaxed(priv->viu.vpp_hsc_region12_startp, 413 priv->io_base + _REG(VPP_HSC_REGION12_STARTP)); 414 writel_relaxed(priv->viu.vpp_hsc_region34_startp, 415 priv->io_base + _REG(VPP_HSC_REGION34_STARTP)); 416 writel_relaxed(priv->viu.vpp_hsc_region4_endp, 417 priv->io_base + _REG(VPP_HSC_REGION4_ENDP)); 418 writel_relaxed(priv->viu.vpp_hsc_start_phase_step, 419 priv->io_base + _REG(VPP_HSC_START_PHASE_STEP)); 420 writel_relaxed(priv->viu.vpp_hsc_region1_phase_slope, 421 priv->io_base + _REG(VPP_HSC_REGION1_PHASE_SLOPE)); 422 writel_relaxed(priv->viu.vpp_hsc_region3_phase_slope, 423 priv->io_base + _REG(VPP_HSC_REGION3_PHASE_SLOPE)); 424 writel_relaxed(priv->viu.vpp_line_in_length, 425 priv->io_base + _REG(VPP_LINE_IN_LENGTH)); 426 writel_relaxed(priv->viu.vpp_preblend_h_size, 427 priv->io_base + _REG(VPP_PREBLEND_H_SIZE)); 428 writel_relaxed(priv->viu.vpp_vsc_region12_startp, 429 priv->io_base + _REG(VPP_VSC_REGION12_STARTP)); 430 writel_relaxed(priv->viu.vpp_vsc_region34_startp, 431 priv->io_base + _REG(VPP_VSC_REGION34_STARTP)); 432 writel_relaxed(priv->viu.vpp_vsc_region4_endp, 433 priv->io_base + _REG(VPP_VSC_REGION4_ENDP)); 434 writel_relaxed(priv->viu.vpp_vsc_start_phase_step, 435 priv->io_base + _REG(VPP_VSC_START_PHASE_STEP)); 436 writel_relaxed(priv->viu.vpp_vsc_ini_phase, 437 priv->io_base + _REG(VPP_VSC_INI_PHASE)); 438 writel_relaxed(priv->viu.vpp_vsc_phase_ctrl, 439 priv->io_base + _REG(VPP_VSC_PHASE_CTRL)); 440 writel_relaxed(priv->viu.vpp_hsc_phase_ctrl, 441 priv->io_base + _REG(VPP_HSC_PHASE_CTRL)); 442 writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); 443 444 /* Enable VD1 */ 445 writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | 446 VPP_COLOR_MNG_ENABLE, 447 VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | 448 VPP_COLOR_MNG_ENABLE, 449 priv->io_base + _REG(VPP_MISC)); 450 451 priv->viu.vd1_commit = false; 452 } 453 454 drm_crtc_handle_vblank(priv->crtc); 455 456 spin_lock_irqsave(&priv->drm->event_lock, flags); 457 if (meson_crtc->event) { 458 drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event); 459 drm_crtc_vblank_put(priv->crtc); 460 meson_crtc->event = NULL; 461 } 462 spin_unlock_irqrestore(&priv->drm->event_lock, flags); 463 } 464 465 int meson_crtc_create(struct meson_drm *priv) 466 { 467 struct meson_crtc *meson_crtc; 468 struct drm_crtc *crtc; 469 int ret; 470 471 meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc), 472 GFP_KERNEL); 473 if (!meson_crtc) 474 return -ENOMEM; 475 476 meson_crtc->priv = priv; 477 crtc = &meson_crtc->base; 478 ret = drm_crtc_init_with_planes(priv->drm, crtc, 479 priv->primary_plane, NULL, 480 &meson_crtc_funcs, "meson_crtc"); 481 if (ret) { 482 dev_err(priv->drm->dev, "Failed to init CRTC\n"); 483 return ret; 484 } 485 486 drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); 487 488 priv->crtc = crtc; 489 490 return 0; 491 } 492