brintos

brintos / linux-shallow public Read only

0
0
Text · 3.3 KiB · 604334e Raw
127 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>5 */6 7#include <linux/platform_device.h>8 9#include <drm/drm_drv.h>10#include <drm/drm_print.h>11 12#include "tidss_crtc.h"13#include "tidss_dispc.h"14#include "tidss_drv.h"15#include "tidss_irq.h"16#include "tidss_plane.h"17 18/* call with wait_lock and dispc runtime held */19static void tidss_irq_update(struct tidss_device *tidss)20{21	assert_spin_locked(&tidss->wait_lock);22 23	dispc_set_irqenable(tidss->dispc, tidss->irq_mask);24}25 26void tidss_irq_enable_vblank(struct drm_crtc *crtc)27{28	struct drm_device *ddev = crtc->dev;29	struct tidss_device *tidss = to_tidss(ddev);30	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);31	u32 hw_videoport = tcrtc->hw_videoport;32	unsigned long flags;33 34	spin_lock_irqsave(&tidss->wait_lock, flags);35	tidss->irq_mask |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |36			   DSS_IRQ_VP_VSYNC_ODD(hw_videoport);37	tidss_irq_update(tidss);38	spin_unlock_irqrestore(&tidss->wait_lock, flags);39}40 41void tidss_irq_disable_vblank(struct drm_crtc *crtc)42{43	struct drm_device *ddev = crtc->dev;44	struct tidss_device *tidss = to_tidss(ddev);45	struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);46	u32 hw_videoport = tcrtc->hw_videoport;47	unsigned long flags;48 49	spin_lock_irqsave(&tidss->wait_lock, flags);50	tidss->irq_mask &= ~(DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |51			     DSS_IRQ_VP_VSYNC_ODD(hw_videoport));52	tidss_irq_update(tidss);53	spin_unlock_irqrestore(&tidss->wait_lock, flags);54}55 56static irqreturn_t tidss_irq_handler(int irq, void *arg)57{58	struct drm_device *ddev = (struct drm_device *)arg;59	struct tidss_device *tidss = to_tidss(ddev);60	unsigned int id;61	dispc_irq_t irqstatus;62 63	irqstatus = dispc_read_and_clear_irqstatus(tidss->dispc);64 65	for (id = 0; id < tidss->num_crtcs; id++) {66		struct drm_crtc *crtc = tidss->crtcs[id];67		struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);68		u32 hw_videoport = tcrtc->hw_videoport;69 70		if (irqstatus & (DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |71				 DSS_IRQ_VP_VSYNC_ODD(hw_videoport)))72			tidss_crtc_vblank_irq(crtc);73 74		if (irqstatus & (DSS_IRQ_VP_FRAME_DONE(hw_videoport)))75			tidss_crtc_framedone_irq(crtc);76 77		if (irqstatus & DSS_IRQ_VP_SYNC_LOST(hw_videoport))78			tidss_crtc_error_irq(crtc, irqstatus);79	}80 81	if (irqstatus & DSS_IRQ_DEVICE_OCP_ERR)82		dev_err_ratelimited(tidss->dev, "OCP error\n");83 84	return IRQ_HANDLED;85}86 87void tidss_irq_resume(struct tidss_device *tidss)88{89	unsigned long flags;90 91	spin_lock_irqsave(&tidss->wait_lock, flags);92	tidss_irq_update(tidss);93	spin_unlock_irqrestore(&tidss->wait_lock, flags);94}95 96int tidss_irq_install(struct drm_device *ddev, unsigned int irq)97{98	struct tidss_device *tidss = to_tidss(ddev);99	int ret;100 101	if (irq == IRQ_NOTCONNECTED)102		return -ENOTCONN;103 104	ret = request_irq(irq, tidss_irq_handler, 0, ddev->driver->name, ddev);105	if (ret)106		return ret;107 108	tidss->irq_mask = DSS_IRQ_DEVICE_OCP_ERR;109 110	for (unsigned int i = 0; i < tidss->num_crtcs; ++i) {111		struct tidss_crtc *tcrtc = to_tidss_crtc(tidss->crtcs[i]);112 113		tidss->irq_mask |= DSS_IRQ_VP_SYNC_LOST(tcrtc->hw_videoport);114 115		tidss->irq_mask |= DSS_IRQ_VP_FRAME_DONE(tcrtc->hw_videoport);116	}117 118	return 0;119}120 121void tidss_irq_uninstall(struct drm_device *ddev)122{123	struct tidss_device *tidss = to_tidss(ddev);124 125	free_irq(tidss->irq, ddev);126}127