132a1795fSJyri Sarha // SPDX-License-Identifier: GPL-2.0 232a1795fSJyri Sarha /* 332a1795fSJyri Sarha * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 432a1795fSJyri Sarha * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 532a1795fSJyri Sarha */ 632a1795fSJyri Sarha 732a1795fSJyri Sarha #include <drm/drm_atomic.h> 832a1795fSJyri Sarha #include <drm/drm_atomic_helper.h> 932a1795fSJyri Sarha #include <drm/drm_crtc.h> 1032a1795fSJyri Sarha #include <drm/drm_crtc_helper.h> 1132a1795fSJyri Sarha #include <drm/drm_fb_cma_helper.h> 1232a1795fSJyri Sarha #include <drm/drm_gem_cma_helper.h> 1332a1795fSJyri Sarha #include <drm/drm_plane_helper.h> 1432a1795fSJyri Sarha #include <drm/drm_vblank.h> 1532a1795fSJyri Sarha 1632a1795fSJyri Sarha #include "tidss_crtc.h" 1732a1795fSJyri Sarha #include "tidss_dispc.h" 1832a1795fSJyri Sarha #include "tidss_drv.h" 1932a1795fSJyri Sarha #include "tidss_irq.h" 20b33b5474SJyri Sarha #include "tidss_plane.h" 2132a1795fSJyri Sarha 2232a1795fSJyri Sarha /* Page flip and frame done IRQs */ 2332a1795fSJyri Sarha 2432a1795fSJyri Sarha static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc) 2532a1795fSJyri Sarha { 2632a1795fSJyri Sarha struct drm_device *ddev = tcrtc->crtc.dev; 2732a1795fSJyri Sarha struct tidss_device *tidss = ddev->dev_private; 2832a1795fSJyri Sarha struct drm_pending_vblank_event *event; 2932a1795fSJyri Sarha unsigned long flags; 3032a1795fSJyri Sarha bool busy; 3132a1795fSJyri Sarha 3232a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags); 3332a1795fSJyri Sarha 3432a1795fSJyri Sarha /* 3532a1795fSJyri Sarha * New settings are taken into use at VFP, and GO bit is cleared at 3632a1795fSJyri Sarha * the same time. This happens before the vertical blank interrupt. 3732a1795fSJyri Sarha * So there is a small change that the driver sets GO bit after VFP, but 3832a1795fSJyri Sarha * before vblank, and we have to check for that case here. 3932a1795fSJyri Sarha */ 4032a1795fSJyri Sarha busy = dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport); 4132a1795fSJyri Sarha if (busy) { 4232a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 4332a1795fSJyri Sarha return; 4432a1795fSJyri Sarha } 4532a1795fSJyri Sarha 4632a1795fSJyri Sarha event = tcrtc->event; 4732a1795fSJyri Sarha tcrtc->event = NULL; 4832a1795fSJyri Sarha 4932a1795fSJyri Sarha if (!event) { 5032a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 5132a1795fSJyri Sarha return; 5232a1795fSJyri Sarha } 5332a1795fSJyri Sarha 5432a1795fSJyri Sarha drm_crtc_send_vblank_event(&tcrtc->crtc, event); 5532a1795fSJyri Sarha 5632a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 5732a1795fSJyri Sarha 5832a1795fSJyri Sarha drm_crtc_vblank_put(&tcrtc->crtc); 5932a1795fSJyri Sarha } 6032a1795fSJyri Sarha 6132a1795fSJyri Sarha void tidss_crtc_vblank_irq(struct drm_crtc *crtc) 6232a1795fSJyri Sarha { 6332a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 6432a1795fSJyri Sarha 6532a1795fSJyri Sarha drm_crtc_handle_vblank(crtc); 6632a1795fSJyri Sarha 6732a1795fSJyri Sarha tidss_crtc_finish_page_flip(tcrtc); 6832a1795fSJyri Sarha } 6932a1795fSJyri Sarha 7032a1795fSJyri Sarha void tidss_crtc_framedone_irq(struct drm_crtc *crtc) 7132a1795fSJyri Sarha { 7232a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 7332a1795fSJyri Sarha 7432a1795fSJyri Sarha complete(&tcrtc->framedone_completion); 7532a1795fSJyri Sarha } 7632a1795fSJyri Sarha 7732a1795fSJyri Sarha void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus) 7832a1795fSJyri Sarha { 7932a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 8032a1795fSJyri Sarha 8132a1795fSJyri Sarha dev_err_ratelimited(crtc->dev->dev, "CRTC%u SYNC LOST: (irq %llx)\n", 8232a1795fSJyri Sarha tcrtc->hw_videoport, irqstatus); 8332a1795fSJyri Sarha } 8432a1795fSJyri Sarha 8532a1795fSJyri Sarha /* drm_crtc_helper_funcs */ 8632a1795fSJyri Sarha 8732a1795fSJyri Sarha static int tidss_crtc_atomic_check(struct drm_crtc *crtc, 8832a1795fSJyri Sarha struct drm_crtc_state *state) 8932a1795fSJyri Sarha { 9032a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 9132a1795fSJyri Sarha struct tidss_device *tidss = ddev->dev_private; 9232a1795fSJyri Sarha struct dispc_device *dispc = tidss->dispc; 9332a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 9432a1795fSJyri Sarha u32 hw_videoport = tcrtc->hw_videoport; 9532a1795fSJyri Sarha const struct drm_display_mode *mode; 9632a1795fSJyri Sarha enum drm_mode_status ok; 9732a1795fSJyri Sarha 9832a1795fSJyri Sarha dev_dbg(ddev->dev, "%s\n", __func__); 9932a1795fSJyri Sarha 10032a1795fSJyri Sarha if (!state->enable) 10132a1795fSJyri Sarha return 0; 10232a1795fSJyri Sarha 10332a1795fSJyri Sarha mode = &state->adjusted_mode; 10432a1795fSJyri Sarha 10532a1795fSJyri Sarha ok = dispc_vp_mode_valid(dispc, hw_videoport, mode); 10632a1795fSJyri Sarha if (ok != MODE_OK) { 10732a1795fSJyri Sarha dev_dbg(ddev->dev, "%s: bad mode: %ux%u pclk %u kHz\n", 10832a1795fSJyri Sarha __func__, mode->hdisplay, mode->vdisplay, mode->clock); 10932a1795fSJyri Sarha return -EINVAL; 11032a1795fSJyri Sarha } 11132a1795fSJyri Sarha 11232a1795fSJyri Sarha return dispc_vp_bus_check(dispc, hw_videoport, state); 11332a1795fSJyri Sarha } 11432a1795fSJyri Sarha 115b33b5474SJyri Sarha /* 116b33b5474SJyri Sarha * This needs all affected planes to be present in the atomic 117b33b5474SJyri Sarha * state. The untouched planes are added to the state in 118b33b5474SJyri Sarha * tidss_atomic_check(). 119b33b5474SJyri Sarha */ 120b33b5474SJyri Sarha static void tidss_crtc_position_planes(struct tidss_device *tidss, 121b33b5474SJyri Sarha struct drm_crtc *crtc, 122b33b5474SJyri Sarha struct drm_crtc_state *old_state, 123b33b5474SJyri Sarha bool newmodeset) 124b33b5474SJyri Sarha { 125b33b5474SJyri Sarha struct drm_atomic_state *ostate = old_state->state; 126b33b5474SJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 127b33b5474SJyri Sarha struct drm_crtc_state *cstate = crtc->state; 128b33b5474SJyri Sarha int layer; 129b33b5474SJyri Sarha 130b33b5474SJyri Sarha if (!newmodeset && !cstate->zpos_changed && 131b33b5474SJyri Sarha !to_tidss_crtc_state(cstate)->plane_pos_changed) 132b33b5474SJyri Sarha return; 133b33b5474SJyri Sarha 134b33b5474SJyri Sarha for (layer = 0; layer < tidss->feat->num_planes; layer++) { 135b33b5474SJyri Sarha struct drm_plane_state *pstate; 136b33b5474SJyri Sarha struct drm_plane *plane; 137b33b5474SJyri Sarha bool layer_active = false; 138b33b5474SJyri Sarha int i; 139b33b5474SJyri Sarha 140b33b5474SJyri Sarha for_each_new_plane_in_state(ostate, plane, pstate, i) { 141b33b5474SJyri Sarha if (pstate->crtc != crtc || !pstate->visible) 142b33b5474SJyri Sarha continue; 143b33b5474SJyri Sarha 144b33b5474SJyri Sarha if (pstate->normalized_zpos == layer) { 145b33b5474SJyri Sarha layer_active = true; 146b33b5474SJyri Sarha break; 147b33b5474SJyri Sarha } 148b33b5474SJyri Sarha } 149b33b5474SJyri Sarha 150b33b5474SJyri Sarha if (layer_active) { 151b33b5474SJyri Sarha struct tidss_plane *tplane = to_tidss_plane(plane); 152b33b5474SJyri Sarha 153b33b5474SJyri Sarha dispc_ovr_set_plane(tidss->dispc, tplane->hw_plane_id, 154b33b5474SJyri Sarha tcrtc->hw_videoport, 155b33b5474SJyri Sarha pstate->crtc_x, pstate->crtc_y, 156b33b5474SJyri Sarha layer); 157b33b5474SJyri Sarha } 158b33b5474SJyri Sarha dispc_ovr_enable_layer(tidss->dispc, tcrtc->hw_videoport, layer, 159b33b5474SJyri Sarha layer_active); 160b33b5474SJyri Sarha } 161b33b5474SJyri Sarha } 162b33b5474SJyri Sarha 16332a1795fSJyri Sarha static void tidss_crtc_atomic_flush(struct drm_crtc *crtc, 16432a1795fSJyri Sarha struct drm_crtc_state *old_crtc_state) 16532a1795fSJyri Sarha { 16632a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 16732a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 16832a1795fSJyri Sarha struct tidss_device *tidss = ddev->dev_private; 16932a1795fSJyri Sarha unsigned long flags; 17032a1795fSJyri Sarha 17132a1795fSJyri Sarha dev_dbg(ddev->dev, 17232a1795fSJyri Sarha "%s: %s enabled %d, needs modeset %d, event %p\n", __func__, 17332a1795fSJyri Sarha crtc->name, drm_atomic_crtc_needs_modeset(crtc->state), 17432a1795fSJyri Sarha crtc->state->enable, crtc->state->event); 17532a1795fSJyri Sarha 17632a1795fSJyri Sarha /* There is nothing to do if CRTC is not going to be enabled. */ 17732a1795fSJyri Sarha if (!crtc->state->enable) 17832a1795fSJyri Sarha return; 17932a1795fSJyri Sarha 18032a1795fSJyri Sarha /* 18132a1795fSJyri Sarha * Flush CRTC changes with go bit only if new modeset is not 18232a1795fSJyri Sarha * coming, so CRTC is enabled trough out the commit. 18332a1795fSJyri Sarha */ 18432a1795fSJyri Sarha if (drm_atomic_crtc_needs_modeset(crtc->state)) 18532a1795fSJyri Sarha return; 18632a1795fSJyri Sarha 18732a1795fSJyri Sarha /* If the GO bit is stuck we better quit here. */ 18832a1795fSJyri Sarha if (WARN_ON(dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport))) 18932a1795fSJyri Sarha return; 19032a1795fSJyri Sarha 19132a1795fSJyri Sarha /* We should have event if CRTC is enabled through out this commit. */ 19232a1795fSJyri Sarha if (WARN_ON(!crtc->state->event)) 19332a1795fSJyri Sarha return; 19432a1795fSJyri Sarha 19532a1795fSJyri Sarha /* Write vp properties to HW if needed. */ 19632a1795fSJyri Sarha dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false); 19732a1795fSJyri Sarha 198b33b5474SJyri Sarha /* Update plane positions if needed. */ 199b33b5474SJyri Sarha tidss_crtc_position_planes(tidss, crtc, old_crtc_state, false); 200b33b5474SJyri Sarha 20132a1795fSJyri Sarha WARN_ON(drm_crtc_vblank_get(crtc) != 0); 20232a1795fSJyri Sarha 20332a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags); 20432a1795fSJyri Sarha dispc_vp_go(tidss->dispc, tcrtc->hw_videoport); 20532a1795fSJyri Sarha 20632a1795fSJyri Sarha WARN_ON(tcrtc->event); 20732a1795fSJyri Sarha 20832a1795fSJyri Sarha tcrtc->event = crtc->state->event; 20932a1795fSJyri Sarha crtc->state->event = NULL; 21032a1795fSJyri Sarha 21132a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 21232a1795fSJyri Sarha } 21332a1795fSJyri Sarha 21432a1795fSJyri Sarha static void tidss_crtc_atomic_enable(struct drm_crtc *crtc, 21532a1795fSJyri Sarha struct drm_crtc_state *old_state) 21632a1795fSJyri Sarha { 21732a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 21832a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 21932a1795fSJyri Sarha struct tidss_device *tidss = ddev->dev_private; 22032a1795fSJyri Sarha const struct drm_display_mode *mode = &crtc->state->adjusted_mode; 22132a1795fSJyri Sarha unsigned long flags; 22232a1795fSJyri Sarha int r; 22332a1795fSJyri Sarha 22432a1795fSJyri Sarha dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event); 22532a1795fSJyri Sarha 22632a1795fSJyri Sarha tidss_runtime_get(tidss); 22732a1795fSJyri Sarha 22832a1795fSJyri Sarha r = dispc_vp_set_clk_rate(tidss->dispc, tcrtc->hw_videoport, 22932a1795fSJyri Sarha mode->clock * 1000); 23032a1795fSJyri Sarha if (r != 0) 23132a1795fSJyri Sarha return; 23232a1795fSJyri Sarha 23332a1795fSJyri Sarha r = dispc_vp_enable_clk(tidss->dispc, tcrtc->hw_videoport); 23432a1795fSJyri Sarha if (r != 0) 23532a1795fSJyri Sarha return; 23632a1795fSJyri Sarha 23732a1795fSJyri Sarha dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true); 238b33b5474SJyri Sarha tidss_crtc_position_planes(tidss, crtc, old_state, true); 23932a1795fSJyri Sarha 24032a1795fSJyri Sarha /* Turn vertical blanking interrupt reporting on. */ 24132a1795fSJyri Sarha drm_crtc_vblank_on(crtc); 24232a1795fSJyri Sarha 24332a1795fSJyri Sarha dispc_vp_prepare(tidss->dispc, tcrtc->hw_videoport, crtc->state); 24432a1795fSJyri Sarha 24532a1795fSJyri Sarha dispc_vp_enable(tidss->dispc, tcrtc->hw_videoport, crtc->state); 24632a1795fSJyri Sarha 24732a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags); 24832a1795fSJyri Sarha 24932a1795fSJyri Sarha if (crtc->state->event) { 25032a1795fSJyri Sarha drm_crtc_send_vblank_event(crtc, crtc->state->event); 25132a1795fSJyri Sarha crtc->state->event = NULL; 25232a1795fSJyri Sarha } 25332a1795fSJyri Sarha 25432a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 25532a1795fSJyri Sarha } 25632a1795fSJyri Sarha 25732a1795fSJyri Sarha static void tidss_crtc_atomic_disable(struct drm_crtc *crtc, 25832a1795fSJyri Sarha struct drm_crtc_state *old_state) 25932a1795fSJyri Sarha { 26032a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 26132a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 26232a1795fSJyri Sarha struct tidss_device *tidss = ddev->dev_private; 26332a1795fSJyri Sarha unsigned long flags; 26432a1795fSJyri Sarha 26532a1795fSJyri Sarha dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event); 26632a1795fSJyri Sarha 26732a1795fSJyri Sarha reinit_completion(&tcrtc->framedone_completion); 26832a1795fSJyri Sarha 26932a1795fSJyri Sarha dispc_vp_disable(tidss->dispc, tcrtc->hw_videoport); 27032a1795fSJyri Sarha 27132a1795fSJyri Sarha if (!wait_for_completion_timeout(&tcrtc->framedone_completion, 27232a1795fSJyri Sarha msecs_to_jiffies(500))) 27332a1795fSJyri Sarha dev_err(tidss->dev, "Timeout waiting for framedone on crtc %d", 27432a1795fSJyri Sarha tcrtc->hw_videoport); 27532a1795fSJyri Sarha 27632a1795fSJyri Sarha dispc_vp_unprepare(tidss->dispc, tcrtc->hw_videoport); 27732a1795fSJyri Sarha 27832a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags); 27932a1795fSJyri Sarha if (crtc->state->event) { 28032a1795fSJyri Sarha drm_crtc_send_vblank_event(crtc, crtc->state->event); 28132a1795fSJyri Sarha crtc->state->event = NULL; 28232a1795fSJyri Sarha } 28332a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 28432a1795fSJyri Sarha 28532a1795fSJyri Sarha drm_crtc_vblank_off(crtc); 28632a1795fSJyri Sarha 28732a1795fSJyri Sarha dispc_vp_disable_clk(tidss->dispc, tcrtc->hw_videoport); 28832a1795fSJyri Sarha 28932a1795fSJyri Sarha tidss_runtime_put(tidss); 29032a1795fSJyri Sarha } 29132a1795fSJyri Sarha 29232a1795fSJyri Sarha static 29332a1795fSJyri Sarha enum drm_mode_status tidss_crtc_mode_valid(struct drm_crtc *crtc, 29432a1795fSJyri Sarha const struct drm_display_mode *mode) 29532a1795fSJyri Sarha { 29632a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 29732a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 29832a1795fSJyri Sarha struct tidss_device *tidss = ddev->dev_private; 29932a1795fSJyri Sarha 30032a1795fSJyri Sarha return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode); 30132a1795fSJyri Sarha } 30232a1795fSJyri Sarha 30332a1795fSJyri Sarha static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = { 30432a1795fSJyri Sarha .atomic_check = tidss_crtc_atomic_check, 30532a1795fSJyri Sarha .atomic_flush = tidss_crtc_atomic_flush, 30632a1795fSJyri Sarha .atomic_enable = tidss_crtc_atomic_enable, 30732a1795fSJyri Sarha .atomic_disable = tidss_crtc_atomic_disable, 30832a1795fSJyri Sarha 30932a1795fSJyri Sarha .mode_valid = tidss_crtc_mode_valid, 31032a1795fSJyri Sarha }; 31132a1795fSJyri Sarha 31232a1795fSJyri Sarha /* drm_crtc_funcs */ 31332a1795fSJyri Sarha 31432a1795fSJyri Sarha static int tidss_crtc_enable_vblank(struct drm_crtc *crtc) 31532a1795fSJyri Sarha { 31632a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 31732a1795fSJyri Sarha struct tidss_device *tidss = ddev->dev_private; 31832a1795fSJyri Sarha 31932a1795fSJyri Sarha dev_dbg(ddev->dev, "%s\n", __func__); 32032a1795fSJyri Sarha 32132a1795fSJyri Sarha tidss_runtime_get(tidss); 32232a1795fSJyri Sarha 32332a1795fSJyri Sarha tidss_irq_enable_vblank(crtc); 32432a1795fSJyri Sarha 32532a1795fSJyri Sarha return 0; 32632a1795fSJyri Sarha } 32732a1795fSJyri Sarha 32832a1795fSJyri Sarha static void tidss_crtc_disable_vblank(struct drm_crtc *crtc) 32932a1795fSJyri Sarha { 33032a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 33132a1795fSJyri Sarha struct tidss_device *tidss = ddev->dev_private; 33232a1795fSJyri Sarha 33332a1795fSJyri Sarha dev_dbg(ddev->dev, "%s\n", __func__); 33432a1795fSJyri Sarha 33532a1795fSJyri Sarha tidss_irq_disable_vblank(crtc); 33632a1795fSJyri Sarha 33732a1795fSJyri Sarha tidss_runtime_put(tidss); 33832a1795fSJyri Sarha } 33932a1795fSJyri Sarha 34032a1795fSJyri Sarha static void tidss_crtc_reset(struct drm_crtc *crtc) 34132a1795fSJyri Sarha { 34232a1795fSJyri Sarha struct tidss_crtc_state *tcrtc; 34332a1795fSJyri Sarha 34432a1795fSJyri Sarha if (crtc->state) 34532a1795fSJyri Sarha __drm_atomic_helper_crtc_destroy_state(crtc->state); 34632a1795fSJyri Sarha 34732a1795fSJyri Sarha kfree(crtc->state); 34832a1795fSJyri Sarha 34932a1795fSJyri Sarha tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL); 35032a1795fSJyri Sarha if (!tcrtc) { 35132a1795fSJyri Sarha crtc->state = NULL; 35232a1795fSJyri Sarha return; 35332a1795fSJyri Sarha } 35432a1795fSJyri Sarha 35532a1795fSJyri Sarha crtc->state = &tcrtc->base; 35632a1795fSJyri Sarha crtc->state->crtc = crtc; 35732a1795fSJyri Sarha } 35832a1795fSJyri Sarha 35932a1795fSJyri Sarha static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc) 36032a1795fSJyri Sarha { 36132a1795fSJyri Sarha struct tidss_crtc_state *state, *current_state; 36232a1795fSJyri Sarha 36332a1795fSJyri Sarha if (WARN_ON(!crtc->state)) 36432a1795fSJyri Sarha return NULL; 36532a1795fSJyri Sarha 36632a1795fSJyri Sarha current_state = to_tidss_crtc_state(crtc->state); 36732a1795fSJyri Sarha 36832a1795fSJyri Sarha state = kmalloc(sizeof(*state), GFP_KERNEL); 36932a1795fSJyri Sarha if (!state) 37032a1795fSJyri Sarha return NULL; 37132a1795fSJyri Sarha 37232a1795fSJyri Sarha __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); 37332a1795fSJyri Sarha 374b33b5474SJyri Sarha state->plane_pos_changed = false; 375b33b5474SJyri Sarha 37632a1795fSJyri Sarha state->bus_format = current_state->bus_format; 37732a1795fSJyri Sarha state->bus_flags = current_state->bus_flags; 37832a1795fSJyri Sarha 37932a1795fSJyri Sarha return &state->base; 38032a1795fSJyri Sarha } 38132a1795fSJyri Sarha 3829da67433STomi Valkeinen static void tidss_crtc_destroy(struct drm_crtc *crtc) 3839da67433STomi Valkeinen { 3849da67433STomi Valkeinen struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 3859da67433STomi Valkeinen 3869da67433STomi Valkeinen drm_crtc_cleanup(crtc); 3879da67433STomi Valkeinen kfree(tcrtc); 3889da67433STomi Valkeinen } 3899da67433STomi Valkeinen 39032a1795fSJyri Sarha static const struct drm_crtc_funcs tidss_crtc_funcs = { 39132a1795fSJyri Sarha .reset = tidss_crtc_reset, 3929da67433STomi Valkeinen .destroy = tidss_crtc_destroy, 39332a1795fSJyri Sarha .set_config = drm_atomic_helper_set_config, 39432a1795fSJyri Sarha .page_flip = drm_atomic_helper_page_flip, 39532a1795fSJyri Sarha .atomic_duplicate_state = tidss_crtc_duplicate_state, 39632a1795fSJyri Sarha .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 39732a1795fSJyri Sarha .enable_vblank = tidss_crtc_enable_vblank, 39832a1795fSJyri Sarha .disable_vblank = tidss_crtc_disable_vblank, 39932a1795fSJyri Sarha }; 40032a1795fSJyri Sarha 40132a1795fSJyri Sarha struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss, 40232a1795fSJyri Sarha u32 hw_videoport, 40332a1795fSJyri Sarha struct drm_plane *primary) 40432a1795fSJyri Sarha { 40532a1795fSJyri Sarha struct tidss_crtc *tcrtc; 40632a1795fSJyri Sarha struct drm_crtc *crtc; 40732a1795fSJyri Sarha unsigned int gamma_lut_size = 0; 40832a1795fSJyri Sarha bool has_ctm = tidss->feat->vp_feat.color.has_ctm; 40932a1795fSJyri Sarha int ret; 41032a1795fSJyri Sarha 4119da67433STomi Valkeinen tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL); 41232a1795fSJyri Sarha if (!tcrtc) 41332a1795fSJyri Sarha return ERR_PTR(-ENOMEM); 41432a1795fSJyri Sarha 41532a1795fSJyri Sarha tcrtc->hw_videoport = hw_videoport; 41632a1795fSJyri Sarha init_completion(&tcrtc->framedone_completion); 41732a1795fSJyri Sarha 41832a1795fSJyri Sarha crtc = &tcrtc->crtc; 41932a1795fSJyri Sarha 42032a1795fSJyri Sarha ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary, 42132a1795fSJyri Sarha NULL, &tidss_crtc_funcs, NULL); 4229da67433STomi Valkeinen if (ret < 0) { 4239da67433STomi Valkeinen kfree(tcrtc); 42432a1795fSJyri Sarha return ERR_PTR(ret); 4259da67433STomi Valkeinen } 42632a1795fSJyri Sarha 42732a1795fSJyri Sarha drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs); 42832a1795fSJyri Sarha 42932a1795fSJyri Sarha /* 43032a1795fSJyri Sarha * The dispc gamma functions adapt to what ever size we ask 43132a1795fSJyri Sarha * from it no matter what HW supports. X-server assumes 256 43232a1795fSJyri Sarha * element gamma tables so lets use that. 43332a1795fSJyri Sarha */ 43432a1795fSJyri Sarha if (tidss->feat->vp_feat.color.gamma_size) 43532a1795fSJyri Sarha gamma_lut_size = 256; 43632a1795fSJyri Sarha 43732a1795fSJyri Sarha drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size); 43832a1795fSJyri Sarha if (gamma_lut_size) 43932a1795fSJyri Sarha drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size); 44032a1795fSJyri Sarha 44132a1795fSJyri Sarha return tcrtc; 44232a1795fSJyri Sarha } 443