Merge drm/drm-next into drm-misc-next
[linux-2.6-microblaze.git] / drivers / accel / ivpu / ivpu_hw_40xx.c
index a779b90..f7e1f5c 100644 (file)
@@ -58,8 +58,7 @@
 
 #define ICB_0_1_IRQ_MASK ((((u64)ICB_1_IRQ_MASK) << 32) | ICB_0_IRQ_MASK)
 
-#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE)) | \
-                          (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \
+#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \
                           (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, CFI0_ERR)) | \
                           (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, CFI1_ERR)) | \
                           (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, IMR0_ERR)) | \
@@ -207,6 +206,14 @@ static int ivpu_pll_wait_for_status_ready(struct ivpu_device *vdev)
        return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, READY, 1, PLL_TIMEOUT_US);
 }
 
+static int ivpu_wait_for_clock_own_resource_ack(struct ivpu_device *vdev)
+{
+       if (ivpu_is_simics(vdev))
+               return 0;
+
+       return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, CLOCK_RESOURCE_OWN_ACK, 1, TIMEOUT_US);
+}
+
 static void ivpu_pll_init_frequency_ratios(struct ivpu_device *vdev)
 {
        struct ivpu_hw_info *hw = vdev->hw;
@@ -567,6 +574,12 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev)
 {
        int ret;
 
+       ret = ivpu_wait_for_clock_own_resource_ack(vdev);
+       if (ret) {
+               ivpu_err(vdev, "Timed out waiting for clock own resource ACK\n");
+               return ret;
+       }
+
        ivpu_boot_pwr_island_trickle_drive(vdev, true);
        ivpu_boot_pwr_island_drive(vdev, true);
 
@@ -1077,8 +1090,6 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq)
        if (status == 0)
                return IRQ_NONE;
 
-       REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status);
-
        if (REG_TEST_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status))
                ivpu_dbg(vdev, IRQ, "FREQ_CHANGE");
 
@@ -1123,6 +1134,9 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq)
                schedule_recovery = true;
        }
 
+       /* This must be done after interrupts are cleared at the source. */
+       REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status);
+
        if (schedule_recovery)
                ivpu_pm_schedule_recovery(vdev);
 
@@ -1134,9 +1148,14 @@ static irqreturn_t ivpu_hw_40xx_irq_handler(int irq, void *ptr)
        struct ivpu_device *vdev = ptr;
        irqreturn_t ret = IRQ_NONE;
 
+       REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x1);
+
        ret |= ivpu_hw_40xx_irqv_handler(vdev, irq);
        ret |= ivpu_hw_40xx_irqb_handler(vdev, irq);
 
+       /* Re-enable global interrupts to re-trigger MSI for pending interrupts */
+       REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x0);
+
        if (ret & IRQ_WAKE_THREAD)
                return IRQ_WAKE_THREAD;
 
@@ -1192,6 +1211,7 @@ const struct ivpu_hw_ops ivpu_hw_40xx_ops = {
        .is_idle = ivpu_hw_40xx_is_idle,
        .wait_for_idle = ivpu_hw_40xx_wait_for_idle,
        .power_down = ivpu_hw_40xx_power_down,
+       .reset = ivpu_hw_40xx_reset,
        .boot_fw = ivpu_hw_40xx_boot_fw,
        .wdt_disable = ivpu_hw_40xx_wdt_disable,
        .diagnose_failure = ivpu_hw_40xx_diagnose_failure,