18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ 48c2ecf20Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "tidss_crtc.h" 108c2ecf20Sopenharmony_ci#include "tidss_dispc.h" 118c2ecf20Sopenharmony_ci#include "tidss_drv.h" 128c2ecf20Sopenharmony_ci#include "tidss_irq.h" 138c2ecf20Sopenharmony_ci#include "tidss_plane.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* call with wait_lock and dispc runtime held */ 168c2ecf20Sopenharmony_cistatic void tidss_irq_update(struct tidss_device *tidss) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci assert_spin_locked(&tidss->wait_lock); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci dispc_set_irqenable(tidss->dispc, tidss->irq_mask); 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_civoid tidss_irq_enable_vblank(struct drm_crtc *crtc) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct drm_device *ddev = crtc->dev; 268c2ecf20Sopenharmony_ci struct tidss_device *tidss = to_tidss(ddev); 278c2ecf20Sopenharmony_ci struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 288c2ecf20Sopenharmony_ci u32 hw_videoport = tcrtc->hw_videoport; 298c2ecf20Sopenharmony_ci unsigned long flags; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci spin_lock_irqsave(&tidss->wait_lock, flags); 328c2ecf20Sopenharmony_ci tidss->irq_mask |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) | 338c2ecf20Sopenharmony_ci DSS_IRQ_VP_VSYNC_ODD(hw_videoport); 348c2ecf20Sopenharmony_ci tidss_irq_update(tidss); 358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tidss->wait_lock, flags); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_civoid tidss_irq_disable_vblank(struct drm_crtc *crtc) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct drm_device *ddev = crtc->dev; 418c2ecf20Sopenharmony_ci struct tidss_device *tidss = to_tidss(ddev); 428c2ecf20Sopenharmony_ci struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 438c2ecf20Sopenharmony_ci u32 hw_videoport = tcrtc->hw_videoport; 448c2ecf20Sopenharmony_ci unsigned long flags; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci spin_lock_irqsave(&tidss->wait_lock, flags); 478c2ecf20Sopenharmony_ci tidss->irq_mask &= ~(DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) | 488c2ecf20Sopenharmony_ci DSS_IRQ_VP_VSYNC_ODD(hw_videoport)); 498c2ecf20Sopenharmony_ci tidss_irq_update(tidss); 508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tidss->wait_lock, flags); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciirqreturn_t tidss_irq_handler(int irq, void *arg) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct drm_device *ddev = (struct drm_device *)arg; 568c2ecf20Sopenharmony_ci struct tidss_device *tidss = to_tidss(ddev); 578c2ecf20Sopenharmony_ci unsigned int id; 588c2ecf20Sopenharmony_ci dispc_irq_t irqstatus; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (WARN_ON(!ddev->irq_enabled)) 618c2ecf20Sopenharmony_ci return IRQ_NONE; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci irqstatus = dispc_read_and_clear_irqstatus(tidss->dispc); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci for (id = 0; id < tidss->num_crtcs; id++) { 668c2ecf20Sopenharmony_ci struct drm_crtc *crtc = tidss->crtcs[id]; 678c2ecf20Sopenharmony_ci struct tidss_crtc *tcrtc = to_tidss_crtc(crtc); 688c2ecf20Sopenharmony_ci u32 hw_videoport = tcrtc->hw_videoport; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (irqstatus & (DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) | 718c2ecf20Sopenharmony_ci DSS_IRQ_VP_VSYNC_ODD(hw_videoport))) 728c2ecf20Sopenharmony_ci tidss_crtc_vblank_irq(crtc); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (irqstatus & (DSS_IRQ_VP_FRAME_DONE(hw_videoport))) 758c2ecf20Sopenharmony_ci tidss_crtc_framedone_irq(crtc); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (irqstatus & DSS_IRQ_VP_SYNC_LOST(hw_videoport)) 788c2ecf20Sopenharmony_ci tidss_crtc_error_irq(crtc, irqstatus); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (irqstatus & DSS_IRQ_DEVICE_OCP_ERR) 828c2ecf20Sopenharmony_ci dev_err_ratelimited(tidss->dev, "OCP error\n"); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return IRQ_HANDLED; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_civoid tidss_irq_resume(struct tidss_device *tidss) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci unsigned long flags; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci spin_lock_irqsave(&tidss->wait_lock, flags); 928c2ecf20Sopenharmony_ci tidss_irq_update(tidss); 938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tidss->wait_lock, flags); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_civoid tidss_irq_preinstall(struct drm_device *ddev) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct tidss_device *tidss = to_tidss(ddev); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci spin_lock_init(&tidss->wait_lock); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci tidss_runtime_get(tidss); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci dispc_set_irqenable(tidss->dispc, 0); 1058c2ecf20Sopenharmony_ci dispc_read_and_clear_irqstatus(tidss->dispc); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci tidss_runtime_put(tidss); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ciint tidss_irq_postinstall(struct drm_device *ddev) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct tidss_device *tidss = to_tidss(ddev); 1138c2ecf20Sopenharmony_ci unsigned long flags; 1148c2ecf20Sopenharmony_ci unsigned int i; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci tidss_runtime_get(tidss); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci spin_lock_irqsave(&tidss->wait_lock, flags); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci tidss->irq_mask = DSS_IRQ_DEVICE_OCP_ERR; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci for (i = 0; i < tidss->num_crtcs; ++i) { 1238c2ecf20Sopenharmony_ci struct tidss_crtc *tcrtc = to_tidss_crtc(tidss->crtcs[i]); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci tidss->irq_mask |= DSS_IRQ_VP_SYNC_LOST(tcrtc->hw_videoport); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci tidss->irq_mask |= DSS_IRQ_VP_FRAME_DONE(tcrtc->hw_videoport); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci tidss_irq_update(tidss); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tidss->wait_lock, flags); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci tidss_runtime_put(tidss); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_civoid tidss_irq_uninstall(struct drm_device *ddev) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct tidss_device *tidss = to_tidss(ddev); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci tidss_runtime_get(tidss); 1448c2ecf20Sopenharmony_ci dispc_set_irqenable(tidss->dispc, 0); 1458c2ecf20Sopenharmony_ci tidss_runtime_put(tidss); 1468c2ecf20Sopenharmony_ci} 147