]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - drivers/gpu/drm/radeon/si.c
drm/radeon/kms: add dpm support for SI (v7)
[linux-imx.git] / drivers / gpu / drm / radeon / si.c
index 7d797f4db360751c0ee05bdbcb45930976d99c96..6c8caaf7a715c8a11cb7ba9b92d7b18a83728490 100644 (file)
@@ -41,26 +41,31 @@ MODULE_FIRMWARE("radeon/TAHITI_me.bin");
 MODULE_FIRMWARE("radeon/TAHITI_ce.bin");
 MODULE_FIRMWARE("radeon/TAHITI_mc.bin");
 MODULE_FIRMWARE("radeon/TAHITI_rlc.bin");
+MODULE_FIRMWARE("radeon/TAHITI_smc.bin");
 MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin");
 MODULE_FIRMWARE("radeon/PITCAIRN_me.bin");
 MODULE_FIRMWARE("radeon/PITCAIRN_ce.bin");
 MODULE_FIRMWARE("radeon/PITCAIRN_mc.bin");
 MODULE_FIRMWARE("radeon/PITCAIRN_rlc.bin");
+MODULE_FIRMWARE("radeon/PITCAIRN_smc.bin");
 MODULE_FIRMWARE("radeon/VERDE_pfp.bin");
 MODULE_FIRMWARE("radeon/VERDE_me.bin");
 MODULE_FIRMWARE("radeon/VERDE_ce.bin");
 MODULE_FIRMWARE("radeon/VERDE_mc.bin");
 MODULE_FIRMWARE("radeon/VERDE_rlc.bin");
+MODULE_FIRMWARE("radeon/VERDE_smc.bin");
 MODULE_FIRMWARE("radeon/OLAND_pfp.bin");
 MODULE_FIRMWARE("radeon/OLAND_me.bin");
 MODULE_FIRMWARE("radeon/OLAND_ce.bin");
 MODULE_FIRMWARE("radeon/OLAND_mc.bin");
 MODULE_FIRMWARE("radeon/OLAND_rlc.bin");
+MODULE_FIRMWARE("radeon/OLAND_smc.bin");
 MODULE_FIRMWARE("radeon/HAINAN_pfp.bin");
 MODULE_FIRMWARE("radeon/HAINAN_me.bin");
 MODULE_FIRMWARE("radeon/HAINAN_ce.bin");
 MODULE_FIRMWARE("radeon/HAINAN_mc.bin");
 MODULE_FIRMWARE("radeon/HAINAN_rlc.bin");
+MODULE_FIRMWARE("radeon/HAINAN_smc.bin");
 
 static void si_pcie_gen3_enable(struct radeon_device *rdev);
 static void si_program_aspm(struct radeon_device *rdev);
@@ -1540,6 +1545,7 @@ static int si_init_microcode(struct radeon_device *rdev)
        const char *chip_name;
        const char *rlc_chip_name;
        size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size;
+       size_t smc_req_size;
        char fw_name[30];
        int err;
 
@@ -1561,6 +1567,7 @@ static int si_init_microcode(struct radeon_device *rdev)
                ce_req_size = SI_CE_UCODE_SIZE * 4;
                rlc_req_size = SI_RLC_UCODE_SIZE * 4;
                mc_req_size = SI_MC_UCODE_SIZE * 4;
+               smc_req_size = ALIGN(TAHITI_SMC_UCODE_SIZE, 4);
                break;
        case CHIP_PITCAIRN:
                chip_name = "PITCAIRN";
@@ -1570,6 +1577,7 @@ static int si_init_microcode(struct radeon_device *rdev)
                ce_req_size = SI_CE_UCODE_SIZE * 4;
                rlc_req_size = SI_RLC_UCODE_SIZE * 4;
                mc_req_size = SI_MC_UCODE_SIZE * 4;
+               smc_req_size = ALIGN(PITCAIRN_SMC_UCODE_SIZE, 4);
                break;
        case CHIP_VERDE:
                chip_name = "VERDE";
@@ -1579,6 +1587,7 @@ static int si_init_microcode(struct radeon_device *rdev)
                ce_req_size = SI_CE_UCODE_SIZE * 4;
                rlc_req_size = SI_RLC_UCODE_SIZE * 4;
                mc_req_size = SI_MC_UCODE_SIZE * 4;
+               smc_req_size = ALIGN(VERDE_SMC_UCODE_SIZE, 4);
                break;
        case CHIP_OLAND:
                chip_name = "OLAND";
@@ -1588,6 +1597,7 @@ static int si_init_microcode(struct radeon_device *rdev)
                ce_req_size = SI_CE_UCODE_SIZE * 4;
                rlc_req_size = SI_RLC_UCODE_SIZE * 4;
                mc_req_size = OLAND_MC_UCODE_SIZE * 4;
+               smc_req_size = ALIGN(OLAND_SMC_UCODE_SIZE, 4);
                break;
        case CHIP_HAINAN:
                chip_name = "HAINAN";
@@ -1597,6 +1607,7 @@ static int si_init_microcode(struct radeon_device *rdev)
                ce_req_size = SI_CE_UCODE_SIZE * 4;
                rlc_req_size = SI_RLC_UCODE_SIZE * 4;
                mc_req_size = OLAND_MC_UCODE_SIZE * 4;
+               smc_req_size = ALIGN(HAINAN_SMC_UCODE_SIZE, 4);
                break;
        default: BUG();
        }
@@ -1659,6 +1670,17 @@ static int si_init_microcode(struct radeon_device *rdev)
                err = -EINVAL;
        }
 
+       snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
+       err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
+       if (err)
+               goto out;
+       if (rdev->smc_fw->size != smc_req_size) {
+               printk(KERN_ERR
+                      "si_smc: Bogus length %zu in firmware \"%s\"\n",
+                      rdev->smc_fw->size, fw_name);
+               err = -EINVAL;
+       }
+
 out:
        platform_device_unregister(pdev);
 
@@ -1677,6 +1699,8 @@ out:
                rdev->rlc_fw = NULL;
                release_firmware(rdev->mc_fw);
                rdev->mc_fw = NULL;
+               release_firmware(rdev->smc_fw);
+               rdev->smc_fw = NULL;
        }
        return err;
 }
@@ -5420,6 +5444,7 @@ int si_irq_set(struct radeon_device *rdev)
        u32 grbm_int_cntl = 0;
        u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
        u32 dma_cntl, dma_cntl1;
+       u32 thermal_int = 0;
 
        if (!rdev->irq.installed) {
                WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -5445,6 +5470,9 @@ int si_irq_set(struct radeon_device *rdev)
        dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
        dma_cntl1 = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
 
+       thermal_int = RREG32(CG_THERMAL_INT) &
+               ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+
        /* enable CP interrupts on all rings */
        if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
                DRM_DEBUG("si_irq_set: sw int gfx\n");
@@ -5531,6 +5559,11 @@ int si_irq_set(struct radeon_device *rdev)
 
        WREG32(GRBM_INT_CNTL, grbm_int_cntl);
 
+       if (rdev->irq.dpm_thermal) {
+               DRM_DEBUG("dpm thermal\n");
+               thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
+       }
+
        if (rdev->num_crtc >= 2) {
                WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
                WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
@@ -5566,6 +5599,8 @@ int si_irq_set(struct radeon_device *rdev)
                WREG32(DC_HPD6_INT_CONTROL, hpd6);
        }
 
+       WREG32(CG_THERMAL_INT, thermal_int);
+
        return 0;
 }
 
@@ -5730,6 +5765,7 @@ int si_irq_process(struct radeon_device *rdev)
        u32 src_id, src_data, ring_id;
        u32 ring_index;
        bool queue_hotplug = false;
+       bool queue_thermal = false;
 
        if (!rdev->ih.enabled || rdev->shutdown)
                return IRQ_NONE;
@@ -6000,6 +6036,16 @@ restart_ih:
                        DRM_DEBUG("IH: DMA trap\n");
                        radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
                        break;
+               case 230: /* thermal low to high */
+                       DRM_DEBUG("IH: thermal low to high\n");
+                       rdev->pm.dpm.thermal.high_to_low = false;
+                       queue_thermal = true;
+                       break;
+               case 231: /* thermal high to low */
+                       DRM_DEBUG("IH: thermal high to low\n");
+                       rdev->pm.dpm.thermal.high_to_low = true;
+                       queue_thermal = true;
+                       break;
                case 233: /* GUI IDLE */
                        DRM_DEBUG("IH: GUI idle\n");
                        break;
@@ -6018,6 +6064,8 @@ restart_ih:
        }
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
+       if (queue_thermal && rdev->pm.dpm_enabled)
+               schedule_work(&rdev->pm.dpm.thermal.work);
        rdev->ih.rptr = rptr;
        WREG32(IH_RB_RPTR, rdev->ih.rptr);
        atomic_set(&rdev->ih.lock, 0);