brintos

brintos / linux-shallow public Read only

0
0
Text · 6.1 KiB · 31267c0 Raw
225 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright 2019 NXP.4 */5 6#include <drm/drm_atomic.h>7#include <drm/drm_atomic_helper.h>8#include <drm/drm_vblank.h>9#include <linux/platform_device.h>10#include <linux/pm_runtime.h>11 12#include "dcss-dev.h"13#include "dcss-kms.h"14 15static int dcss_enable_vblank(struct drm_crtc *crtc)16{17	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,18						   base);19	struct dcss_dev *dcss = crtc->dev->dev_private;20 21	dcss_dtg_vblank_irq_enable(dcss->dtg, true);22 23	dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, true);24 25	enable_irq(dcss_crtc->irq);26 27	return 0;28}29 30static void dcss_disable_vblank(struct drm_crtc *crtc)31{32	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,33						   base);34	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;35 36	disable_irq_nosync(dcss_crtc->irq);37 38	dcss_dtg_vblank_irq_enable(dcss->dtg, false);39 40	if (dcss_crtc->disable_ctxld_kick_irq)41		dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, false);42}43 44static const struct drm_crtc_funcs dcss_crtc_funcs = {45	.set_config = drm_atomic_helper_set_config,46	.destroy = drm_crtc_cleanup,47	.page_flip = drm_atomic_helper_page_flip,48	.reset = drm_atomic_helper_crtc_reset,49	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,50	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,51	.enable_vblank = dcss_enable_vblank,52	.disable_vblank = dcss_disable_vblank,53};54 55static void dcss_crtc_atomic_begin(struct drm_crtc *crtc,56				   struct drm_atomic_state *state)57{58	drm_crtc_vblank_on(crtc);59}60 61static void dcss_crtc_atomic_flush(struct drm_crtc *crtc,62				   struct drm_atomic_state *state)63{64	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,65						   base);66	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;67 68	spin_lock_irq(&crtc->dev->event_lock);69	if (crtc->state->event) {70		WARN_ON(drm_crtc_vblank_get(crtc));71		drm_crtc_arm_vblank_event(crtc, crtc->state->event);72		crtc->state->event = NULL;73	}74	spin_unlock_irq(&crtc->dev->event_lock);75 76	if (dcss_dtg_is_enabled(dcss->dtg))77		dcss_ctxld_enable(dcss->ctxld);78}79 80static void dcss_crtc_atomic_enable(struct drm_crtc *crtc,81				    struct drm_atomic_state *state)82{83	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,84									      crtc);85	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,86						   base);87	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;88	struct drm_display_mode *mode = &crtc->state->adjusted_mode;89	struct drm_display_mode *old_mode = &old_crtc_state->adjusted_mode;90	struct videomode vm;91 92	drm_display_mode_to_videomode(mode, &vm);93 94	pm_runtime_get_sync(dcss->dev);95 96	vm.pixelclock = mode->crtc_clock * 1000;97 98	dcss_ss_subsam_set(dcss->ss);99	dcss_dtg_css_set(dcss->dtg);100 101	if (!drm_mode_equal(mode, old_mode) || !old_crtc_state->active) {102		dcss_dtg_sync_set(dcss->dtg, &vm);103		dcss_ss_sync_set(dcss->ss, &vm,104				 mode->flags & DRM_MODE_FLAG_PHSYNC,105				 mode->flags & DRM_MODE_FLAG_PVSYNC);106	}107 108	dcss_enable_dtg_and_ss(dcss);109 110	dcss_ctxld_enable(dcss->ctxld);111 112	/* Allow CTXLD kick interrupt to be disabled when VBLANK is disabled. */113	dcss_crtc->disable_ctxld_kick_irq = true;114}115 116static void dcss_crtc_atomic_disable(struct drm_crtc *crtc,117				     struct drm_atomic_state *state)118{119	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,120									      crtc);121	struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,122						   base);123	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;124	struct drm_display_mode *mode = &crtc->state->adjusted_mode;125	struct drm_display_mode *old_mode = &old_crtc_state->adjusted_mode;126 127	drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);128 129	spin_lock_irq(&crtc->dev->event_lock);130	if (crtc->state->event) {131		drm_crtc_send_vblank_event(crtc, crtc->state->event);132		crtc->state->event = NULL;133	}134	spin_unlock_irq(&crtc->dev->event_lock);135 136	dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, true);137 138	reinit_completion(&dcss->disable_completion);139 140	dcss_disable_dtg_and_ss(dcss);141 142	dcss_ctxld_enable(dcss->ctxld);143 144	if (!drm_mode_equal(mode, old_mode) || !crtc->state->active)145		if (!wait_for_completion_timeout(&dcss->disable_completion,146						 msecs_to_jiffies(100)))147			dev_err(dcss->dev, "Shutting off DTG timed out.\n");148 149	/*150	 * Do not shut off CTXLD kick interrupt when shutting VBLANK off. It151	 * will be needed to commit the last changes, before going to suspend.152	 */153	dcss_crtc->disable_ctxld_kick_irq = false;154 155	drm_crtc_vblank_off(crtc);156 157	pm_runtime_mark_last_busy(dcss->dev);158	pm_runtime_put_autosuspend(dcss->dev);159}160 161static const struct drm_crtc_helper_funcs dcss_helper_funcs = {162	.atomic_begin = dcss_crtc_atomic_begin,163	.atomic_flush = dcss_crtc_atomic_flush,164	.atomic_enable = dcss_crtc_atomic_enable,165	.atomic_disable = dcss_crtc_atomic_disable,166};167 168static irqreturn_t dcss_crtc_irq_handler(int irq, void *dev_id)169{170	struct dcss_crtc *dcss_crtc = dev_id;171	struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;172 173	if (!dcss_dtg_vblank_irq_valid(dcss->dtg))174		return IRQ_NONE;175 176	if (dcss_ctxld_is_flushed(dcss->ctxld))177		drm_crtc_handle_vblank(&dcss_crtc->base);178 179	dcss_dtg_vblank_irq_clear(dcss->dtg);180 181	return IRQ_HANDLED;182}183 184int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm)185{186	struct dcss_dev *dcss = drm->dev_private;187	struct platform_device *pdev = to_platform_device(dcss->dev);188	int ret;189 190	crtc->plane[0] = dcss_plane_init(drm, drm_crtc_mask(&crtc->base),191					 DRM_PLANE_TYPE_PRIMARY, 0);192	if (IS_ERR(crtc->plane[0]))193		return PTR_ERR(crtc->plane[0]);194 195	crtc->base.port = dcss->of_port;196 197	drm_crtc_helper_add(&crtc->base, &dcss_helper_funcs);198	ret = drm_crtc_init_with_planes(drm, &crtc->base, &crtc->plane[0]->base,199					NULL, &dcss_crtc_funcs, NULL);200	if (ret) {201		dev_err(dcss->dev, "failed to init crtc\n");202		return ret;203	}204 205	crtc->irq = platform_get_irq_byname(pdev, "vblank");206	if (crtc->irq < 0)207		return crtc->irq;208 209	ret = request_irq(crtc->irq, dcss_crtc_irq_handler,210			  0, "dcss_drm", crtc);211	if (ret) {212		dev_err(dcss->dev, "irq request failed with %d.\n", ret);213		return ret;214	}215 216	disable_irq(crtc->irq);217 218	return 0;219}220 221void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm)222{223	free_irq(crtc->irq, crtc);224}225