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