Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
0004  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
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 /* call with wait_lock and dispc runtime held */
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 }