drm/radeon/kms/cayman: add asic init/startup/fini/suspend/resume functions
authorAlex Deucher <alexdeucher@gmail.com>
Thu, 3 Mar 2011 01:07:34 +0000 (20:07 -0500)
committerDave Airlie <airlied@redhat.com>
Thu, 3 Mar 2011 01:52:04 +0000 (11:52 +1000)
Cayman is different enough from evergreen to warrant it's own functions.

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/radeon.h

index 0a3d6fc13c2db0eee8de2434de500adfeceaa9ff..d4045223d0ff73a64bf6e677a5976c0754af9cd3 100644 (file)
@@ -1108,7 +1108,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
        WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
 }
 
-static void evergreen_mc_program(struct radeon_device *rdev)
+void evergreen_mc_program(struct radeon_device *rdev)
 {
        struct evergreen_mc_save save;
        u32 tmp;
@@ -2565,7 +2565,7 @@ void evergreen_irq_disable(struct radeon_device *rdev)
        evergreen_disable_interrupt_state(rdev);
 }
 
-static void evergreen_irq_suspend(struct radeon_device *rdev)
+void evergreen_irq_suspend(struct radeon_device *rdev)
 {
        evergreen_irq_disable(rdev);
        r600_rlc_stop(rdev);
@@ -2888,7 +2888,7 @@ static int evergreen_startup(struct radeon_device *rdev)
                                return r;
                        }
                }
-               r = btc_mc_load_microcode(rdev);
+               r = ni_mc_load_microcode(rdev);
                if (r) {
                        DRM_ERROR("Failed to load MC firmware!\n");
                        return r;
@@ -2970,7 +2970,7 @@ int evergreen_resume(struct radeon_device *rdev)
 
        r = evergreen_startup(rdev);
        if (r) {
-               DRM_ERROR("r600 startup failed on resume\n");
+               DRM_ERROR("evergreen startup failed on resume\n");
                return r;
        }
 
@@ -3050,7 +3050,7 @@ int evergreen_init(struct radeon_device *rdev)
        }
        /* Must be an ATOMBIOS */
        if (!rdev->is_atom_bios) {
-               dev_err(rdev->dev, "Expecting atombios for R600 GPU\n");
+               dev_err(rdev->dev, "Expecting atombios for evergreen GPU\n");
                return -EINVAL;
        }
        r = radeon_atombios_init(rdev);
index 3a3fdf5b5dd25d400fd92f0909b3ca3eb8f26d62..227173bf0127d476799999d7eea0fe5a1d3259b1 100644 (file)
@@ -36,6 +36,9 @@
 extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
 extern int evergreen_mc_wait_for_idle(struct radeon_device *rdev);
+extern void evergreen_mc_program(struct radeon_device *rdev);
+extern void evergreen_irq_suspend(struct radeon_device *rdev);
+extern int evergreen_mc_init(struct radeon_device *rdev);
 
 #define EVERGREEN_PFP_UCODE_SIZE 1120
 #define EVERGREEN_PM4_UCODE_SIZE 1376
@@ -193,7 +196,7 @@ static const u32 cayman_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = {
        {0x0000009f, 0x00976b00}
 };
 
-int btc_mc_load_microcode(struct radeon_device *rdev)
+int ni_mc_load_microcode(struct radeon_device *rdev)
 {
        const __be32 *fw_data;
        u32 mem_type, running, blackout = 0;
@@ -1129,6 +1132,12 @@ static int cayman_cp_start(struct radeon_device *rdev)
        return 0;
 }
 
+static void cayman_cp_fini(struct radeon_device *rdev)
+{
+       cayman_cp_enable(rdev, false);
+       radeon_ring_fini(rdev);
+}
+
 int cayman_cp_resume(struct radeon_device *rdev)
 {
        u32 tmp;
@@ -1346,3 +1355,233 @@ int cayman_asic_reset(struct radeon_device *rdev)
        return cayman_gpu_soft_reset(rdev);
 }
 
+static int cayman_startup(struct radeon_device *rdev)
+{
+       int r;
+
+       if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
+               r = ni_init_microcode(rdev);
+               if (r) {
+                       DRM_ERROR("Failed to load firmware!\n");
+                       return r;
+               }
+       }
+       r = ni_mc_load_microcode(rdev);
+       if (r) {
+               DRM_ERROR("Failed to load MC firmware!\n");
+               return r;
+       }
+
+       evergreen_mc_program(rdev);
+       r = cayman_pcie_gart_enable(rdev);
+       if (r)
+               return r;
+       cayman_gpu_init(rdev);
+
+#if 0
+       r = cayman_blit_init(rdev);
+       if (r) {
+               cayman_blit_fini(rdev);
+               rdev->asic->copy = NULL;
+               dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
+       }
+#endif
+
+       /* allocate wb buffer */
+       r = radeon_wb_init(rdev);
+       if (r)
+               return r;
+
+       /* Enable IRQ */
+       r = r600_irq_init(rdev);
+       if (r) {
+               DRM_ERROR("radeon: IH init failed (%d).\n", r);
+               radeon_irq_kms_fini(rdev);
+               return r;
+       }
+       evergreen_irq_set(rdev);
+
+       r = radeon_ring_init(rdev, rdev->cp.ring_size);
+       if (r)
+               return r;
+       r = cayman_cp_load_microcode(rdev);
+       if (r)
+               return r;
+       r = cayman_cp_resume(rdev);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+int cayman_resume(struct radeon_device *rdev)
+{
+       int r;
+
+       /* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
+        * posting will perform necessary task to bring back GPU into good
+        * shape.
+        */
+       /* post card */
+       atom_asic_init(rdev->mode_info.atom_context);
+
+       r = cayman_startup(rdev);
+       if (r) {
+               DRM_ERROR("cayman startup failed on resume\n");
+               return r;
+       }
+
+       r = r600_ib_test(rdev);
+       if (r) {
+               DRM_ERROR("radeon: failled testing IB (%d).\n", r);
+               return r;
+       }
+
+       return r;
+
+}
+
+int cayman_suspend(struct radeon_device *rdev)
+{
+       /* int r; */
+
+       /* FIXME: we should wait for ring to be empty */
+       cayman_cp_enable(rdev, false);
+       rdev->cp.ready = false;
+       evergreen_irq_suspend(rdev);
+       radeon_wb_disable(rdev);
+       cayman_pcie_gart_disable(rdev);
+
+#if 0
+       /* unpin shaders bo */
+       r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+       if (likely(r == 0)) {
+               radeon_bo_unpin(rdev->r600_blit.shader_obj);
+               radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+       }
+#endif
+       return 0;
+}
+
+/* Plan is to move initialization in that function and use
+ * helper function so that radeon_device_init pretty much
+ * do nothing more than calling asic specific function. This
+ * should also allow to remove a bunch of callback function
+ * like vram_info.
+ */
+int cayman_init(struct radeon_device *rdev)
+{
+       int r;
+
+       /* This don't do much */
+       r = radeon_gem_init(rdev);
+       if (r)
+               return r;
+       /* Read BIOS */
+       if (!radeon_get_bios(rdev)) {
+               if (ASIC_IS_AVIVO(rdev))
+                       return -EINVAL;
+       }
+       /* Must be an ATOMBIOS */
+       if (!rdev->is_atom_bios) {
+               dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
+               return -EINVAL;
+       }
+       r = radeon_atombios_init(rdev);
+       if (r)
+               return r;
+
+       /* Post card if necessary */
+       if (!radeon_card_posted(rdev)) {
+               if (!rdev->bios) {
+                       dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
+                       return -EINVAL;
+               }
+               DRM_INFO("GPU not posted. posting now...\n");
+               atom_asic_init(rdev->mode_info.atom_context);
+       }
+       /* Initialize scratch registers */
+       r600_scratch_init(rdev);
+       /* Initialize surface registers */
+       radeon_surface_init(rdev);
+       /* Initialize clocks */
+       radeon_get_clock_info(rdev->ddev);
+       /* Fence driver */
+       r = radeon_fence_driver_init(rdev);
+       if (r)
+               return r;
+       /* initialize memory controller */
+       r = evergreen_mc_init(rdev);
+       if (r)
+               return r;
+       /* Memory manager */
+       r = radeon_bo_init(rdev);
+       if (r)
+               return r;
+
+       r = radeon_irq_kms_init(rdev);
+       if (r)
+               return r;
+
+       rdev->cp.ring_obj = NULL;
+       r600_ring_init(rdev, 1024 * 1024);
+
+       rdev->ih.ring_obj = NULL;
+       r600_ih_ring_init(rdev, 64 * 1024);
+
+       r = r600_pcie_gart_init(rdev);
+       if (r)
+               return r;
+
+       rdev->accel_working = true;
+       r = cayman_startup(rdev);
+       if (r) {
+               dev_err(rdev->dev, "disabling GPU acceleration\n");
+               cayman_cp_fini(rdev);
+               r600_irq_fini(rdev);
+               radeon_wb_fini(rdev);
+               radeon_irq_kms_fini(rdev);
+               cayman_pcie_gart_fini(rdev);
+               rdev->accel_working = false;
+       }
+       if (rdev->accel_working) {
+               r = radeon_ib_pool_init(rdev);
+               if (r) {
+                       DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r);
+                       rdev->accel_working = false;
+               }
+               r = r600_ib_test(rdev);
+               if (r) {
+                       DRM_ERROR("radeon: failed testing IB (%d).\n", r);
+                       rdev->accel_working = false;
+               }
+       }
+
+       /* Don't start up if the MC ucode is missing.
+        * The default clocks and voltages before the MC ucode
+        * is loaded are not suffient for advanced operations.
+        */
+       if (!rdev->mc_fw) {
+               DRM_ERROR("radeon: MC ucode required for NI+.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void cayman_fini(struct radeon_device *rdev)
+{
+       /* cayman_blit_fini(rdev); */
+       cayman_cp_fini(rdev);
+       r600_irq_fini(rdev);
+       radeon_wb_fini(rdev);
+       radeon_irq_kms_fini(rdev);
+       cayman_pcie_gart_fini(rdev);
+       radeon_gem_fini(rdev);
+       radeon_fence_driver_fini(rdev);
+       radeon_bo_fini(rdev);
+       radeon_atombios_fini(rdev);
+       kfree(rdev->bios);
+       rdev->bios = NULL;
+}
+
index 4ff28d68a4986de15dd6a64be3438027329e19a1..6989e3422e8712ba6c82b237a94159ed6c18d355 100644 (file)
@@ -1501,7 +1501,7 @@ extern void r600_hdmi_disable(struct drm_encoder *encoder);
 extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
 
 extern int ni_init_microcode(struct radeon_device *rdev);
-extern int btc_mc_load_microcode(struct radeon_device *rdev);
+extern int ni_mc_load_microcode(struct radeon_device *rdev);
 
 /* radeon_acpi.c */ 
 #if defined(CONFIG_ACPI)