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