| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Copyright (C) 2023 Loongson Technology Corporation Limited |
| */ |
| |
| #include <drm/drm_vblank.h> |
| |
| #include "lsdc_irq.h" |
| |
| /* |
| * For the DC in LS7A2000, clearing interrupt status is achieved by |
| * write "1" to LSDC_INT_REG. |
| * |
| * For the DC in LS7A1000, clear interrupt status is achieved by write "0" |
| * to LSDC_INT_REG. |
| * |
| * Two different hardware engineers modify it as their will. |
| */ |
| |
| irqreturn_t ls7a2000_dc_irq_handler(int irq, void *arg) |
| { |
| struct drm_device *ddev = arg; |
| struct lsdc_device *ldev = to_lsdc(ddev); |
| u32 val; |
| |
| /* Read the interrupt status */ |
| val = lsdc_rreg32(ldev, LSDC_INT_REG); |
| if ((val & INT_STATUS_MASK) == 0) { |
| drm_warn(ddev, "no interrupt occurs\n"); |
| return IRQ_NONE; |
| } |
| |
| ldev->irq_status = val; |
| |
| /* write "1" to clear the interrupt status */ |
| lsdc_wreg32(ldev, LSDC_INT_REG, val); |
| |
| if (ldev->irq_status & INT_CRTC0_VSYNC) |
| drm_handle_vblank(ddev, 0); |
| |
| if (ldev->irq_status & INT_CRTC1_VSYNC) |
| drm_handle_vblank(ddev, 1); |
| |
| return IRQ_HANDLED; |
| } |
| |
| /* For the DC in LS7A1000 and LS2K1000 */ |
| irqreturn_t ls7a1000_dc_irq_handler(int irq, void *arg) |
| { |
| struct drm_device *ddev = arg; |
| struct lsdc_device *ldev = to_lsdc(ddev); |
| u32 val; |
| |
| /* Read the interrupt status */ |
| val = lsdc_rreg32(ldev, LSDC_INT_REG); |
| if ((val & INT_STATUS_MASK) == 0) { |
| drm_warn(ddev, "no interrupt occurs\n"); |
| return IRQ_NONE; |
| } |
| |
| ldev->irq_status = val; |
| |
| /* write "0" to clear the interrupt status */ |
| val &= ~(INT_CRTC0_VSYNC | INT_CRTC1_VSYNC); |
| lsdc_wreg32(ldev, LSDC_INT_REG, val); |
| |
| if (ldev->irq_status & INT_CRTC0_VSYNC) |
| drm_handle_vblank(ddev, 0); |
| |
| if (ldev->irq_status & INT_CRTC1_VSYNC) |
| drm_handle_vblank(ddev, 1); |
| |
| return IRQ_HANDLED; |
| } |