132a1795fSJyri Sarha // SPDX-License-Identifier: GPL-2.0 232a1795fSJyri Sarha /* 39410113fSAlexander A. Klimov * Copyright (C) 2018 Texas Instruments Incorporated - https://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> 11*4a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h> 1232a1795fSJyri Sarha #include <drm/drm_vblank.h> 1332a1795fSJyri Sarha 1432a1795fSJyri Sarha #include "tidss_crtc.h" 1532a1795fSJyri Sarha #include "tidss_dispc.h" 1632a1795fSJyri Sarha #include "tidss_drv.h" 1732a1795fSJyri Sarha #include "tidss_irq.h" 18b33b5474SJyri Sarha #include "tidss_plane.h" 1932a1795fSJyri Sarha 2032a1795fSJyri Sarha /* Page flip and frame done IRQs */ 2132a1795fSJyri Sarha 2232a1795fSJyri Sarha static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc) 2332a1795fSJyri Sarha { 2432a1795fSJyri Sarha struct drm_device *ddev = tcrtc->crtc.dev; 2502bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev); 2632a1795fSJyri Sarha struct drm_pending_vblank_event *event; 2732a1795fSJyri Sarha unsigned long flags; 2832a1795fSJyri Sarha bool busy; 2932a1795fSJyri Sarha 3032a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags); 3132a1795fSJyri Sarha 3232a1795fSJyri Sarha /* 3332a1795fSJyri Sarha * New settings are taken into use at VFP, and GO bit is cleared at 3432a1795fSJyri Sarha * the same time. This happens before the vertical blank interrupt. 3532a1795fSJyri Sarha * So there is a small change that the driver sets GO bit after VFP, but 3632a1795fSJyri Sarha * before vblank, and we have to check for that case here. 3732a1795fSJyri Sarha */ 3832a1795fSJyri Sarha busy = dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport); 3932a1795fSJyri Sarha if (busy) { 4032a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 4132a1795fSJyri Sarha return; 4232a1795fSJyri Sarha } 4332a1795fSJyri Sarha 4432a1795fSJyri Sarha event = tcrtc->event; 4532a1795fSJyri Sarha tcrtc->event = NULL; 4632a1795fSJyri Sarha 4732a1795fSJyri Sarha if (!event) { 4832a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 4932a1795fSJyri Sarha return; 5032a1795fSJyri Sarha } 5132a1795fSJyri Sarha 5232a1795fSJyri Sarha drm_crtc_send_vblank_event(&tcrtc->crtc, event); 5332a1795fSJyri Sarha 5432a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 5532a1795fSJyri Sarha 5632a1795fSJyri Sarha drm_crtc_vblank_put(&tcrtc->crtc); 5732a1795fSJyri Sarha } 5832a1795fSJyri Sarha 5932a1795fSJyri Sarha void tidss_crtc_vblank_irq(struct drm_crtc *crtc) 6032a1795fSJyri Sarha { 6132a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 6232a1795fSJyri Sarha 6332a1795fSJyri Sarha drm_crtc_handle_vblank(crtc); 6432a1795fSJyri Sarha 6532a1795fSJyri Sarha tidss_crtc_finish_page_flip(tcrtc); 6632a1795fSJyri Sarha } 6732a1795fSJyri Sarha 6832a1795fSJyri Sarha void tidss_crtc_framedone_irq(struct drm_crtc *crtc) 6932a1795fSJyri Sarha { 7032a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 7132a1795fSJyri Sarha 7232a1795fSJyri Sarha complete(&tcrtc->framedone_completion); 7332a1795fSJyri Sarha } 7432a1795fSJyri Sarha 7532a1795fSJyri Sarha void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus) 7632a1795fSJyri Sarha { 7732a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 7832a1795fSJyri Sarha 7932a1795fSJyri Sarha dev_err_ratelimited(crtc->dev->dev, "CRTC%u SYNC LOST: (irq %llx)\n", 8032a1795fSJyri Sarha tcrtc->hw_videoport, irqstatus); 8132a1795fSJyri Sarha } 8232a1795fSJyri Sarha 8332a1795fSJyri Sarha /* drm_crtc_helper_funcs */ 8432a1795fSJyri Sarha 8532a1795fSJyri Sarha static int tidss_crtc_atomic_check(struct drm_crtc *crtc, 8629b77ad7SMaxime Ripard struct drm_atomic_state *state) 8732a1795fSJyri Sarha { 8829b77ad7SMaxime Ripard struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, 8929b77ad7SMaxime Ripard crtc); 9032a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 9102bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev); 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 10029b77ad7SMaxime Ripard if (!crtc_state->enable) 10132a1795fSJyri Sarha return 0; 10232a1795fSJyri Sarha 10329b77ad7SMaxime Ripard mode = &crtc_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 11229b77ad7SMaxime Ripard return dispc_vp_bus_check(dispc, hw_videoport, crtc_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, 164f6ebe9f9SMaxime Ripard struct drm_atomic_state *state) 16532a1795fSJyri Sarha { 166f6ebe9f9SMaxime Ripard struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, 167f6ebe9f9SMaxime Ripard crtc); 16832a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 16932a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 17002bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev); 17132a1795fSJyri Sarha unsigned long flags; 17232a1795fSJyri Sarha 17332a1795fSJyri Sarha dev_dbg(ddev->dev, 17432a1795fSJyri Sarha "%s: %s enabled %d, needs modeset %d, event %p\n", __func__, 17532a1795fSJyri Sarha crtc->name, drm_atomic_crtc_needs_modeset(crtc->state), 17632a1795fSJyri Sarha crtc->state->enable, crtc->state->event); 17732a1795fSJyri Sarha 17832a1795fSJyri Sarha /* There is nothing to do if CRTC is not going to be enabled. */ 17932a1795fSJyri Sarha if (!crtc->state->enable) 18032a1795fSJyri Sarha return; 18132a1795fSJyri Sarha 18232a1795fSJyri Sarha /* 18332a1795fSJyri Sarha * Flush CRTC changes with go bit only if new modeset is not 18432a1795fSJyri Sarha * coming, so CRTC is enabled trough out the commit. 18532a1795fSJyri Sarha */ 18632a1795fSJyri Sarha if (drm_atomic_crtc_needs_modeset(crtc->state)) 18732a1795fSJyri Sarha return; 18832a1795fSJyri Sarha 18932a1795fSJyri Sarha /* If the GO bit is stuck we better quit here. */ 19032a1795fSJyri Sarha if (WARN_ON(dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport))) 19132a1795fSJyri Sarha return; 19232a1795fSJyri Sarha 19332a1795fSJyri Sarha /* We should have event if CRTC is enabled through out this commit. */ 19432a1795fSJyri Sarha if (WARN_ON(!crtc->state->event)) 19532a1795fSJyri Sarha return; 19632a1795fSJyri Sarha 19732a1795fSJyri Sarha /* Write vp properties to HW if needed. */ 19832a1795fSJyri Sarha dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false); 19932a1795fSJyri Sarha 200b33b5474SJyri Sarha /* Update plane positions if needed. */ 201b33b5474SJyri Sarha tidss_crtc_position_planes(tidss, crtc, old_crtc_state, false); 202b33b5474SJyri Sarha 20332a1795fSJyri Sarha WARN_ON(drm_crtc_vblank_get(crtc) != 0); 20432a1795fSJyri Sarha 20532a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags); 20632a1795fSJyri Sarha dispc_vp_go(tidss->dispc, tcrtc->hw_videoport); 20732a1795fSJyri Sarha 20832a1795fSJyri Sarha WARN_ON(tcrtc->event); 20932a1795fSJyri Sarha 21032a1795fSJyri Sarha tcrtc->event = crtc->state->event; 21132a1795fSJyri Sarha crtc->state->event = NULL; 21232a1795fSJyri Sarha 21332a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 21432a1795fSJyri Sarha } 21532a1795fSJyri Sarha 21632a1795fSJyri Sarha static void tidss_crtc_atomic_enable(struct drm_crtc *crtc, 217351f950dSMaxime Ripard struct drm_atomic_state *state) 21832a1795fSJyri Sarha { 219351f950dSMaxime Ripard struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, 220351f950dSMaxime Ripard crtc); 22132a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 22232a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 22302bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev); 22432a1795fSJyri Sarha const struct drm_display_mode *mode = &crtc->state->adjusted_mode; 22532a1795fSJyri Sarha unsigned long flags; 22632a1795fSJyri Sarha int r; 22732a1795fSJyri Sarha 22832a1795fSJyri Sarha dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event); 22932a1795fSJyri Sarha 23032a1795fSJyri Sarha tidss_runtime_get(tidss); 23132a1795fSJyri Sarha 23232a1795fSJyri Sarha r = dispc_vp_set_clk_rate(tidss->dispc, tcrtc->hw_videoport, 23332a1795fSJyri Sarha mode->clock * 1000); 23432a1795fSJyri Sarha if (r != 0) 23532a1795fSJyri Sarha return; 23632a1795fSJyri Sarha 23732a1795fSJyri Sarha r = dispc_vp_enable_clk(tidss->dispc, tcrtc->hw_videoport); 23832a1795fSJyri Sarha if (r != 0) 23932a1795fSJyri Sarha return; 24032a1795fSJyri Sarha 24132a1795fSJyri Sarha dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true); 242b33b5474SJyri Sarha tidss_crtc_position_planes(tidss, crtc, old_state, true); 24332a1795fSJyri Sarha 24432a1795fSJyri Sarha /* Turn vertical blanking interrupt reporting on. */ 24532a1795fSJyri Sarha drm_crtc_vblank_on(crtc); 24632a1795fSJyri Sarha 24732a1795fSJyri Sarha dispc_vp_prepare(tidss->dispc, tcrtc->hw_videoport, crtc->state); 24832a1795fSJyri Sarha 24932a1795fSJyri Sarha dispc_vp_enable(tidss->dispc, tcrtc->hw_videoport, crtc->state); 25032a1795fSJyri Sarha 25132a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags); 25232a1795fSJyri Sarha 25332a1795fSJyri Sarha if (crtc->state->event) { 25432a1795fSJyri Sarha drm_crtc_send_vblank_event(crtc, crtc->state->event); 25532a1795fSJyri Sarha crtc->state->event = NULL; 25632a1795fSJyri Sarha } 25732a1795fSJyri Sarha 25832a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 25932a1795fSJyri Sarha } 26032a1795fSJyri Sarha 26132a1795fSJyri Sarha static void tidss_crtc_atomic_disable(struct drm_crtc *crtc, 262351f950dSMaxime Ripard struct drm_atomic_state *state) 26332a1795fSJyri Sarha { 26432a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 26532a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 26602bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev); 26732a1795fSJyri Sarha unsigned long flags; 26832a1795fSJyri Sarha 26932a1795fSJyri Sarha dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event); 27032a1795fSJyri Sarha 27132a1795fSJyri Sarha reinit_completion(&tcrtc->framedone_completion); 27232a1795fSJyri Sarha 27332a1795fSJyri Sarha dispc_vp_disable(tidss->dispc, tcrtc->hw_videoport); 27432a1795fSJyri Sarha 27532a1795fSJyri Sarha if (!wait_for_completion_timeout(&tcrtc->framedone_completion, 27632a1795fSJyri Sarha msecs_to_jiffies(500))) 27732a1795fSJyri Sarha dev_err(tidss->dev, "Timeout waiting for framedone on crtc %d", 27832a1795fSJyri Sarha tcrtc->hw_videoport); 27932a1795fSJyri Sarha 28032a1795fSJyri Sarha dispc_vp_unprepare(tidss->dispc, tcrtc->hw_videoport); 28132a1795fSJyri Sarha 28232a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags); 28332a1795fSJyri Sarha if (crtc->state->event) { 28432a1795fSJyri Sarha drm_crtc_send_vblank_event(crtc, crtc->state->event); 28532a1795fSJyri Sarha crtc->state->event = NULL; 28632a1795fSJyri Sarha } 28732a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags); 28832a1795fSJyri Sarha 28932a1795fSJyri Sarha drm_crtc_vblank_off(crtc); 29032a1795fSJyri Sarha 29132a1795fSJyri Sarha dispc_vp_disable_clk(tidss->dispc, tcrtc->hw_videoport); 29232a1795fSJyri Sarha 29332a1795fSJyri Sarha tidss_runtime_put(tidss); 29432a1795fSJyri Sarha } 29532a1795fSJyri Sarha 29632a1795fSJyri Sarha static 29732a1795fSJyri Sarha enum drm_mode_status tidss_crtc_mode_valid(struct drm_crtc *crtc, 29832a1795fSJyri Sarha const struct drm_display_mode *mode) 29932a1795fSJyri Sarha { 30032a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 30132a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 30202bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev); 30332a1795fSJyri Sarha 30432a1795fSJyri Sarha return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode); 30532a1795fSJyri Sarha } 30632a1795fSJyri Sarha 30732a1795fSJyri Sarha static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = { 30832a1795fSJyri Sarha .atomic_check = tidss_crtc_atomic_check, 30932a1795fSJyri Sarha .atomic_flush = tidss_crtc_atomic_flush, 31032a1795fSJyri Sarha .atomic_enable = tidss_crtc_atomic_enable, 31132a1795fSJyri Sarha .atomic_disable = tidss_crtc_atomic_disable, 31232a1795fSJyri Sarha 31332a1795fSJyri Sarha .mode_valid = tidss_crtc_mode_valid, 31432a1795fSJyri Sarha }; 31532a1795fSJyri Sarha 31632a1795fSJyri Sarha /* drm_crtc_funcs */ 31732a1795fSJyri Sarha 31832a1795fSJyri Sarha static int tidss_crtc_enable_vblank(struct drm_crtc *crtc) 31932a1795fSJyri Sarha { 32032a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 32102bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev); 32232a1795fSJyri Sarha 32332a1795fSJyri Sarha dev_dbg(ddev->dev, "%s\n", __func__); 32432a1795fSJyri Sarha 32532a1795fSJyri Sarha tidss_runtime_get(tidss); 32632a1795fSJyri Sarha 32732a1795fSJyri Sarha tidss_irq_enable_vblank(crtc); 32832a1795fSJyri Sarha 32932a1795fSJyri Sarha return 0; 33032a1795fSJyri Sarha } 33132a1795fSJyri Sarha 33232a1795fSJyri Sarha static void tidss_crtc_disable_vblank(struct drm_crtc *crtc) 33332a1795fSJyri Sarha { 33432a1795fSJyri Sarha struct drm_device *ddev = crtc->dev; 33502bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev); 33632a1795fSJyri Sarha 33732a1795fSJyri Sarha dev_dbg(ddev->dev, "%s\n", __func__); 33832a1795fSJyri Sarha 33932a1795fSJyri Sarha tidss_irq_disable_vblank(crtc); 34032a1795fSJyri Sarha 34132a1795fSJyri Sarha tidss_runtime_put(tidss); 34232a1795fSJyri Sarha } 34332a1795fSJyri Sarha 34432a1795fSJyri Sarha static void tidss_crtc_reset(struct drm_crtc *crtc) 34532a1795fSJyri Sarha { 34632a1795fSJyri Sarha struct tidss_crtc_state *tcrtc; 34732a1795fSJyri Sarha 34832a1795fSJyri Sarha if (crtc->state) 34932a1795fSJyri Sarha __drm_atomic_helper_crtc_destroy_state(crtc->state); 35032a1795fSJyri Sarha 35132a1795fSJyri Sarha kfree(crtc->state); 35232a1795fSJyri Sarha 35332a1795fSJyri Sarha tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL); 35432a1795fSJyri Sarha if (!tcrtc) { 35532a1795fSJyri Sarha crtc->state = NULL; 35632a1795fSJyri Sarha return; 35732a1795fSJyri Sarha } 35832a1795fSJyri Sarha 35951f644b4SDaniel Vetter __drm_atomic_helper_crtc_reset(crtc, &tcrtc->base); 36032a1795fSJyri Sarha } 36132a1795fSJyri Sarha 36232a1795fSJyri Sarha static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc) 36332a1795fSJyri Sarha { 36432a1795fSJyri Sarha struct tidss_crtc_state *state, *current_state; 36532a1795fSJyri Sarha 36632a1795fSJyri Sarha if (WARN_ON(!crtc->state)) 36732a1795fSJyri Sarha return NULL; 36832a1795fSJyri Sarha 36932a1795fSJyri Sarha current_state = to_tidss_crtc_state(crtc->state); 37032a1795fSJyri Sarha 37132a1795fSJyri Sarha state = kmalloc(sizeof(*state), GFP_KERNEL); 37232a1795fSJyri Sarha if (!state) 37332a1795fSJyri Sarha return NULL; 37432a1795fSJyri Sarha 37532a1795fSJyri Sarha __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); 37632a1795fSJyri Sarha 377b33b5474SJyri Sarha state->plane_pos_changed = false; 378b33b5474SJyri Sarha 37932a1795fSJyri Sarha state->bus_format = current_state->bus_format; 38032a1795fSJyri Sarha state->bus_flags = current_state->bus_flags; 38132a1795fSJyri Sarha 38232a1795fSJyri Sarha return &state->base; 38332a1795fSJyri Sarha } 38432a1795fSJyri Sarha 3859da67433STomi Valkeinen static void tidss_crtc_destroy(struct drm_crtc *crtc) 3869da67433STomi Valkeinen { 3879da67433STomi Valkeinen struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 3889da67433STomi Valkeinen 3899da67433STomi Valkeinen drm_crtc_cleanup(crtc); 3909da67433STomi Valkeinen kfree(tcrtc); 3919da67433STomi Valkeinen } 3929da67433STomi Valkeinen 39332a1795fSJyri Sarha static const struct drm_crtc_funcs tidss_crtc_funcs = { 39432a1795fSJyri Sarha .reset = tidss_crtc_reset, 3959da67433STomi Valkeinen .destroy = tidss_crtc_destroy, 39632a1795fSJyri Sarha .set_config = drm_atomic_helper_set_config, 39732a1795fSJyri Sarha .page_flip = drm_atomic_helper_page_flip, 39832a1795fSJyri Sarha .atomic_duplicate_state = tidss_crtc_duplicate_state, 39932a1795fSJyri Sarha .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 40032a1795fSJyri Sarha .enable_vblank = tidss_crtc_enable_vblank, 40132a1795fSJyri Sarha .disable_vblank = tidss_crtc_disable_vblank, 40232a1795fSJyri Sarha }; 40332a1795fSJyri Sarha 40432a1795fSJyri Sarha struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss, 40532a1795fSJyri Sarha u32 hw_videoport, 40632a1795fSJyri Sarha struct drm_plane *primary) 40732a1795fSJyri Sarha { 40832a1795fSJyri Sarha struct tidss_crtc *tcrtc; 40932a1795fSJyri Sarha struct drm_crtc *crtc; 41032a1795fSJyri Sarha unsigned int gamma_lut_size = 0; 41132a1795fSJyri Sarha bool has_ctm = tidss->feat->vp_feat.color.has_ctm; 41232a1795fSJyri Sarha int ret; 41332a1795fSJyri Sarha 4149da67433STomi Valkeinen tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL); 41532a1795fSJyri Sarha if (!tcrtc) 41632a1795fSJyri Sarha return ERR_PTR(-ENOMEM); 41732a1795fSJyri Sarha 41832a1795fSJyri Sarha tcrtc->hw_videoport = hw_videoport; 41932a1795fSJyri Sarha init_completion(&tcrtc->framedone_completion); 42032a1795fSJyri Sarha 42132a1795fSJyri Sarha crtc = &tcrtc->crtc; 42232a1795fSJyri Sarha 42332a1795fSJyri Sarha ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary, 42432a1795fSJyri Sarha NULL, &tidss_crtc_funcs, NULL); 4259da67433STomi Valkeinen if (ret < 0) { 4269da67433STomi Valkeinen kfree(tcrtc); 42732a1795fSJyri Sarha return ERR_PTR(ret); 4289da67433STomi Valkeinen } 42932a1795fSJyri Sarha 43032a1795fSJyri Sarha drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs); 43132a1795fSJyri Sarha 43232a1795fSJyri Sarha /* 43332a1795fSJyri Sarha * The dispc gamma functions adapt to what ever size we ask 43432a1795fSJyri Sarha * from it no matter what HW supports. X-server assumes 256 43532a1795fSJyri Sarha * element gamma tables so lets use that. 43632a1795fSJyri Sarha */ 43732a1795fSJyri Sarha if (tidss->feat->vp_feat.color.gamma_size) 43832a1795fSJyri Sarha gamma_lut_size = 256; 43932a1795fSJyri Sarha 44032a1795fSJyri Sarha drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size); 44132a1795fSJyri Sarha if (gamma_lut_size) 44232a1795fSJyri Sarha drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size); 44332a1795fSJyri Sarha 44432a1795fSJyri Sarha return tcrtc; 44532a1795fSJyri Sarha } 446