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>
104a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
1132a1795fSJyri Sarha #include <drm/drm_vblank.h>
1232a1795fSJyri Sarha
1332a1795fSJyri Sarha #include "tidss_crtc.h"
1432a1795fSJyri Sarha #include "tidss_dispc.h"
1532a1795fSJyri Sarha #include "tidss_drv.h"
1632a1795fSJyri Sarha #include "tidss_irq.h"
17b33b5474SJyri Sarha #include "tidss_plane.h"
1832a1795fSJyri Sarha
1932a1795fSJyri Sarha /* Page flip and frame done IRQs */
2032a1795fSJyri Sarha
tidss_crtc_finish_page_flip(struct tidss_crtc * tcrtc)2132a1795fSJyri Sarha static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc)
2232a1795fSJyri Sarha {
2332a1795fSJyri Sarha struct drm_device *ddev = tcrtc->crtc.dev;
2402bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev);
2532a1795fSJyri Sarha struct drm_pending_vblank_event *event;
2632a1795fSJyri Sarha unsigned long flags;
2732a1795fSJyri Sarha bool busy;
2832a1795fSJyri Sarha
2932a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags);
3032a1795fSJyri Sarha
3132a1795fSJyri Sarha /*
3232a1795fSJyri Sarha * New settings are taken into use at VFP, and GO bit is cleared at
3332a1795fSJyri Sarha * the same time. This happens before the vertical blank interrupt.
3432a1795fSJyri Sarha * So there is a small change that the driver sets GO bit after VFP, but
3532a1795fSJyri Sarha * before vblank, and we have to check for that case here.
3632a1795fSJyri Sarha */
3732a1795fSJyri Sarha busy = dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport);
3832a1795fSJyri Sarha if (busy) {
3932a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags);
4032a1795fSJyri Sarha return;
4132a1795fSJyri Sarha }
4232a1795fSJyri Sarha
4332a1795fSJyri Sarha event = tcrtc->event;
4432a1795fSJyri Sarha tcrtc->event = NULL;
4532a1795fSJyri Sarha
4632a1795fSJyri Sarha if (!event) {
4732a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags);
4832a1795fSJyri Sarha return;
4932a1795fSJyri Sarha }
5032a1795fSJyri Sarha
5132a1795fSJyri Sarha drm_crtc_send_vblank_event(&tcrtc->crtc, event);
5232a1795fSJyri Sarha
5332a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags);
5432a1795fSJyri Sarha
5532a1795fSJyri Sarha drm_crtc_vblank_put(&tcrtc->crtc);
5632a1795fSJyri Sarha }
5732a1795fSJyri Sarha
tidss_crtc_vblank_irq(struct drm_crtc * crtc)5832a1795fSJyri Sarha void tidss_crtc_vblank_irq(struct drm_crtc *crtc)
5932a1795fSJyri Sarha {
6032a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
6132a1795fSJyri Sarha
6232a1795fSJyri Sarha drm_crtc_handle_vblank(crtc);
6332a1795fSJyri Sarha
6432a1795fSJyri Sarha tidss_crtc_finish_page_flip(tcrtc);
6532a1795fSJyri Sarha }
6632a1795fSJyri Sarha
tidss_crtc_framedone_irq(struct drm_crtc * crtc)6732a1795fSJyri Sarha void tidss_crtc_framedone_irq(struct drm_crtc *crtc)
6832a1795fSJyri Sarha {
6932a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
7032a1795fSJyri Sarha
7132a1795fSJyri Sarha complete(&tcrtc->framedone_completion);
7232a1795fSJyri Sarha }
7332a1795fSJyri Sarha
tidss_crtc_error_irq(struct drm_crtc * crtc,u64 irqstatus)7432a1795fSJyri Sarha void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus)
7532a1795fSJyri Sarha {
7632a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
7732a1795fSJyri Sarha
7832a1795fSJyri Sarha dev_err_ratelimited(crtc->dev->dev, "CRTC%u SYNC LOST: (irq %llx)\n",
7932a1795fSJyri Sarha tcrtc->hw_videoport, irqstatus);
8032a1795fSJyri Sarha }
8132a1795fSJyri Sarha
8232a1795fSJyri Sarha /* drm_crtc_helper_funcs */
8332a1795fSJyri Sarha
tidss_crtc_atomic_check(struct drm_crtc * crtc,struct drm_atomic_state * state)8432a1795fSJyri Sarha static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
8529b77ad7SMaxime Ripard struct drm_atomic_state *state)
8632a1795fSJyri Sarha {
8729b77ad7SMaxime Ripard struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
8829b77ad7SMaxime Ripard crtc);
8932a1795fSJyri Sarha struct drm_device *ddev = crtc->dev;
9002bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev);
9132a1795fSJyri Sarha struct dispc_device *dispc = tidss->dispc;
9232a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
9332a1795fSJyri Sarha u32 hw_videoport = tcrtc->hw_videoport;
9432a1795fSJyri Sarha const struct drm_display_mode *mode;
9532a1795fSJyri Sarha enum drm_mode_status ok;
9632a1795fSJyri Sarha
9732a1795fSJyri Sarha dev_dbg(ddev->dev, "%s\n", __func__);
9832a1795fSJyri Sarha
9929b77ad7SMaxime Ripard if (!crtc_state->enable)
10032a1795fSJyri Sarha return 0;
10132a1795fSJyri Sarha
10229b77ad7SMaxime Ripard mode = &crtc_state->adjusted_mode;
10332a1795fSJyri Sarha
10432a1795fSJyri Sarha ok = dispc_vp_mode_valid(dispc, hw_videoport, mode);
10532a1795fSJyri Sarha if (ok != MODE_OK) {
10632a1795fSJyri Sarha dev_dbg(ddev->dev, "%s: bad mode: %ux%u pclk %u kHz\n",
10732a1795fSJyri Sarha __func__, mode->hdisplay, mode->vdisplay, mode->clock);
10832a1795fSJyri Sarha return -EINVAL;
10932a1795fSJyri Sarha }
11032a1795fSJyri Sarha
11129b77ad7SMaxime Ripard return dispc_vp_bus_check(dispc, hw_videoport, crtc_state);
11232a1795fSJyri Sarha }
11332a1795fSJyri Sarha
114b33b5474SJyri Sarha /*
115b33b5474SJyri Sarha * This needs all affected planes to be present in the atomic
116b33b5474SJyri Sarha * state. The untouched planes are added to the state in
117b33b5474SJyri Sarha * tidss_atomic_check().
118b33b5474SJyri Sarha */
tidss_crtc_position_planes(struct tidss_device * tidss,struct drm_crtc * crtc,struct drm_crtc_state * old_state,bool newmodeset)119b33b5474SJyri Sarha static void tidss_crtc_position_planes(struct tidss_device *tidss,
120b33b5474SJyri Sarha struct drm_crtc *crtc,
121b33b5474SJyri Sarha struct drm_crtc_state *old_state,
122b33b5474SJyri Sarha bool newmodeset)
123b33b5474SJyri Sarha {
124b33b5474SJyri Sarha struct drm_atomic_state *ostate = old_state->state;
125b33b5474SJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
126b33b5474SJyri Sarha struct drm_crtc_state *cstate = crtc->state;
127b33b5474SJyri Sarha int layer;
128b33b5474SJyri Sarha
129b33b5474SJyri Sarha if (!newmodeset && !cstate->zpos_changed &&
130b33b5474SJyri Sarha !to_tidss_crtc_state(cstate)->plane_pos_changed)
131b33b5474SJyri Sarha return;
132b33b5474SJyri Sarha
133b33b5474SJyri Sarha for (layer = 0; layer < tidss->feat->num_planes; layer++) {
134b33b5474SJyri Sarha struct drm_plane_state *pstate;
135b33b5474SJyri Sarha struct drm_plane *plane;
136b33b5474SJyri Sarha bool layer_active = false;
137b33b5474SJyri Sarha int i;
138b33b5474SJyri Sarha
139b33b5474SJyri Sarha for_each_new_plane_in_state(ostate, plane, pstate, i) {
140b33b5474SJyri Sarha if (pstate->crtc != crtc || !pstate->visible)
141b33b5474SJyri Sarha continue;
142b33b5474SJyri Sarha
143b33b5474SJyri Sarha if (pstate->normalized_zpos == layer) {
144b33b5474SJyri Sarha layer_active = true;
145b33b5474SJyri Sarha break;
146b33b5474SJyri Sarha }
147b33b5474SJyri Sarha }
148b33b5474SJyri Sarha
149b33b5474SJyri Sarha if (layer_active) {
150b33b5474SJyri Sarha struct tidss_plane *tplane = to_tidss_plane(plane);
151b33b5474SJyri Sarha
152b33b5474SJyri Sarha dispc_ovr_set_plane(tidss->dispc, tplane->hw_plane_id,
153b33b5474SJyri Sarha tcrtc->hw_videoport,
154b33b5474SJyri Sarha pstate->crtc_x, pstate->crtc_y,
155b33b5474SJyri Sarha layer);
156b33b5474SJyri Sarha }
157b33b5474SJyri Sarha dispc_ovr_enable_layer(tidss->dispc, tcrtc->hw_videoport, layer,
158b33b5474SJyri Sarha layer_active);
159b33b5474SJyri Sarha }
160b33b5474SJyri Sarha }
161b33b5474SJyri Sarha
tidss_crtc_atomic_flush(struct drm_crtc * crtc,struct drm_atomic_state * state)16232a1795fSJyri Sarha static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
163f6ebe9f9SMaxime Ripard struct drm_atomic_state *state)
16432a1795fSJyri Sarha {
165f6ebe9f9SMaxime Ripard struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
166f6ebe9f9SMaxime Ripard crtc);
16732a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
16832a1795fSJyri Sarha struct drm_device *ddev = crtc->dev;
16902bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev);
17032a1795fSJyri Sarha unsigned long flags;
17132a1795fSJyri Sarha
172adc0787fSTomi Valkeinen dev_dbg(ddev->dev, "%s: %s is %sactive, %s modeset, event %p\n",
173adc0787fSTomi Valkeinen __func__, crtc->name, crtc->state->active ? "" : "not ",
174adc0787fSTomi Valkeinen drm_atomic_crtc_needs_modeset(crtc->state) ? "needs" : "doesn't need",
175adc0787fSTomi Valkeinen crtc->state->event);
17632a1795fSJyri Sarha
17732a1795fSJyri Sarha /* There is nothing to do if CRTC is not going to be enabled. */
178adc0787fSTomi Valkeinen if (!crtc->state->active)
17932a1795fSJyri Sarha return;
18032a1795fSJyri Sarha
18132a1795fSJyri Sarha /*
18232a1795fSJyri Sarha * Flush CRTC changes with go bit only if new modeset is not
18332a1795fSJyri Sarha * coming, so CRTC is enabled trough out the commit.
18432a1795fSJyri Sarha */
18532a1795fSJyri Sarha if (drm_atomic_crtc_needs_modeset(crtc->state))
18632a1795fSJyri Sarha return;
18732a1795fSJyri Sarha
18832a1795fSJyri Sarha /* If the GO bit is stuck we better quit here. */
18932a1795fSJyri Sarha if (WARN_ON(dispc_vp_go_busy(tidss->dispc, tcrtc->hw_videoport)))
19032a1795fSJyri Sarha return;
19132a1795fSJyri Sarha
19232a1795fSJyri Sarha /* We should have event if CRTC is enabled through out this commit. */
19332a1795fSJyri Sarha if (WARN_ON(!crtc->state->event))
19432a1795fSJyri Sarha return;
19532a1795fSJyri Sarha
19632a1795fSJyri Sarha /* Write vp properties to HW if needed. */
19732a1795fSJyri Sarha dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false);
19832a1795fSJyri Sarha
199b33b5474SJyri Sarha /* Update plane positions if needed. */
200b33b5474SJyri Sarha tidss_crtc_position_planes(tidss, crtc, old_crtc_state, false);
201b33b5474SJyri Sarha
20232a1795fSJyri Sarha WARN_ON(drm_crtc_vblank_get(crtc) != 0);
20332a1795fSJyri Sarha
20432a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags);
20532a1795fSJyri Sarha dispc_vp_go(tidss->dispc, tcrtc->hw_videoport);
20632a1795fSJyri Sarha
20732a1795fSJyri Sarha WARN_ON(tcrtc->event);
20832a1795fSJyri Sarha
20932a1795fSJyri Sarha tcrtc->event = crtc->state->event;
21032a1795fSJyri Sarha crtc->state->event = NULL;
21132a1795fSJyri Sarha
21232a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags);
21332a1795fSJyri Sarha }
21432a1795fSJyri Sarha
tidss_crtc_atomic_enable(struct drm_crtc * crtc,struct drm_atomic_state * state)21532a1795fSJyri Sarha static void tidss_crtc_atomic_enable(struct drm_crtc *crtc,
216351f950dSMaxime Ripard struct drm_atomic_state *state)
21732a1795fSJyri Sarha {
218351f950dSMaxime Ripard struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
219351f950dSMaxime Ripard crtc);
22032a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
22132a1795fSJyri Sarha struct drm_device *ddev = crtc->dev;
22202bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev);
22332a1795fSJyri Sarha const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
22432a1795fSJyri Sarha unsigned long flags;
22532a1795fSJyri Sarha int r;
22632a1795fSJyri Sarha
22732a1795fSJyri Sarha dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
22832a1795fSJyri Sarha
22932a1795fSJyri Sarha tidss_runtime_get(tidss);
23032a1795fSJyri Sarha
23132a1795fSJyri Sarha r = dispc_vp_set_clk_rate(tidss->dispc, tcrtc->hw_videoport,
23232a1795fSJyri Sarha mode->clock * 1000);
23332a1795fSJyri Sarha if (r != 0)
23432a1795fSJyri Sarha return;
23532a1795fSJyri Sarha
23632a1795fSJyri Sarha r = dispc_vp_enable_clk(tidss->dispc, tcrtc->hw_videoport);
23732a1795fSJyri Sarha if (r != 0)
23832a1795fSJyri Sarha return;
23932a1795fSJyri Sarha
24032a1795fSJyri Sarha dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true);
241b33b5474SJyri Sarha tidss_crtc_position_planes(tidss, crtc, old_state, true);
24232a1795fSJyri Sarha
24332a1795fSJyri Sarha /* Turn vertical blanking interrupt reporting on. */
24432a1795fSJyri Sarha drm_crtc_vblank_on(crtc);
24532a1795fSJyri Sarha
24632a1795fSJyri Sarha dispc_vp_prepare(tidss->dispc, tcrtc->hw_videoport, crtc->state);
24732a1795fSJyri Sarha
24832a1795fSJyri Sarha dispc_vp_enable(tidss->dispc, tcrtc->hw_videoport, crtc->state);
24932a1795fSJyri Sarha
25032a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags);
25132a1795fSJyri Sarha
25232a1795fSJyri Sarha if (crtc->state->event) {
25332a1795fSJyri Sarha drm_crtc_send_vblank_event(crtc, crtc->state->event);
25432a1795fSJyri Sarha crtc->state->event = NULL;
25532a1795fSJyri Sarha }
25632a1795fSJyri Sarha
25732a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags);
25832a1795fSJyri Sarha }
25932a1795fSJyri Sarha
tidss_crtc_atomic_disable(struct drm_crtc * crtc,struct drm_atomic_state * state)26032a1795fSJyri Sarha static void tidss_crtc_atomic_disable(struct drm_crtc *crtc,
261351f950dSMaxime Ripard struct drm_atomic_state *state)
26232a1795fSJyri Sarha {
26332a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
26432a1795fSJyri Sarha struct drm_device *ddev = crtc->dev;
26502bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev);
26632a1795fSJyri Sarha unsigned long flags;
26732a1795fSJyri Sarha
26832a1795fSJyri Sarha dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
26932a1795fSJyri Sarha
27032a1795fSJyri Sarha reinit_completion(&tcrtc->framedone_completion);
27132a1795fSJyri Sarha
272*1dce1ceeSTomi Valkeinen /*
273*1dce1ceeSTomi Valkeinen * If a layer is left enabled when the videoport is disabled, and the
274*1dce1ceeSTomi Valkeinen * vid pipeline that was used for the layer is taken into use on
275*1dce1ceeSTomi Valkeinen * another videoport, the DSS will report sync lost issues. Disable all
276*1dce1ceeSTomi Valkeinen * the layers here as a work-around.
277*1dce1ceeSTomi Valkeinen */
278*1dce1ceeSTomi Valkeinen for (u32 layer = 0; layer < tidss->feat->num_planes; layer++)
279*1dce1ceeSTomi Valkeinen dispc_ovr_enable_layer(tidss->dispc, tcrtc->hw_videoport, layer,
280*1dce1ceeSTomi Valkeinen false);
281*1dce1ceeSTomi Valkeinen
28232a1795fSJyri Sarha dispc_vp_disable(tidss->dispc, tcrtc->hw_videoport);
28332a1795fSJyri Sarha
28432a1795fSJyri Sarha if (!wait_for_completion_timeout(&tcrtc->framedone_completion,
28532a1795fSJyri Sarha msecs_to_jiffies(500)))
28632a1795fSJyri Sarha dev_err(tidss->dev, "Timeout waiting for framedone on crtc %d",
28732a1795fSJyri Sarha tcrtc->hw_videoport);
28832a1795fSJyri Sarha
28932a1795fSJyri Sarha dispc_vp_unprepare(tidss->dispc, tcrtc->hw_videoport);
29032a1795fSJyri Sarha
29132a1795fSJyri Sarha spin_lock_irqsave(&ddev->event_lock, flags);
29232a1795fSJyri Sarha if (crtc->state->event) {
29332a1795fSJyri Sarha drm_crtc_send_vblank_event(crtc, crtc->state->event);
29432a1795fSJyri Sarha crtc->state->event = NULL;
29532a1795fSJyri Sarha }
29632a1795fSJyri Sarha spin_unlock_irqrestore(&ddev->event_lock, flags);
29732a1795fSJyri Sarha
29832a1795fSJyri Sarha drm_crtc_vblank_off(crtc);
29932a1795fSJyri Sarha
30032a1795fSJyri Sarha dispc_vp_disable_clk(tidss->dispc, tcrtc->hw_videoport);
30132a1795fSJyri Sarha
30232a1795fSJyri Sarha tidss_runtime_put(tidss);
30332a1795fSJyri Sarha }
30432a1795fSJyri Sarha
30532a1795fSJyri Sarha static
tidss_crtc_mode_valid(struct drm_crtc * crtc,const struct drm_display_mode * mode)30632a1795fSJyri Sarha enum drm_mode_status tidss_crtc_mode_valid(struct drm_crtc *crtc,
30732a1795fSJyri Sarha const struct drm_display_mode *mode)
30832a1795fSJyri Sarha {
30932a1795fSJyri Sarha struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
31032a1795fSJyri Sarha struct drm_device *ddev = crtc->dev;
31102bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev);
31232a1795fSJyri Sarha
31332a1795fSJyri Sarha return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode);
31432a1795fSJyri Sarha }
31532a1795fSJyri Sarha
31632a1795fSJyri Sarha static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = {
31732a1795fSJyri Sarha .atomic_check = tidss_crtc_atomic_check,
31832a1795fSJyri Sarha .atomic_flush = tidss_crtc_atomic_flush,
31932a1795fSJyri Sarha .atomic_enable = tidss_crtc_atomic_enable,
32032a1795fSJyri Sarha .atomic_disable = tidss_crtc_atomic_disable,
32132a1795fSJyri Sarha
32232a1795fSJyri Sarha .mode_valid = tidss_crtc_mode_valid,
32332a1795fSJyri Sarha };
32432a1795fSJyri Sarha
32532a1795fSJyri Sarha /* drm_crtc_funcs */
32632a1795fSJyri Sarha
tidss_crtc_enable_vblank(struct drm_crtc * crtc)32732a1795fSJyri Sarha static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
32832a1795fSJyri Sarha {
32932a1795fSJyri Sarha struct drm_device *ddev = crtc->dev;
33002bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev);
33132a1795fSJyri Sarha
33232a1795fSJyri Sarha dev_dbg(ddev->dev, "%s\n", __func__);
33332a1795fSJyri Sarha
33432a1795fSJyri Sarha tidss_runtime_get(tidss);
33532a1795fSJyri Sarha
33632a1795fSJyri Sarha tidss_irq_enable_vblank(crtc);
33732a1795fSJyri Sarha
33832a1795fSJyri Sarha return 0;
33932a1795fSJyri Sarha }
34032a1795fSJyri Sarha
tidss_crtc_disable_vblank(struct drm_crtc * crtc)34132a1795fSJyri Sarha static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
34232a1795fSJyri Sarha {
34332a1795fSJyri Sarha struct drm_device *ddev = crtc->dev;
34402bb1317SDaniel Vetter struct tidss_device *tidss = to_tidss(ddev);
34532a1795fSJyri Sarha
34632a1795fSJyri Sarha dev_dbg(ddev->dev, "%s\n", __func__);
34732a1795fSJyri Sarha
34832a1795fSJyri Sarha tidss_irq_disable_vblank(crtc);
34932a1795fSJyri Sarha
35032a1795fSJyri Sarha tidss_runtime_put(tidss);
35132a1795fSJyri Sarha }
35232a1795fSJyri Sarha
tidss_crtc_reset(struct drm_crtc * crtc)35332a1795fSJyri Sarha static void tidss_crtc_reset(struct drm_crtc *crtc)
35432a1795fSJyri Sarha {
35532a1795fSJyri Sarha struct tidss_crtc_state *tcrtc;
35632a1795fSJyri Sarha
35732a1795fSJyri Sarha if (crtc->state)
35832a1795fSJyri Sarha __drm_atomic_helper_crtc_destroy_state(crtc->state);
35932a1795fSJyri Sarha
36032a1795fSJyri Sarha kfree(crtc->state);
36132a1795fSJyri Sarha
36232a1795fSJyri Sarha tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
36332a1795fSJyri Sarha if (!tcrtc) {
36432a1795fSJyri Sarha crtc->state = NULL;
36532a1795fSJyri Sarha return;
36632a1795fSJyri Sarha }
36732a1795fSJyri Sarha
36851f644b4SDaniel Vetter __drm_atomic_helper_crtc_reset(crtc, &tcrtc->base);
36932a1795fSJyri Sarha }
37032a1795fSJyri Sarha
tidss_crtc_duplicate_state(struct drm_crtc * crtc)37132a1795fSJyri Sarha static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
37232a1795fSJyri Sarha {
37332a1795fSJyri Sarha struct tidss_crtc_state *state, *current_state;
37432a1795fSJyri Sarha
37532a1795fSJyri Sarha if (WARN_ON(!crtc->state))
37632a1795fSJyri Sarha return NULL;
37732a1795fSJyri Sarha
37832a1795fSJyri Sarha current_state = to_tidss_crtc_state(crtc->state);
37932a1795fSJyri Sarha
38032a1795fSJyri Sarha state = kmalloc(sizeof(*state), GFP_KERNEL);
38132a1795fSJyri Sarha if (!state)
38232a1795fSJyri Sarha return NULL;
38332a1795fSJyri Sarha
38432a1795fSJyri Sarha __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
38532a1795fSJyri Sarha
386b33b5474SJyri Sarha state->plane_pos_changed = false;
387b33b5474SJyri Sarha
38832a1795fSJyri Sarha state->bus_format = current_state->bus_format;
38932a1795fSJyri Sarha state->bus_flags = current_state->bus_flags;
39032a1795fSJyri Sarha
39132a1795fSJyri Sarha return &state->base;
39232a1795fSJyri Sarha }
39332a1795fSJyri Sarha
tidss_crtc_destroy(struct drm_crtc * crtc)3949da67433STomi Valkeinen static void tidss_crtc_destroy(struct drm_crtc *crtc)
3959da67433STomi Valkeinen {
3969da67433STomi Valkeinen struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
3979da67433STomi Valkeinen
3989da67433STomi Valkeinen drm_crtc_cleanup(crtc);
3999da67433STomi Valkeinen kfree(tcrtc);
4009da67433STomi Valkeinen }
4019da67433STomi Valkeinen
40232a1795fSJyri Sarha static const struct drm_crtc_funcs tidss_crtc_funcs = {
40332a1795fSJyri Sarha .reset = tidss_crtc_reset,
4049da67433STomi Valkeinen .destroy = tidss_crtc_destroy,
40532a1795fSJyri Sarha .set_config = drm_atomic_helper_set_config,
40632a1795fSJyri Sarha .page_flip = drm_atomic_helper_page_flip,
40732a1795fSJyri Sarha .atomic_duplicate_state = tidss_crtc_duplicate_state,
40832a1795fSJyri Sarha .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
40932a1795fSJyri Sarha .enable_vblank = tidss_crtc_enable_vblank,
41032a1795fSJyri Sarha .disable_vblank = tidss_crtc_disable_vblank,
41132a1795fSJyri Sarha };
41232a1795fSJyri Sarha
tidss_crtc_create(struct tidss_device * tidss,u32 hw_videoport,struct drm_plane * primary)41332a1795fSJyri Sarha struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
41432a1795fSJyri Sarha u32 hw_videoport,
41532a1795fSJyri Sarha struct drm_plane *primary)
41632a1795fSJyri Sarha {
41732a1795fSJyri Sarha struct tidss_crtc *tcrtc;
41832a1795fSJyri Sarha struct drm_crtc *crtc;
41932a1795fSJyri Sarha unsigned int gamma_lut_size = 0;
42032a1795fSJyri Sarha bool has_ctm = tidss->feat->vp_feat.color.has_ctm;
42132a1795fSJyri Sarha int ret;
42232a1795fSJyri Sarha
4239da67433STomi Valkeinen tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
42432a1795fSJyri Sarha if (!tcrtc)
42532a1795fSJyri Sarha return ERR_PTR(-ENOMEM);
42632a1795fSJyri Sarha
42732a1795fSJyri Sarha tcrtc->hw_videoport = hw_videoport;
42832a1795fSJyri Sarha init_completion(&tcrtc->framedone_completion);
42932a1795fSJyri Sarha
43032a1795fSJyri Sarha crtc = &tcrtc->crtc;
43132a1795fSJyri Sarha
43232a1795fSJyri Sarha ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary,
43332a1795fSJyri Sarha NULL, &tidss_crtc_funcs, NULL);
4349da67433STomi Valkeinen if (ret < 0) {
4359da67433STomi Valkeinen kfree(tcrtc);
43632a1795fSJyri Sarha return ERR_PTR(ret);
4379da67433STomi Valkeinen }
43832a1795fSJyri Sarha
43932a1795fSJyri Sarha drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs);
44032a1795fSJyri Sarha
44132a1795fSJyri Sarha /*
44232a1795fSJyri Sarha * The dispc gamma functions adapt to what ever size we ask
44332a1795fSJyri Sarha * from it no matter what HW supports. X-server assumes 256
44432a1795fSJyri Sarha * element gamma tables so lets use that.
44532a1795fSJyri Sarha */
44632a1795fSJyri Sarha if (tidss->feat->vp_feat.color.gamma_size)
44732a1795fSJyri Sarha gamma_lut_size = 256;
44832a1795fSJyri Sarha
44932a1795fSJyri Sarha drm_crtc_enable_color_mgmt(crtc, 0, has_ctm, gamma_lut_size);
45032a1795fSJyri Sarha if (gamma_lut_size)
45132a1795fSJyri Sarha drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size);
45232a1795fSJyri Sarha
45332a1795fSJyri Sarha return tcrtc;
45432a1795fSJyri Sarha }
455