849 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/4 * Author: Rob Clark <rob@ti.com>5 */6 7#include <linux/math64.h>8 9#include <drm/drm_atomic.h>10#include <drm/drm_atomic_helper.h>11#include <drm/drm_crtc.h>12#include <drm/drm_mode.h>13#include <drm/drm_vblank.h>14 15#include "omap_drv.h"16 17#define to_omap_crtc_state(x) container_of(x, struct omap_crtc_state, base)18 19struct omap_crtc_state {20 /* Must be first. */21 struct drm_crtc_state base;22 /* Shadow values for legacy userspace support. */23 unsigned int rotation;24 unsigned int zpos;25 bool manually_updated;26};27 28#define to_omap_crtc(x) container_of(x, struct omap_crtc, base)29 30struct omap_crtc {31 struct drm_crtc base;32 33 const char *name;34 struct omap_drm_pipeline *pipe;35 enum omap_channel channel;36 37 struct videomode vm;38 39 bool ignore_digit_sync_lost;40 41 bool enabled;42 bool pending;43 wait_queue_head_t pending_wait;44 struct drm_pending_vblank_event *event;45 struct delayed_work update_work;46 47 void (*framedone_handler)(void *);48 void *framedone_handler_data;49};50 51/* -----------------------------------------------------------------------------52 * Helper Functions53 */54 55struct videomode *omap_crtc_timings(struct drm_crtc *crtc)56{57 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);58 return &omap_crtc->vm;59}60 61enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)62{63 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);64 return omap_crtc->channel;65}66 67static bool omap_crtc_is_pending(struct drm_crtc *crtc)68{69 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);70 unsigned long flags;71 bool pending;72 73 spin_lock_irqsave(&crtc->dev->event_lock, flags);74 pending = omap_crtc->pending;75 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);76 77 return pending;78}79 80int omap_crtc_wait_pending(struct drm_crtc *crtc)81{82 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);83 84 /*85 * Timeout is set to a "sufficiently" high value, which should cover86 * a single frame refresh even on slower displays.87 */88 return wait_event_timeout(omap_crtc->pending_wait,89 !omap_crtc_is_pending(crtc),90 msecs_to_jiffies(250));91}92 93/* -----------------------------------------------------------------------------94 * DSS Manager Functions95 */96 97/*98 * Manager-ops, callbacks from output when they need to configure99 * the upstream part of the video pipe.100 */101 102void omap_crtc_dss_start_update(struct omap_drm_private *priv,103 enum omap_channel channel)104{105 dispc_mgr_enable(priv->dispc, channel, true);106}107 108/* Called only from the encoder enable/disable and suspend/resume handlers. */109void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)110{111 struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state);112 struct drm_device *dev = crtc->dev;113 struct omap_drm_private *priv = dev->dev_private;114 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);115 enum omap_channel channel = omap_crtc->channel;116 struct omap_irq_wait *wait;117 u32 framedone_irq, vsync_irq;118 int ret;119 120 if (WARN_ON(omap_crtc->enabled == enable))121 return;122 123 if (omap_state->manually_updated) {124 omap_irq_enable_framedone(crtc, enable);125 omap_crtc->enabled = enable;126 return;127 }128 129 if (omap_crtc->pipe->output->type == OMAP_DISPLAY_TYPE_HDMI) {130 dispc_mgr_enable(priv->dispc, channel, enable);131 omap_crtc->enabled = enable;132 return;133 }134 135 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {136 /*137 * Digit output produces some sync lost interrupts during the138 * first frame when enabling, so we need to ignore those.139 */140 omap_crtc->ignore_digit_sync_lost = true;141 }142 143 framedone_irq = dispc_mgr_get_framedone_irq(priv->dispc,144 channel);145 vsync_irq = dispc_mgr_get_vsync_irq(priv->dispc, channel);146 147 if (enable) {148 wait = omap_irq_wait_init(dev, vsync_irq, 1);149 } else {150 /*151 * When we disable the digit output, we need to wait for152 * FRAMEDONE to know that DISPC has finished with the output.153 *154 * OMAP2/3 does not have FRAMEDONE irq for digit output, and in155 * that case we need to use vsync interrupt, and wait for both156 * even and odd frames.157 */158 159 if (framedone_irq)160 wait = omap_irq_wait_init(dev, framedone_irq, 1);161 else162 wait = omap_irq_wait_init(dev, vsync_irq, 2);163 }164 165 dispc_mgr_enable(priv->dispc, channel, enable);166 omap_crtc->enabled = enable;167 168 ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));169 if (ret) {170 dev_err(dev->dev, "%s: timeout waiting for %s\n",171 omap_crtc->name, enable ? "enable" : "disable");172 }173 174 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {175 omap_crtc->ignore_digit_sync_lost = false;176 /* make sure the irq handler sees the value above */177 mb();178 }179}180 181 182int omap_crtc_dss_enable(struct omap_drm_private *priv, enum omap_channel channel)183{184 struct drm_crtc *crtc = priv->channels[channel]->crtc;185 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);186 187 dispc_mgr_set_timings(priv->dispc, omap_crtc->channel,188 &omap_crtc->vm);189 omap_crtc_set_enabled(&omap_crtc->base, true);190 191 return 0;192}193 194void omap_crtc_dss_disable(struct omap_drm_private *priv, enum omap_channel channel)195{196 struct drm_crtc *crtc = priv->channels[channel]->crtc;197 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);198 199 omap_crtc_set_enabled(&omap_crtc->base, false);200}201 202void omap_crtc_dss_set_timings(struct omap_drm_private *priv,203 enum omap_channel channel,204 const struct videomode *vm)205{206 struct drm_crtc *crtc = priv->channels[channel]->crtc;207 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);208 209 DBG("%s", omap_crtc->name);210 omap_crtc->vm = *vm;211}212 213void omap_crtc_dss_set_lcd_config(struct omap_drm_private *priv,214 enum omap_channel channel,215 const struct dss_lcd_mgr_config *config)216{217 struct drm_crtc *crtc = priv->channels[channel]->crtc;218 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);219 220 DBG("%s", omap_crtc->name);221 dispc_mgr_set_lcd_config(priv->dispc, omap_crtc->channel,222 config);223}224 225int omap_crtc_dss_register_framedone(226 struct omap_drm_private *priv, enum omap_channel channel,227 void (*handler)(void *), void *data)228{229 struct drm_crtc *crtc = priv->channels[channel]->crtc;230 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);231 struct drm_device *dev = omap_crtc->base.dev;232 233 if (omap_crtc->framedone_handler)234 return -EBUSY;235 236 dev_dbg(dev->dev, "register framedone %s", omap_crtc->name);237 238 omap_crtc->framedone_handler = handler;239 omap_crtc->framedone_handler_data = data;240 241 return 0;242}243 244void omap_crtc_dss_unregister_framedone(245 struct omap_drm_private *priv, enum omap_channel channel,246 void (*handler)(void *), void *data)247{248 struct drm_crtc *crtc = priv->channels[channel]->crtc;249 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);250 struct drm_device *dev = omap_crtc->base.dev;251 252 dev_dbg(dev->dev, "unregister framedone %s", omap_crtc->name);253 254 WARN_ON(omap_crtc->framedone_handler != handler);255 WARN_ON(omap_crtc->framedone_handler_data != data);256 257 omap_crtc->framedone_handler = NULL;258 omap_crtc->framedone_handler_data = NULL;259}260 261/* -----------------------------------------------------------------------------262 * Setup, Flush and Page Flip263 */264 265void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus)266{267 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);268 269 if (omap_crtc->ignore_digit_sync_lost) {270 irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;271 if (!irqstatus)272 return;273 }274 275 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);276}277 278void omap_crtc_vblank_irq(struct drm_crtc *crtc)279{280 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);281 struct drm_device *dev = omap_crtc->base.dev;282 struct omap_drm_private *priv = dev->dev_private;283 bool pending;284 285 spin_lock(&crtc->dev->event_lock);286 /*287 * If the dispc is busy we're racing the flush operation. Try again on288 * the next vblank interrupt.289 */290 if (dispc_mgr_go_busy(priv->dispc, omap_crtc->channel)) {291 spin_unlock(&crtc->dev->event_lock);292 return;293 }294 295 /* Send the vblank event if one has been requested. */296 if (omap_crtc->event) {297 drm_crtc_send_vblank_event(crtc, omap_crtc->event);298 omap_crtc->event = NULL;299 }300 301 pending = omap_crtc->pending;302 omap_crtc->pending = false;303 spin_unlock(&crtc->dev->event_lock);304 305 if (pending)306 drm_crtc_vblank_put(crtc);307 308 /* Wake up omap_atomic_complete. */309 wake_up(&omap_crtc->pending_wait);310 311 DBG("%s: apply done", omap_crtc->name);312}313 314void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus)315{316 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);317 318 if (!omap_crtc->framedone_handler)319 return;320 321 omap_crtc->framedone_handler(omap_crtc->framedone_handler_data);322 323 spin_lock(&crtc->dev->event_lock);324 /* Send the vblank event if one has been requested. */325 if (omap_crtc->event) {326 drm_crtc_send_vblank_event(crtc, omap_crtc->event);327 omap_crtc->event = NULL;328 }329 omap_crtc->pending = false;330 spin_unlock(&crtc->dev->event_lock);331 332 /* Wake up omap_atomic_complete. */333 wake_up(&omap_crtc->pending_wait);334}335 336void omap_crtc_flush(struct drm_crtc *crtc)337{338 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);339 struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state);340 341 if (!omap_state->manually_updated)342 return;343 344 if (!delayed_work_pending(&omap_crtc->update_work))345 schedule_delayed_work(&omap_crtc->update_work, 0);346}347 348static void omap_crtc_manual_display_update(struct work_struct *data)349{350 struct omap_crtc *omap_crtc =351 container_of(data, struct omap_crtc, update_work.work);352 struct omap_dss_device *dssdev = omap_crtc->pipe->output;353 struct drm_device *dev = omap_crtc->base.dev;354 int ret;355 356 if (!dssdev || !dssdev->dsi_ops || !dssdev->dsi_ops->update)357 return;358 359 ret = dssdev->dsi_ops->update(dssdev);360 if (ret < 0) {361 spin_lock_irq(&dev->event_lock);362 omap_crtc->pending = false;363 spin_unlock_irq(&dev->event_lock);364 wake_up(&omap_crtc->pending_wait);365 }366}367 368static s16 omap_crtc_s31_32_to_s2_8(s64 coef)369{370 u64 sign_bit = 1ULL << 63;371 u64 cbits = (u64)coef;372 373 s16 ret = clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x1ff);374 375 if (cbits & sign_bit)376 ret = -ret;377 378 return ret;379}380 381static void omap_crtc_cpr_coefs_from_ctm(const struct drm_color_ctm *ctm,382 struct omap_dss_cpr_coefs *cpr)383{384 cpr->rr = omap_crtc_s31_32_to_s2_8(ctm->matrix[0]);385 cpr->rg = omap_crtc_s31_32_to_s2_8(ctm->matrix[1]);386 cpr->rb = omap_crtc_s31_32_to_s2_8(ctm->matrix[2]);387 cpr->gr = omap_crtc_s31_32_to_s2_8(ctm->matrix[3]);388 cpr->gg = omap_crtc_s31_32_to_s2_8(ctm->matrix[4]);389 cpr->gb = omap_crtc_s31_32_to_s2_8(ctm->matrix[5]);390 cpr->br = omap_crtc_s31_32_to_s2_8(ctm->matrix[6]);391 cpr->bg = omap_crtc_s31_32_to_s2_8(ctm->matrix[7]);392 cpr->bb = omap_crtc_s31_32_to_s2_8(ctm->matrix[8]);393}394 395static void omap_crtc_write_crtc_properties(struct drm_crtc *crtc)396{397 struct omap_drm_private *priv = crtc->dev->dev_private;398 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);399 struct omap_overlay_manager_info info;400 401 memset(&info, 0, sizeof(info));402 403 info.default_color = 0x000000;404 info.trans_enabled = false;405 info.partial_alpha_enabled = false;406 407 if (crtc->state->ctm) {408 struct drm_color_ctm *ctm = crtc->state->ctm->data;409 410 info.cpr_enable = true;411 omap_crtc_cpr_coefs_from_ctm(ctm, &info.cpr_coefs);412 } else {413 info.cpr_enable = false;414 }415 416 dispc_mgr_setup(priv->dispc, omap_crtc->channel, &info);417}418 419/* -----------------------------------------------------------------------------420 * CRTC Functions421 */422 423static void omap_crtc_destroy(struct drm_crtc *crtc)424{425 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);426 427 DBG("%s", omap_crtc->name);428 429 drm_crtc_cleanup(crtc);430 431 kfree(omap_crtc);432}433 434static void omap_crtc_arm_event(struct drm_crtc *crtc)435{436 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);437 438 WARN_ON(omap_crtc->pending);439 omap_crtc->pending = true;440 441 if (crtc->state->event) {442 omap_crtc->event = crtc->state->event;443 crtc->state->event = NULL;444 }445}446 447static void omap_crtc_atomic_enable(struct drm_crtc *crtc,448 struct drm_atomic_state *state)449{450 struct omap_drm_private *priv = crtc->dev->dev_private;451 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);452 struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state);453 int ret;454 455 DBG("%s", omap_crtc->name);456 457 dispc_runtime_get(priv->dispc);458 459 /* manual updated display will not trigger vsync irq */460 if (omap_state->manually_updated)461 return;462 463 drm_crtc_vblank_on(crtc);464 465 ret = drm_crtc_vblank_get(crtc);466 WARN_ON(ret != 0);467 468 spin_lock_irq(&crtc->dev->event_lock);469 omap_crtc_arm_event(crtc);470 spin_unlock_irq(&crtc->dev->event_lock);471}472 473static void omap_crtc_atomic_disable(struct drm_crtc *crtc,474 struct drm_atomic_state *state)475{476 struct omap_drm_private *priv = crtc->dev->dev_private;477 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);478 struct drm_device *dev = crtc->dev;479 480 DBG("%s", omap_crtc->name);481 482 spin_lock_irq(&crtc->dev->event_lock);483 if (crtc->state->event) {484 drm_crtc_send_vblank_event(crtc, crtc->state->event);485 crtc->state->event = NULL;486 }487 spin_unlock_irq(&crtc->dev->event_lock);488 489 cancel_delayed_work(&omap_crtc->update_work);490 491 if (!omap_crtc_wait_pending(crtc))492 dev_warn(dev->dev, "manual display update did not finish!");493 494 drm_crtc_vblank_off(crtc);495 496 dispc_runtime_put(priv->dispc);497}498 499static enum drm_mode_status omap_crtc_mode_valid(struct drm_crtc *crtc,500 const struct drm_display_mode *mode)501{502 struct omap_drm_private *priv = crtc->dev->dev_private;503 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);504 struct videomode vm = {0};505 int r;506 507 drm_display_mode_to_videomode(mode, &vm);508 509 /*510 * DSI might not call this, since the supplied mode is not a511 * valid DISPC mode. DSI will calculate and configure the512 * proper DISPC mode later.513 */514 if (omap_crtc->pipe->output->type != OMAP_DISPLAY_TYPE_DSI) {515 r = dispc_mgr_check_timings(priv->dispc,516 omap_crtc->channel,517 &vm);518 if (r)519 return r;520 }521 522 /* Check for bandwidth limit */523 if (priv->max_bandwidth) {524 /*525 * Estimation for the bandwidth need of a given mode with one526 * full screen plane:527 * bandwidth = resolution * 32bpp * (pclk / (vtotal * htotal))528 * ^^ Refresh rate ^^529 *530 * The interlaced mode is taken into account by using the531 * pixelclock in the calculation.532 *533 * The equation is rearranged for 64bit arithmetic.534 */535 uint64_t bandwidth = mode->clock * 1000;536 unsigned int bpp = 4;537 538 bandwidth = bandwidth * mode->hdisplay * mode->vdisplay * bpp;539 bandwidth = div_u64(bandwidth, mode->htotal * mode->vtotal);540 541 /*542 * Reject modes which would need more bandwidth if used with one543 * full resolution plane (most common use case).544 */545 if (priv->max_bandwidth < bandwidth)546 return MODE_BAD;547 }548 549 return MODE_OK;550}551 552static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)553{554 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);555 struct drm_display_mode *mode = &crtc->state->adjusted_mode;556 557 DBG("%s: set mode: " DRM_MODE_FMT,558 omap_crtc->name, DRM_MODE_ARG(mode));559 560 drm_display_mode_to_videomode(mode, &omap_crtc->vm);561}562 563static bool omap_crtc_is_manually_updated(struct drm_crtc *crtc)564{565 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);566 struct omap_dss_device *dssdev = omap_crtc->pipe->output;567 568 if (!dssdev || !dssdev->dsi_ops || !dssdev->dsi_ops->is_video_mode)569 return false;570 571 if (dssdev->dsi_ops->is_video_mode(dssdev))572 return false;573 574 DBG("detected manually updated display!");575 return true;576}577 578static int omap_crtc_atomic_check(struct drm_crtc *crtc,579 struct drm_atomic_state *state)580{581 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,582 crtc);583 struct drm_plane_state *pri_state;584 585 if (crtc_state->color_mgmt_changed && crtc_state->degamma_lut) {586 unsigned int length = crtc_state->degamma_lut->length /587 sizeof(struct drm_color_lut);588 589 if (length < 2)590 return -EINVAL;591 }592 593 pri_state = drm_atomic_get_new_plane_state(state,594 crtc->primary);595 if (pri_state) {596 struct omap_crtc_state *omap_crtc_state =597 to_omap_crtc_state(crtc_state);598 599 /* Mirror new values for zpos and rotation in omap_crtc_state */600 omap_crtc_state->zpos = pri_state->zpos;601 omap_crtc_state->rotation = pri_state->rotation;602 603 /* Check if this CRTC is for a manually updated display */604 omap_crtc_state->manually_updated = omap_crtc_is_manually_updated(crtc);605 }606 607 return 0;608}609 610static void omap_crtc_atomic_begin(struct drm_crtc *crtc,611 struct drm_atomic_state *state)612{613}614 615static void omap_crtc_atomic_flush(struct drm_crtc *crtc,616 struct drm_atomic_state *state)617{618 struct omap_drm_private *priv = crtc->dev->dev_private;619 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);620 struct omap_crtc_state *omap_crtc_state = to_omap_crtc_state(crtc->state);621 int ret;622 623 if (crtc->state->color_mgmt_changed) {624 struct drm_color_lut *lut = NULL;625 unsigned int length = 0;626 627 if (crtc->state->degamma_lut) {628 lut = (struct drm_color_lut *)629 crtc->state->degamma_lut->data;630 length = crtc->state->degamma_lut->length /631 sizeof(*lut);632 }633 dispc_mgr_set_gamma(priv->dispc, omap_crtc->channel,634 lut, length);635 }636 637 omap_crtc_write_crtc_properties(crtc);638 639 /* Only flush the CRTC if it is currently enabled. */640 if (!omap_crtc->enabled)641 return;642 643 DBG("%s: GO", omap_crtc->name);644 645 if (omap_crtc_state->manually_updated) {646 /* send new image for page flips and modeset changes */647 spin_lock_irq(&crtc->dev->event_lock);648 omap_crtc_flush(crtc);649 omap_crtc_arm_event(crtc);650 spin_unlock_irq(&crtc->dev->event_lock);651 return;652 }653 654 ret = drm_crtc_vblank_get(crtc);655 WARN_ON(ret != 0);656 657 spin_lock_irq(&crtc->dev->event_lock);658 dispc_mgr_go(priv->dispc, omap_crtc->channel);659 omap_crtc_arm_event(crtc);660 spin_unlock_irq(&crtc->dev->event_lock);661}662 663static int omap_crtc_atomic_set_property(struct drm_crtc *crtc,664 struct drm_crtc_state *state,665 struct drm_property *property,666 u64 val)667{668 struct omap_drm_private *priv = crtc->dev->dev_private;669 struct drm_plane_state *plane_state;670 671 /*672 * Delegate property set to the primary plane. Get the plane state and673 * set the property directly, the shadow copy will be assigned in the674 * omap_crtc_atomic_check callback. This way updates to plane state will675 * always be mirrored in the crtc state correctly.676 */677 plane_state = drm_atomic_get_plane_state(state->state, crtc->primary);678 if (IS_ERR(plane_state))679 return PTR_ERR(plane_state);680 681 if (property == crtc->primary->rotation_property)682 plane_state->rotation = val;683 else if (property == priv->zorder_prop)684 plane_state->zpos = val;685 else686 return -EINVAL;687 688 return 0;689}690 691static int omap_crtc_atomic_get_property(struct drm_crtc *crtc,692 const struct drm_crtc_state *state,693 struct drm_property *property,694 u64 *val)695{696 struct omap_drm_private *priv = crtc->dev->dev_private;697 struct omap_crtc_state *omap_state = to_omap_crtc_state(state);698 699 if (property == crtc->primary->rotation_property)700 *val = omap_state->rotation;701 else if (property == priv->zorder_prop)702 *val = omap_state->zpos;703 else704 return -EINVAL;705 706 return 0;707}708 709static void omap_crtc_reset(struct drm_crtc *crtc)710{711 struct omap_crtc_state *state;712 713 if (crtc->state)714 __drm_atomic_helper_crtc_destroy_state(crtc->state);715 716 kfree(crtc->state);717 718 state = kzalloc(sizeof(*state), GFP_KERNEL);719 if (state)720 __drm_atomic_helper_crtc_reset(crtc, &state->base);721}722 723static struct drm_crtc_state *724omap_crtc_duplicate_state(struct drm_crtc *crtc)725{726 struct omap_crtc_state *state, *current_state;727 728 if (WARN_ON(!crtc->state))729 return NULL;730 731 current_state = to_omap_crtc_state(crtc->state);732 733 state = kmalloc(sizeof(*state), GFP_KERNEL);734 if (!state)735 return NULL;736 737 __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);738 739 state->zpos = current_state->zpos;740 state->rotation = current_state->rotation;741 state->manually_updated = current_state->manually_updated;742 743 return &state->base;744}745 746static const struct drm_crtc_funcs omap_crtc_funcs = {747 .reset = omap_crtc_reset,748 .set_config = drm_atomic_helper_set_config,749 .destroy = omap_crtc_destroy,750 .page_flip = drm_atomic_helper_page_flip,751 .atomic_duplicate_state = omap_crtc_duplicate_state,752 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,753 .atomic_set_property = omap_crtc_atomic_set_property,754 .atomic_get_property = omap_crtc_atomic_get_property,755 .enable_vblank = omap_irq_enable_vblank,756 .disable_vblank = omap_irq_disable_vblank,757};758 759static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {760 .mode_set_nofb = omap_crtc_mode_set_nofb,761 .atomic_check = omap_crtc_atomic_check,762 .atomic_begin = omap_crtc_atomic_begin,763 .atomic_flush = omap_crtc_atomic_flush,764 .atomic_enable = omap_crtc_atomic_enable,765 .atomic_disable = omap_crtc_atomic_disable,766 .mode_valid = omap_crtc_mode_valid,767};768 769/* -----------------------------------------------------------------------------770 * Init and Cleanup771 */772 773static const char *channel_names[] = {774 [OMAP_DSS_CHANNEL_LCD] = "lcd",775 [OMAP_DSS_CHANNEL_DIGIT] = "tv",776 [OMAP_DSS_CHANNEL_LCD2] = "lcd2",777 [OMAP_DSS_CHANNEL_LCD3] = "lcd3",778};779 780/* initialize crtc */781struct drm_crtc *omap_crtc_init(struct drm_device *dev,782 struct omap_drm_pipeline *pipe,783 struct drm_plane *plane)784{785 struct omap_drm_private *priv = dev->dev_private;786 struct drm_crtc *crtc = NULL;787 struct omap_crtc *omap_crtc;788 enum omap_channel channel;789 int ret;790 791 channel = pipe->output->dispc_channel;792 793 DBG("%s", channel_names[channel]);794 795 omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);796 if (!omap_crtc)797 return ERR_PTR(-ENOMEM);798 799 crtc = &omap_crtc->base;800 801 init_waitqueue_head(&omap_crtc->pending_wait);802 803 omap_crtc->pipe = pipe;804 omap_crtc->channel = channel;805 omap_crtc->name = channel_names[channel];806 807 /*808 * We want to refresh manually updated displays from dirty callback,809 * which is called quite often (e.g. for each drawn line). This will810 * be used to do the display update asynchronously to avoid blocking811 * the rendering process and merges multiple dirty calls into one812 * update if they arrive very fast. We also call this function for813 * atomic display updates (e.g. for page flips), which means we do814 * not need extra locking. Atomic updates should be synchronous, but815 * need to wait for the framedone interrupt anyways.816 */817 INIT_DELAYED_WORK(&omap_crtc->update_work,818 omap_crtc_manual_display_update);819 820 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,821 &omap_crtc_funcs, NULL);822 if (ret < 0) {823 dev_err(dev->dev, "%s(): could not init crtc for: %s\n",824 __func__, pipe->output->name);825 kfree(omap_crtc);826 return ERR_PTR(ret);827 }828 829 drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);830 831 /* The dispc API adapts to what ever size, but the HW supports832 * 256 element gamma table for LCDs and 1024 element table for833 * OMAP_DSS_CHANNEL_DIGIT. X server assumes 256 element gamma834 * tables so lets use that. Size of HW gamma table can be835 * extracted with dispc_mgr_gamma_size(). If it returns 0836 * gamma table is not supported.837 */838 if (dispc_mgr_gamma_size(priv->dispc, channel)) {839 unsigned int gamma_lut_size = 256;840 841 drm_crtc_enable_color_mgmt(crtc, gamma_lut_size, true, 0);842 drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size);843 }844 845 omap_plane_install_properties(crtc->primary, &crtc->base);846 847 return crtc;848}849