0001
0002
0003
0004
0005
0006
0007 #include <linux/platform_device.h>
0008
0009 #include <drm/drm_drv.h>
0010 #include <drm/drm_print.h>
0011
0012 #include "tidss_crtc.h"
0013 #include "tidss_dispc.h"
0014 #include "tidss_drv.h"
0015 #include "tidss_irq.h"
0016 #include "tidss_plane.h"
0017
0018
0019 static void tidss_irq_update(struct tidss_device *tidss)
0020 {
0021 assert_spin_locked(&tidss->wait_lock);
0022
0023 dispc_set_irqenable(tidss->dispc, tidss->irq_mask);
0024 }
0025
0026 void tidss_irq_enable_vblank(struct drm_crtc *crtc)
0027 {
0028 struct drm_device *ddev = crtc->dev;
0029 struct tidss_device *tidss = to_tidss(ddev);
0030 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0031 u32 hw_videoport = tcrtc->hw_videoport;
0032 unsigned long flags;
0033
0034 spin_lock_irqsave(&tidss->wait_lock, flags);
0035 tidss->irq_mask |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
0036 DSS_IRQ_VP_VSYNC_ODD(hw_videoport);
0037 tidss_irq_update(tidss);
0038 spin_unlock_irqrestore(&tidss->wait_lock, flags);
0039 }
0040
0041 void tidss_irq_disable_vblank(struct drm_crtc *crtc)
0042 {
0043 struct drm_device *ddev = crtc->dev;
0044 struct tidss_device *tidss = to_tidss(ddev);
0045 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0046 u32 hw_videoport = tcrtc->hw_videoport;
0047 unsigned long flags;
0048
0049 spin_lock_irqsave(&tidss->wait_lock, flags);
0050 tidss->irq_mask &= ~(DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
0051 DSS_IRQ_VP_VSYNC_ODD(hw_videoport));
0052 tidss_irq_update(tidss);
0053 spin_unlock_irqrestore(&tidss->wait_lock, flags);
0054 }
0055
0056 static irqreturn_t tidss_irq_handler(int irq, void *arg)
0057 {
0058 struct drm_device *ddev = (struct drm_device *)arg;
0059 struct tidss_device *tidss = to_tidss(ddev);
0060 unsigned int id;
0061 dispc_irq_t irqstatus;
0062
0063 irqstatus = dispc_read_and_clear_irqstatus(tidss->dispc);
0064
0065 for (id = 0; id < tidss->num_crtcs; id++) {
0066 struct drm_crtc *crtc = tidss->crtcs[id];
0067 struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
0068 u32 hw_videoport = tcrtc->hw_videoport;
0069
0070 if (irqstatus & (DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
0071 DSS_IRQ_VP_VSYNC_ODD(hw_videoport)))
0072 tidss_crtc_vblank_irq(crtc);
0073
0074 if (irqstatus & (DSS_IRQ_VP_FRAME_DONE(hw_videoport)))
0075 tidss_crtc_framedone_irq(crtc);
0076
0077 if (irqstatus & DSS_IRQ_VP_SYNC_LOST(hw_videoport))
0078 tidss_crtc_error_irq(crtc, irqstatus);
0079 }
0080
0081 if (irqstatus & DSS_IRQ_DEVICE_OCP_ERR)
0082 dev_err_ratelimited(tidss->dev, "OCP error\n");
0083
0084 return IRQ_HANDLED;
0085 }
0086
0087 void tidss_irq_resume(struct tidss_device *tidss)
0088 {
0089 unsigned long flags;
0090
0091 spin_lock_irqsave(&tidss->wait_lock, flags);
0092 tidss_irq_update(tidss);
0093 spin_unlock_irqrestore(&tidss->wait_lock, flags);
0094 }
0095
0096 static void tidss_irq_preinstall(struct drm_device *ddev)
0097 {
0098 struct tidss_device *tidss = to_tidss(ddev);
0099
0100 spin_lock_init(&tidss->wait_lock);
0101
0102 tidss_runtime_get(tidss);
0103
0104 dispc_set_irqenable(tidss->dispc, 0);
0105 dispc_read_and_clear_irqstatus(tidss->dispc);
0106
0107 tidss_runtime_put(tidss);
0108 }
0109
0110 static void tidss_irq_postinstall(struct drm_device *ddev)
0111 {
0112 struct tidss_device *tidss = to_tidss(ddev);
0113 unsigned long flags;
0114 unsigned int i;
0115
0116 tidss_runtime_get(tidss);
0117
0118 spin_lock_irqsave(&tidss->wait_lock, flags);
0119
0120 tidss->irq_mask = DSS_IRQ_DEVICE_OCP_ERR;
0121
0122 for (i = 0; i < tidss->num_crtcs; ++i) {
0123 struct tidss_crtc *tcrtc = to_tidss_crtc(tidss->crtcs[i]);
0124
0125 tidss->irq_mask |= DSS_IRQ_VP_SYNC_LOST(tcrtc->hw_videoport);
0126
0127 tidss->irq_mask |= DSS_IRQ_VP_FRAME_DONE(tcrtc->hw_videoport);
0128 }
0129
0130 tidss_irq_update(tidss);
0131
0132 spin_unlock_irqrestore(&tidss->wait_lock, flags);
0133
0134 tidss_runtime_put(tidss);
0135 }
0136
0137 int tidss_irq_install(struct drm_device *ddev, unsigned int irq)
0138 {
0139 int ret;
0140
0141 if (irq == IRQ_NOTCONNECTED)
0142 return -ENOTCONN;
0143
0144 tidss_irq_preinstall(ddev);
0145
0146 ret = request_irq(irq, tidss_irq_handler, 0, ddev->driver->name, ddev);
0147 if (ret)
0148 return ret;
0149
0150 tidss_irq_postinstall(ddev);
0151
0152 return 0;
0153 }
0154
0155 void tidss_irq_uninstall(struct drm_device *ddev)
0156 {
0157 struct tidss_device *tidss = to_tidss(ddev);
0158
0159 tidss_runtime_get(tidss);
0160 dispc_set_irqenable(tidss->dispc, 0);
0161 tidss_runtime_put(tidss);
0162
0163 free_irq(tidss->irq, ddev);
0164 }