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