162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2023 Loongson Technology Corporation Limited 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <drm/drm_vblank.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "lsdc_irq.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * For the DC in LS7A2000, clearing interrupt status is achieved by 1262306a36Sopenharmony_ci * write "1" to LSDC_INT_REG. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * For the DC in LS7A1000, clear interrupt status is achieved by write "0" 1562306a36Sopenharmony_ci * to LSDC_INT_REG. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Two different hardware engineers modify it as their will. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciirqreturn_t ls7a2000_dc_irq_handler(int irq, void *arg) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct drm_device *ddev = arg; 2362306a36Sopenharmony_ci struct lsdc_device *ldev = to_lsdc(ddev); 2462306a36Sopenharmony_ci u32 val; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* Read the interrupt status */ 2762306a36Sopenharmony_ci val = lsdc_rreg32(ldev, LSDC_INT_REG); 2862306a36Sopenharmony_ci if ((val & INT_STATUS_MASK) == 0) { 2962306a36Sopenharmony_ci drm_warn(ddev, "no interrupt occurs\n"); 3062306a36Sopenharmony_ci return IRQ_NONE; 3162306a36Sopenharmony_ci } 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci ldev->irq_status = val; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* write "1" to clear the interrupt status */ 3662306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_INT_REG, val); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (ldev->irq_status & INT_CRTC0_VSYNC) 3962306a36Sopenharmony_ci drm_handle_vblank(ddev, 0); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (ldev->irq_status & INT_CRTC1_VSYNC) 4262306a36Sopenharmony_ci drm_handle_vblank(ddev, 1); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return IRQ_HANDLED; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* For the DC in LS7A1000 and LS2K1000 */ 4862306a36Sopenharmony_ciirqreturn_t ls7a1000_dc_irq_handler(int irq, void *arg) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct drm_device *ddev = arg; 5162306a36Sopenharmony_ci struct lsdc_device *ldev = to_lsdc(ddev); 5262306a36Sopenharmony_ci u32 val; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* Read the interrupt status */ 5562306a36Sopenharmony_ci val = lsdc_rreg32(ldev, LSDC_INT_REG); 5662306a36Sopenharmony_ci if ((val & INT_STATUS_MASK) == 0) { 5762306a36Sopenharmony_ci drm_warn(ddev, "no interrupt occurs\n"); 5862306a36Sopenharmony_ci return IRQ_NONE; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci ldev->irq_status = val; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* write "0" to clear the interrupt status */ 6462306a36Sopenharmony_ci val &= ~(INT_CRTC0_VSYNC | INT_CRTC1_VSYNC); 6562306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_INT_REG, val); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (ldev->irq_status & INT_CRTC0_VSYNC) 6862306a36Sopenharmony_ci drm_handle_vblank(ddev, 0); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (ldev->irq_status & INT_CRTC1_VSYNC) 7162306a36Sopenharmony_ci drm_handle_vblank(ddev, 1); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return IRQ_HANDLED; 7462306a36Sopenharmony_ci} 75