diff options
Diffstat (limited to 'drivers/gpu/drm/loongson/lsdc_irq.c')
-rw-r--r-- | drivers/gpu/drm/loongson/lsdc_irq.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/gpu/drm/loongson/lsdc_irq.c b/drivers/gpu/drm/loongson/lsdc_irq.c new file mode 100644 index 000000000000..efdc4d10792d --- /dev/null +++ b/drivers/gpu/drm/loongson/lsdc_irq.c @@ -0,0 +1,74 @@ +// 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; +} |