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