brintos

brintos / linux-shallow public Read only

0
0
Text · 22.5 KiB · 63ddc51 Raw
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