xref: /openbmc/linux/drivers/gpu/drm/tidss/tidss_irq.c (revision 02bb1317d5e4002e65a3debfb27ae2a1bfd0a3c2)
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_print.h>
832a1795fSJyri Sarha 
932a1795fSJyri Sarha #include "tidss_crtc.h"
1032a1795fSJyri Sarha #include "tidss_dispc.h"
1132a1795fSJyri Sarha #include "tidss_drv.h"
1232a1795fSJyri Sarha #include "tidss_irq.h"
1332a1795fSJyri Sarha #include "tidss_plane.h"
1432a1795fSJyri Sarha 
1532a1795fSJyri Sarha /* call with wait_lock and dispc runtime held */
1632a1795fSJyri Sarha static void tidss_irq_update(struct tidss_device *tidss)
1732a1795fSJyri Sarha {
1832a1795fSJyri Sarha 	assert_spin_locked(&tidss->wait_lock);
1932a1795fSJyri Sarha 
2032a1795fSJyri Sarha 	dispc_set_irqenable(tidss->dispc, tidss->irq_mask);
2132a1795fSJyri Sarha }
2232a1795fSJyri Sarha 
2332a1795fSJyri Sarha void tidss_irq_enable_vblank(struct drm_crtc *crtc)
2432a1795fSJyri Sarha {
2532a1795fSJyri Sarha 	struct drm_device *ddev = crtc->dev;
26*02bb1317SDaniel Vetter 	struct tidss_device *tidss = to_tidss(ddev);
2732a1795fSJyri Sarha 	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
2832a1795fSJyri Sarha 	u32 hw_videoport = tcrtc->hw_videoport;
2932a1795fSJyri Sarha 	unsigned long flags;
3032a1795fSJyri Sarha 
3132a1795fSJyri Sarha 	spin_lock_irqsave(&tidss->wait_lock, flags);
3232a1795fSJyri Sarha 	tidss->irq_mask |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
3332a1795fSJyri Sarha 			   DSS_IRQ_VP_VSYNC_ODD(hw_videoport);
3432a1795fSJyri Sarha 	tidss_irq_update(tidss);
3532a1795fSJyri Sarha 	spin_unlock_irqrestore(&tidss->wait_lock, flags);
3632a1795fSJyri Sarha }
3732a1795fSJyri Sarha 
3832a1795fSJyri Sarha void tidss_irq_disable_vblank(struct drm_crtc *crtc)
3932a1795fSJyri Sarha {
4032a1795fSJyri Sarha 	struct drm_device *ddev = crtc->dev;
41*02bb1317SDaniel Vetter 	struct tidss_device *tidss = to_tidss(ddev);
4232a1795fSJyri Sarha 	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
4332a1795fSJyri Sarha 	u32 hw_videoport = tcrtc->hw_videoport;
4432a1795fSJyri Sarha 	unsigned long flags;
4532a1795fSJyri Sarha 
4632a1795fSJyri Sarha 	spin_lock_irqsave(&tidss->wait_lock, flags);
4732a1795fSJyri Sarha 	tidss->irq_mask &= ~(DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
4832a1795fSJyri Sarha 			     DSS_IRQ_VP_VSYNC_ODD(hw_videoport));
4932a1795fSJyri Sarha 	tidss_irq_update(tidss);
5032a1795fSJyri Sarha 	spin_unlock_irqrestore(&tidss->wait_lock, flags);
5132a1795fSJyri Sarha }
5232a1795fSJyri Sarha 
5332a1795fSJyri Sarha irqreturn_t tidss_irq_handler(int irq, void *arg)
5432a1795fSJyri Sarha {
5532a1795fSJyri Sarha 	struct drm_device *ddev = (struct drm_device *)arg;
56*02bb1317SDaniel Vetter 	struct tidss_device *tidss = to_tidss(ddev);
5732a1795fSJyri Sarha 	unsigned int id;
5832a1795fSJyri Sarha 	dispc_irq_t irqstatus;
5932a1795fSJyri Sarha 
6032a1795fSJyri Sarha 	if (WARN_ON(!ddev->irq_enabled))
6132a1795fSJyri Sarha 		return IRQ_NONE;
6232a1795fSJyri Sarha 
6332a1795fSJyri Sarha 	irqstatus = dispc_read_and_clear_irqstatus(tidss->dispc);
6432a1795fSJyri Sarha 
6532a1795fSJyri Sarha 	for (id = 0; id < tidss->num_crtcs; id++) {
6632a1795fSJyri Sarha 		struct drm_crtc *crtc = tidss->crtcs[id];
6732a1795fSJyri Sarha 		struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
6832a1795fSJyri Sarha 		u32 hw_videoport = tcrtc->hw_videoport;
6932a1795fSJyri Sarha 
7032a1795fSJyri Sarha 		if (irqstatus & (DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
7132a1795fSJyri Sarha 				 DSS_IRQ_VP_VSYNC_ODD(hw_videoport)))
7232a1795fSJyri Sarha 			tidss_crtc_vblank_irq(crtc);
7332a1795fSJyri Sarha 
7432a1795fSJyri Sarha 		if (irqstatus & (DSS_IRQ_VP_FRAME_DONE(hw_videoport)))
7532a1795fSJyri Sarha 			tidss_crtc_framedone_irq(crtc);
7632a1795fSJyri Sarha 
7732a1795fSJyri Sarha 		if (irqstatus & DSS_IRQ_VP_SYNC_LOST(hw_videoport))
7832a1795fSJyri Sarha 			tidss_crtc_error_irq(crtc, irqstatus);
7932a1795fSJyri Sarha 	}
8032a1795fSJyri Sarha 
8132a1795fSJyri Sarha 	if (irqstatus & DSS_IRQ_DEVICE_OCP_ERR)
8232a1795fSJyri Sarha 		dev_err_ratelimited(tidss->dev, "OCP error\n");
8332a1795fSJyri Sarha 
8432a1795fSJyri Sarha 	return IRQ_HANDLED;
8532a1795fSJyri Sarha }
8632a1795fSJyri Sarha 
8732a1795fSJyri Sarha void tidss_irq_resume(struct tidss_device *tidss)
8832a1795fSJyri Sarha {
8932a1795fSJyri Sarha 	unsigned long flags;
9032a1795fSJyri Sarha 
9132a1795fSJyri Sarha 	spin_lock_irqsave(&tidss->wait_lock, flags);
9232a1795fSJyri Sarha 	tidss_irq_update(tidss);
9332a1795fSJyri Sarha 	spin_unlock_irqrestore(&tidss->wait_lock, flags);
9432a1795fSJyri Sarha }
9532a1795fSJyri Sarha 
9632a1795fSJyri Sarha void tidss_irq_preinstall(struct drm_device *ddev)
9732a1795fSJyri Sarha {
98*02bb1317SDaniel Vetter 	struct tidss_device *tidss = to_tidss(ddev);
9932a1795fSJyri Sarha 
10032a1795fSJyri Sarha 	spin_lock_init(&tidss->wait_lock);
10132a1795fSJyri Sarha 
10232a1795fSJyri Sarha 	tidss_runtime_get(tidss);
10332a1795fSJyri Sarha 
10432a1795fSJyri Sarha 	dispc_set_irqenable(tidss->dispc, 0);
10532a1795fSJyri Sarha 	dispc_read_and_clear_irqstatus(tidss->dispc);
10632a1795fSJyri Sarha 
10732a1795fSJyri Sarha 	tidss_runtime_put(tidss);
10832a1795fSJyri Sarha }
10932a1795fSJyri Sarha 
11032a1795fSJyri Sarha int tidss_irq_postinstall(struct drm_device *ddev)
11132a1795fSJyri Sarha {
112*02bb1317SDaniel Vetter 	struct tidss_device *tidss = to_tidss(ddev);
11332a1795fSJyri Sarha 	unsigned long flags;
11432a1795fSJyri Sarha 	unsigned int i;
11532a1795fSJyri Sarha 
11632a1795fSJyri Sarha 	tidss_runtime_get(tidss);
11732a1795fSJyri Sarha 
11832a1795fSJyri Sarha 	spin_lock_irqsave(&tidss->wait_lock, flags);
11932a1795fSJyri Sarha 
12032a1795fSJyri Sarha 	tidss->irq_mask = DSS_IRQ_DEVICE_OCP_ERR;
12132a1795fSJyri Sarha 
12232a1795fSJyri Sarha 	for (i = 0; i < tidss->num_crtcs; ++i) {
12332a1795fSJyri Sarha 		struct tidss_crtc *tcrtc = to_tidss_crtc(tidss->crtcs[i]);
12432a1795fSJyri Sarha 
12532a1795fSJyri Sarha 		tidss->irq_mask |= DSS_IRQ_VP_SYNC_LOST(tcrtc->hw_videoport);
12632a1795fSJyri Sarha 
12732a1795fSJyri Sarha 		tidss->irq_mask |= DSS_IRQ_VP_FRAME_DONE(tcrtc->hw_videoport);
12832a1795fSJyri Sarha 	}
12932a1795fSJyri Sarha 
13032a1795fSJyri Sarha 	tidss_irq_update(tidss);
13132a1795fSJyri Sarha 
13232a1795fSJyri Sarha 	spin_unlock_irqrestore(&tidss->wait_lock, flags);
13332a1795fSJyri Sarha 
13432a1795fSJyri Sarha 	tidss_runtime_put(tidss);
13532a1795fSJyri Sarha 
13632a1795fSJyri Sarha 	return 0;
13732a1795fSJyri Sarha }
13832a1795fSJyri Sarha 
13932a1795fSJyri Sarha void tidss_irq_uninstall(struct drm_device *ddev)
14032a1795fSJyri Sarha {
141*02bb1317SDaniel Vetter 	struct tidss_device *tidss = to_tidss(ddev);
14232a1795fSJyri Sarha 
14332a1795fSJyri Sarha 	tidss_runtime_get(tidss);
14432a1795fSJyri Sarha 	dispc_set_irqenable(tidss->dispc, 0);
14532a1795fSJyri Sarha 	tidss_runtime_put(tidss);
14632a1795fSJyri Sarha }
147