1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2023 Loongson Technology Corporation Limited 4 */ 5 6 #include <drm/drm_vblank.h> 7 8 #include "lsdc_irq.h" 9 10 /* 11 * For the DC in LS7A2000, clearing interrupt status is achieved by 12 * write "1" to LSDC_INT_REG. 13 * 14 * For the DC in LS7A1000, clear interrupt status is achieved by write "0" 15 * to LSDC_INT_REG. 16 * 17 * Two different hardware engineers modify it as their will. 18 */ 19 20 irqreturn_t ls7a2000_dc_irq_handler(int irq, void *arg) 21 { 22 struct drm_device *ddev = arg; 23 struct lsdc_device *ldev = to_lsdc(ddev); 24 u32 val; 25 26 /* Read the interrupt status */ 27 val = lsdc_rreg32(ldev, LSDC_INT_REG); 28 if ((val & INT_STATUS_MASK) == 0) { 29 drm_warn(ddev, "no interrupt occurs\n"); 30 return IRQ_NONE; 31 } 32 33 ldev->irq_status = val; 34 35 /* write "1" to clear the interrupt status */ 36 lsdc_wreg32(ldev, LSDC_INT_REG, val); 37 38 if (ldev->irq_status & INT_CRTC0_VSYNC) 39 drm_handle_vblank(ddev, 0); 40 41 if (ldev->irq_status & INT_CRTC1_VSYNC) 42 drm_handle_vblank(ddev, 1); 43 44 return IRQ_HANDLED; 45 } 46 47 /* For the DC in LS7A1000 and LS2K1000 */ 48 irqreturn_t ls7a1000_dc_irq_handler(int irq, void *arg) 49 { 50 struct drm_device *ddev = arg; 51 struct lsdc_device *ldev = to_lsdc(ddev); 52 u32 val; 53 54 /* Read the interrupt status */ 55 val = lsdc_rreg32(ldev, LSDC_INT_REG); 56 if ((val & INT_STATUS_MASK) == 0) { 57 drm_warn(ddev, "no interrupt occurs\n"); 58 return IRQ_NONE; 59 } 60 61 ldev->irq_status = val; 62 63 /* write "0" to clear the interrupt status */ 64 val &= ~(INT_CRTC0_VSYNC | INT_CRTC1_VSYNC); 65 lsdc_wreg32(ldev, LSDC_INT_REG, val); 66 67 if (ldev->irq_status & INT_CRTC0_VSYNC) 68 drm_handle_vblank(ddev, 0); 69 70 if (ldev->irq_status & INT_CRTC1_VSYNC) 71 drm_handle_vblank(ddev, 1); 72 73 return IRQ_HANDLED; 74 } 75